From 52d1500155bf7c67cccb73739ee2c478d983f13f Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Fri, 8 Nov 2019 11:37:08 +0000 Subject: [PATCH] refactor(ngcc): allow look up of multiple helpers (#33689) This change is a precursor to finding the end of a class, which needs to search for helpers of many different names. PR Close #33689 --- .../ngcc/src/host/commonjs_host.ts | 25 ++++++++------ .../ngcc/src/host/esm2015_host.ts | 33 ++++++++++--------- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/packages/compiler-cli/ngcc/src/host/commonjs_host.ts b/packages/compiler-cli/ngcc/src/host/commonjs_host.ts index 189e9157a5..a96e74801d 100644 --- a/packages/compiler-cli/ngcc/src/host/commonjs_host.ts +++ b/packages/compiler-cli/ngcc/src/host/commonjs_host.ts @@ -63,14 +63,14 @@ export class CommonJsReflectionHost extends Esm5ReflectionHost { * @param helperName the name of the helper (e.g. `__decorate`) whose calls we are interested in. * @returns an array of nodes of calls to the helper with the given name. */ - protected getHelperCallsForClass(classSymbol: NgccClassSymbol, helperName: string): + protected getHelperCallsForClass(classSymbol: NgccClassSymbol, helperNames: string[]): ts.CallExpression[] { - const esm5HelperCalls = super.getHelperCallsForClass(classSymbol, helperName); + const esm5HelperCalls = super.getHelperCallsForClass(classSymbol, helperNames); if (esm5HelperCalls.length > 0) { return esm5HelperCalls; } else { const sourceFile = classSymbol.declaration.valueDeclaration.getSourceFile(); - return this.getTopLevelHelperCalls(sourceFile, helperName); + return this.getTopLevelHelperCalls(sourceFile, helperNames); } } @@ -81,16 +81,21 @@ export class CommonJsReflectionHost extends Esm5ReflectionHost { * each class in a file. * * @param sourceFile the source who may contain helper calls. - * @param helperName the name of the helper (e.g. `__decorate`) whose calls we are interested in. + * @param helperNames the names of the helpers (e.g. `__decorate`) whose calls we are interested + * in. * @returns an array of nodes of calls to the helper with the given name. */ - private getTopLevelHelperCalls(sourceFile: ts.SourceFile, helperName: string): + private getTopLevelHelperCalls(sourceFile: ts.SourceFile, helperNames: string[]): ts.CallExpression[] { - const helperCallsMap = getOrDefault(this.topLevelHelperCalls, helperName, () => new Map()); - return getOrDefault( - helperCallsMap, sourceFile, - () => sourceFile.statements.map(statement => this.getHelperCall(statement, helperName)) - .filter(isDefined)); + const calls: ts.CallExpression[] = []; + helperNames.forEach(helperName => { + const helperCallsMap = getOrDefault(this.topLevelHelperCalls, helperName, () => new Map()); + calls.push(...getOrDefault( + helperCallsMap, sourceFile, + () => sourceFile.statements.map(statement => this.getHelperCall(statement, helperNames)) + .filter(isDefined))); + }); + return calls; } private computeExportsOfCommonJsModule(sourceFile: ts.SourceFile): Map { diff --git a/packages/compiler-cli/ngcc/src/host/esm2015_host.ts b/packages/compiler-cli/ngcc/src/host/esm2015_host.ts index 58bbdff8e5..2ef112c3cb 100644 --- a/packages/compiler-cli/ngcc/src/host/esm2015_host.ts +++ b/packages/compiler-cli/ngcc/src/host/esm2015_host.ts @@ -900,7 +900,7 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N // Note that although the helper calls are retrieved using the class symbol, the result may // contain helper calls corresponding with unrelated classes. Therefore, each helper call still // has to be checked to actually correspond with the class symbol. - const helperCalls = this.getHelperCallsForClass(classSymbol, '__decorate'); + const helperCalls = this.getHelperCallsForClass(classSymbol, ['__decorate']); for (const helperCall of helperCalls) { if (isClassDecorateCall(helperCall, classSymbol.name)) { @@ -1065,23 +1065,26 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N } /** - * Check the given statement to see if it is a call to the specified helper function or null if - * not found. + * Check the given statement to see if it is a call to any of the specified helper functions or + * null if not found. * * Matching statements will look like: `tslib_1.__decorate(...);`. * @param statement the statement that may contain the call. - * @param helperName the name of the helper we are looking for. + * @param helperNames the names of the helper we are looking for. * @returns the node that corresponds to the `__decorate(...)` call or null if the statement * does not match. */ - protected getHelperCall(statement: ts.Statement, helperName: string): ts.CallExpression|null { + protected getHelperCall(statement: ts.Statement, helperNames: string[]): ts.CallExpression|null { if (ts.isExpressionStatement(statement)) { let expression = statement.expression; while (isAssignment(expression)) { expression = expression.right; } - if (ts.isCallExpression(expression) && getCalleeName(expression) === helperName) { - return expression; + if (ts.isCallExpression(expression)) { + const calleeName = getCalleeName(expression); + if (calleeName !== null && helperNames.includes(calleeName)) { + return expression; + } } } return null; @@ -1326,8 +1329,8 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N * Get the parameter type and decorators for the constructor of a class, * where the information is stored on a static property of the class. * - * Note that in ESM2015, the property is defined an array, or by an arrow function that returns an - * array, of decorator and type information. + * Note that in ESM2015, the property is defined an array, or by an arrow function that returns + * an array, of decorator and type information. * * For example, * @@ -1387,14 +1390,14 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N /** * Search statements related to the given class for calls to the specified helper. * @param classSymbol the class whose helper calls we are interested in. - * @param helperName the name of the helper (e.g. `__decorate`) whose calls we are interested + * @param helperNames the names of the helpers (e.g. `__decorate`) whose calls we are interested * in. * @returns an array of CallExpression nodes for each matching helper call. */ - protected getHelperCallsForClass(classSymbol: NgccClassSymbol, helperName: string): + protected getHelperCallsForClass(classSymbol: NgccClassSymbol, helperNames: string[]): ts.CallExpression[] { return this.getStatementsForClass(classSymbol) - .map(statement => this.getHelperCall(statement, helperName)) + .map(statement => this.getHelperCall(statement, helperNames)) .filter(isDefined); } @@ -1620,9 +1623,9 @@ interface DecoratorInfo { /** * Represents the constructor parameter information, such as the type of a parameter and all - * decorators for a certain parameter. Indices in this array correspond with the parameter's index - * in the constructor. Note that this array may be sparse, i.e. certain constructor parameters may - * not have any info recorded. + * decorators for a certain parameter. Indices in this array correspond with the parameter's + * index in the constructor. Note that this array may be sparse, i.e. certain constructor + * parameters may not have any info recorded. */ constructorParamInfo: ParamInfo[]; }