Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(update): support parenthesized directive metadata #12314

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 22 additions & 7 deletions src/lib/schematics/update/tslint/component-walker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
}