Skip to content

Commit

Permalink
feat(rules): add ion-range-attributes-renamed rule (#37)
Browse files Browse the repository at this point in the history
* feat(rules): add ion-range-attributes-renamed rule

* docs(readme): mark rule as complete
  • Loading branch information
imhoffd committed Jul 6, 2018
1 parent 9e8f626 commit 6cac6a2
Show file tree
Hide file tree
Showing 12 changed files with 372 additions and 25 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -429,12 +429,14 @@ We are looking for contributors to help build these rules out! See [`CONTRIBUTIN
<th>
<a href="https://github.com/ionic-team/ionic/blob/master/angular/BREAKING.md#range">Range</a>
</th>
<td></td>
<td>:white_large_square:</td>
<td>:wrench:</td>
<td>:white_check_mark:</td>
<td>
<code>ion-range-attributes-renamed</code>
</td>
<td></td>
<td>
<a href="https://github.com/dwieeb">@dwieeb</a>
</td>
</tr>
<tr>
<th>
Expand Down
32 changes: 18 additions & 14 deletions src/helpers/attributesRenamed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,30 @@ function generateErrorMessage(elementName: string, attrName: string, replacement
return `The ${attrName} attribute of ${elementName} has been renamed. Use ${replacement} instead.`;
}

export function createAttributesRenamedTemplateVisitorClass(elementName: string, replacementMap: Map<string, string>) {
export function createAttributesRenamedTemplateVisitorClass(elementNames: string[] | undefined, replacementMap: Map<string, string>) {
return class extends BasicTemplateAstVisitor {
visitElement(element: ast.ElementAst, context: any): any {
if (element.name === elementName) {
for (const attr of element.attrs) {
const replacement = replacementMap.get(attr.name);
if (!elementNames || elementNames.includes(element.name)) {
this.checkAttributesForReplacements(element);
}

super.visitElement(element, context);
}

if (replacement) {
const start = attr.sourceSpan.start.offset;
const length = attr.name.length;
const position = this.getSourcePosition(start);
private checkAttributesForReplacements(element: ast.ElementAst) {
for (const attr of element.attrs) {
const replacement = replacementMap.get(attr.name);

this.addFailureAt(start, length, generateErrorMessage(elementName, attr.name, replacement), [
Lint.Replacement.replaceFromTo(position, position + length, replacement)
]);
}
if (replacement) {
const start = attr.sourceSpan.start.offset;
const length = attr.name.length;
const position = this.getSourcePosition(start);

this.addFailureAt(start, length, generateErrorMessage(element.name, attr.name, replacement), [
Lint.Replacement.replaceFromTo(position, position + length, replacement)
]);
}
}

super.visitElement(element, context);
}
};
}
2 changes: 1 addition & 1 deletion src/ionButtonAttributesRenamedRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const replacementMap = new Map([
['block', 'expand="block"']
]);

const IonButtonAttributesAreRenamedTemplateVisitor = createAttributesRenamedTemplateVisitorClass('ion-button', replacementMap);
const IonButtonAttributesAreRenamedTemplateVisitor = createAttributesRenamedTemplateVisitorClass(['ion-button'], replacementMap);

export class Rule extends Lint.Rules.AbstractRule {
public static metadata: Lint.IRuleMetadata = {
Expand Down
2 changes: 1 addition & 1 deletion src/ionColAttributesRenamedRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const replacementPairs: [string, string][] = [].concat(

const replacementMap = new Map(replacementPairs);

const IonGridAttributesRenamedTemplateVisitor = createAttributesRenamedTemplateVisitorClass('ion-col', replacementMap);
const IonGridAttributesRenamedTemplateVisitor = createAttributesRenamedTemplateVisitorClass(['ion-col'], replacementMap);

export class Rule extends Lint.Rules.AbstractRule {
public static metadata: Lint.IRuleMetadata = {
Expand Down
2 changes: 1 addition & 1 deletion src/ionFabAttributesRenamedRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const replacementMap = new Map([
['middle', 'vertical="center"']
]);

const IonFabAttributesRenamedTemplateVisitor = createAttributesRenamedTemplateVisitorClass('ion-fab', replacementMap);
const IonFabAttributesRenamedTemplateVisitor = createAttributesRenamedTemplateVisitorClass(['ion-fab'], replacementMap);

export class Rule extends Lint.Rules.AbstractRule {
public static metadata: Lint.IRuleMetadata = {
Expand Down
2 changes: 1 addition & 1 deletion src/ionItemAttributesRenamedRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const replacementMap = new Map([
['item-right', 'slot="end"']
]);

const IonItemAttributesRenamedTemplateVisitor = createAttributesRenamedTemplateVisitorClass('ion-item', replacementMap);
const IonItemAttributesRenamedTemplateVisitor = createAttributesRenamedTemplateVisitorClass(['ion-item'], replacementMap);

export class Rule extends Lint.Rules.AbstractRule {
public static metadata: Lint.IRuleMetadata = {
Expand Down
2 changes: 1 addition & 1 deletion src/ionLabelAttributesRenamedRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const ruleName = 'ion-label-attributes-renamed';

const replacementMap = new Map([['fixed', 'position="fixed"'], ['floating', 'position="floating"'], ['stacked', 'position="stacked"']]);

const IonButtonAttributesAreRenamedTemplateVisitor = createAttributesRenamedTemplateVisitorClass('ion-label', replacementMap);
const IonButtonAttributesAreRenamedTemplateVisitor = createAttributesRenamedTemplateVisitorClass(['ion-label'], replacementMap);

export class Rule extends Lint.Rules.AbstractRule {
public static metadata: Lint.IRuleMetadata = {
Expand Down
2 changes: 1 addition & 1 deletion src/ionRadioAttributesRenamedRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const ruleName = 'ion-radio-attributes-renamed';

const replacementMap = new Map([['item-left', 'slot="start"'], ['item-right', 'slot="end"']]);

const IonFabAttributesRenamedTemplateVisitor = createAttributesRenamedTemplateVisitorClass('ion-radio', replacementMap);
const IonFabAttributesRenamedTemplateVisitor = createAttributesRenamedTemplateVisitorClass(['ion-radio'], replacementMap);

export class Rule extends Lint.Rules.AbstractRule {
public static metadata: Lint.IRuleMetadata = {
Expand Down
36 changes: 36 additions & 0 deletions src/ionRangeAttributesRenamedRule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { NgWalker } from 'codelyzer/angular/ngWalker';
import * as Lint from 'tslint';
import * as ts from 'typescript';

import { createAttributesRenamedTemplateVisitorClass } from './helpers/attributesRenamed';

export const ruleName = 'ion-range-attributes-renamed';

const replacementMap = new Map([
['range-left', 'slot="start"'],
['range-start', 'slot="start"'],
['range-right', 'slot="end"'],
['range-end', 'slot="end"']
]);

const TemplateVisitor = createAttributesRenamedTemplateVisitorClass(undefined, replacementMap);

export class Rule extends Lint.Rules.AbstractRule {
public static metadata: Lint.IRuleMetadata = {
ruleName: ruleName,
type: 'functionality',
description: 'Attributes of children of ion-range have been renamed.',
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
})
);
}
}
2 changes: 1 addition & 1 deletion src/ionTabAttributesRenamedRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const ruleName = 'ion-tab-attributes-renamed';

const replacementMap = new Map([['tabTitle', 'label'], ['tabIcon', 'icon'], ['tabBadge', 'badge'], ['tabBadgeStyle', 'badgeStyle']]);

const IonButtonAttributesAreRenamedTemplateVisitor = createAttributesRenamedTemplateVisitorClass('ion-tab', replacementMap);
const IonButtonAttributesAreRenamedTemplateVisitor = createAttributesRenamedTemplateVisitorClass(['ion-tab'], replacementMap);

export class Rule extends Lint.Rules.AbstractRule {
public static metadata: Lint.IRuleMetadata = {
Expand Down
2 changes: 1 addition & 1 deletion test/ionItemAttributesRenamed.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ describe(ruleName, () => {
it('should work with proper style', () => {
let source = `
@Component({
template: \`<ion-item slot="start"><ion-item>\`
template: \`<ion-item slot="start"></ion-item>\`
})
class Bar{}
`;
Expand Down
Loading

0 comments on commit 6cac6a2

Please sign in to comment.