From bc9770ab040643bd05726e4c06b4a666ef010260 Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Sun, 22 Jul 2018 15:10:24 +0200 Subject: [PATCH] fix(update): support parenthesized directive metadata * Currently if the directive metadata is parenthesized, the upgrade tool will fail due to a runtime exception. We should properly handle that edge-case since the `ComponentWalker` is one of major parts for the upgrade tool and will persist in future releases. * No longer fails if a `@Component` is being created without any metadata or a wrong number of arguments (rel: https://github.com/angular/angular/commit/9a6f27c34ce32af346e20f9cae8ebaacff89cd56) --- .../update/tslint/component-walker.ts | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/lib/schematics/update/tslint/component-walker.ts b/src/lib/schematics/update/tslint/component-walker.ts index d8d6f7292937..b63eb13935c4 100644 --- a/src/lib/schematics/update/tslint/component-walker.ts +++ b/src/lib/schematics/update/tslint/component-walker.ts @@ -11,7 +11,7 @@ */ import {existsSync, readFileSync} from 'fs'; import {dirname, join, resolve} from 'path'; -import {Fix, IOptions, RuleFailure, RuleWalker} from 'tslint'; +import {IOptions, RuleWalker} from 'tslint'; import * as ts from 'typescript'; import {getLiteralTextWithoutQuotes} from '../typescript/literal'; import {createComponentFile, ExternalResource} from './component-file'; @@ -49,7 +49,13 @@ export class ComponentWalker extends RuleWalker { } private _visitDirectiveCallExpression(callExpression: ts.CallExpression) { - const directiveMetadata = callExpression.arguments[0] as ts.ObjectLiteralExpression; + // If the call expressions does not have the correct amount of arguments, we can assume that + // this call expression is not related to Angular and just uses a similar decorator name. + if (callExpression.arguments.length !== 1) { + return; + } + + const directiveMetadata = this._findMetadataFromExpression(callExpression.arguments[0]); if (!directiveMetadata) { return; @@ -130,11 +136,20 @@ export class ComponentWalker extends RuleWalker { this.visitExternalStylesheet(stylesheetFile); } - /** Creates a TSLint rule failure for the given external resource. */ - protected addExternalResourceFailure(file: ExternalResource, message: string, fix?: Fix) { - const ruleFailure = new RuleFailure(file, file.getStart(), file.getEnd(), - message, this.getRuleName(), fix); + /** + * Recursively searches for the metadata object literal expression inside of a directive call + * expression. Since expression calls can be nested through *parenthesized* expressions, we + * need to recursively visit and check every expression inside of a parenthesized expression. + * + * e.g. @Component((({myMetadataExpression}))) will return `myMetadataExpression`. + */ + private _findMetadataFromExpression(node: ts.Expression): ts.ObjectLiteralExpression | null { + if (node.kind === ts.SyntaxKind.ObjectLiteralExpression) { + return node as ts.ObjectLiteralExpression; + } else if (node.kind === ts.SyntaxKind.ParenthesizedExpression) { + return this._findMetadataFromExpression((node as ts.ParenthesizedExpression).expression); + } - this.addFailure(ruleFailure); + return null; } }