Skip to content

Commit

Permalink
feat(rules): add ion-item-option-is-now-an-element rule
Browse files Browse the repository at this point in the history
  • Loading branch information
imhoffd committed Jul 6, 2018
1 parent f90128b commit 04dae1c
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 3 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -330,11 +330,13 @@ We are looking for contributors to help build these rules out! See [`CONTRIBUTIN
<a href="https://github.com/ionic-team/ionic/blob/master/angular/BREAKING.md#item-sliding">Item Sliding</a>
</th>
<td></td>
<td>:white_large_square:</td>
<td>:white_check_mark:</td>
<td>
<code>ion-item-option-is-now-an-element</code>
</td>
<td></td>
<td>
<a href="https://github.com/dwieeb">@dwieeb</a>
</td>
</tr>
<tr>
<th>
Expand Down
2 changes: 1 addition & 1 deletion src/helpers/directiveToElement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export function createDirectiveToElementTemplateVisitorClass(directive: string,
const start = foundAttr.sourceSpan.start.offset;
const absolutePosition = this.getSourcePosition(start - 1);

this.addFailure(this.createFailure(start, directive.length, generateDescription(directive, resultantElement)));
this.addFailureAt(start, directive.length, generateDescription(directive, resultantElement));
}

super.visitElement(element, context);
Expand Down
51 changes: 51 additions & 0 deletions src/ionItemOptionIsNowAnElementRule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import * as ast from '@angular/compiler';
import { NgWalker } from 'codelyzer/angular/ngWalker';
import { BasicTemplateAstVisitor } from 'codelyzer/angular/templates/basicTemplateAstVisitor';
import * as Lint from 'tslint';
import * as ts from 'typescript';

import { createDirectiveToElementTemplateVisitorClass } from './helpers/directiveToElement';
import { isElementAst } from './helpers/utils';

const directive = 'ion-button';
const description = 'Buttons within ion-item-options are now ion-item-option elements instead of Angular directives.';

export const ruleName = 'ion-item-option-is-now-an-element';

class TemplateVisitor extends BasicTemplateAstVisitor {
visitElement(element: ast.ElementAst, context: any): any {
if (element.name === 'ion-item-options') {
for (const child of element.children) {
if (isElementAst(child)) {
if (child.name === 'button' && child.attrs.find(attr => attr.name === directive)) {
const start = child.sourceSpan.start.offset + 1;

this.addFailureAt(start, child.name.length, description);
}
}
}
}

super.visitElement(element, context);
}
}

export class Rule extends Lint.Rules.AbstractRule {
public static metadata: Lint.IRuleMetadata = {
ruleName: ruleName,
type: 'functionality',
description: description,
options: null,
optionsDescription: 'Not configurable.',
typescriptOnly: false,
hasFix: true
};

public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithWalker(
new NgWalker(sourceFile, this.getOptions(), {
templateVisitorCtrl: TemplateVisitor
})
);
}
}
51 changes: 51 additions & 0 deletions test/ionItemOptionIsNowAnElement.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { ruleName } from '../src/ionItemOptionIsNowAnElementRule';
import { assertAnnotated, assertSuccess } from './testHelper';

describe(ruleName, () => {
describe('success', () => {
it('should work with proper style', () => {
let source = `
@Component({
template: \`
<ion-item-sliding>
<ion-item>
<ion-label>Item 1</ion-label>
</ion-item>
<ion-item-options side="end">
<ion-item-option expandable>
<ion-icon name="star"></ion-icon>
</ion-item-option>
</ion-item-options>
</ion-item-sliding>
\`
})
class Bar{}
`;
assertSuccess(ruleName, source);
});
});

describe('failure', () => {
it('should fail when ion-button attribute is used on a button within ion-item-options', () => {
let source = `
@Component({
template: \`
<ion-item-options side="end">
<button ion-button expandable>
~~~~~~
<ion-icon name="star"></ion-icon>
</button>
</ion-item-options>
\`
})
class Bar{}
`;

assertAnnotated({
ruleName,
message: 'Buttons within ion-item-options are now ion-item-option elements instead of Angular directives.',
source
});
});
});
});

0 comments on commit 04dae1c

Please sign in to comment.