Skip to content

Commit

Permalink
feat(rules): add ion-buttons-attributes-renamed rule
Browse files Browse the repository at this point in the history
  • Loading branch information
imhoffd committed Jul 6, 2018
1 parent 6cac6a2 commit 2a480dd
Show file tree
Hide file tree
Showing 3 changed files with 316 additions and 4 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -489,12 +489,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#toolbar">Toolbar</a>
</th>
<td></td>
<td>:white_large_square:</td>
<td>:wrench:</td>
<td>:white_check_mark:</td>
<td>
<code>ion-toolbar-attributes-renamed</code>
<code>ion-buttons-attributes-renamed</code>
</td>
<td>
<a href="https://github.com/dwieeb">@dwieeb</a>
</td>
<td></td>
</tr>
</table>

Expand Down
36 changes: 36 additions & 0 deletions src/ionButtonsAttributesRenamedRule.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-buttons-attributes-renamed';

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

const TemplateVisitor = createAttributesRenamedTemplateVisitorClass(['ion-buttons'], replacementMap);

export class Rule extends Lint.Rules.AbstractRule {
public static metadata: Lint.IRuleMetadata = {
ruleName: ruleName,
type: 'functionality',
description: 'Attributes of ion-buttons 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
})
);
}
}
274 changes: 274 additions & 0 deletions test/ionButtonsAttributesRenamed.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
import { expect } from 'chai';
import { Replacement, Utils } from 'tslint';
import { ruleName } from '../src/ionButtonsAttributesRenamedRule';
import { assertAnnotated, assertFailure, assertFailures, assertMultipleAnnotated, assertSuccess } from './testHelper';

describe(ruleName, () => {
describe('success', () => {
it('should work with proper style', () => {
let source = `
@Component({
template: \`
<ion-buttons slot="secondary">
<ion-button>Secondary</ion-button>
</ion-buttons>
\`
})
class Bar{}
`;
assertSuccess(ruleName, source);
});
});

describe('failure', () => {
it('should fail when start is used', () => {
let source = `
@Component({
template: \`
<ion-buttons start>
~~~~~
<ion-button>Secondary</ion-button>
</ion-buttons>
\`
})
class Bar{}
`;

assertAnnotated({
ruleName,
message: 'The start attribute of ion-buttons has been renamed. Use slot="secondary" instead.',
source
});
});

it('should fail when end is used', () => {
let source = `
@Component({
template: \`
<ion-buttons end>
~~~
<ion-button>Primary</ion-button>
</ion-buttons>
\`
})
class Bar{}
`;

assertAnnotated({
ruleName,
message: 'The end attribute of ion-buttons has been renamed. Use slot="primary" instead.',
source
});
});

it('should fail when left is used', () => {
let source = `
@Component({
template: \`
<ion-buttons left>
~~~~
<ion-button>Left</ion-button>
</ion-buttons>
\`
})
class Bar{}
`;

assertAnnotated({
ruleName,
message: 'The left attribute of ion-buttons has been renamed. Use slot="start" instead.',
source
});
});

it('should fail when right is used', () => {
let source = `
@Component({
template: \`
<ion-buttons right>
~~~~~
<ion-button>Right</ion-button>
</ion-buttons>
\`
})
class Bar{}
`;

assertAnnotated({
ruleName,
message: 'The right attribute of ion-buttons has been renamed. Use slot="end" instead.',
source
});
});
});

describe('replacements', () => {
it('should replace start with slot="secondary"', () => {
let source = `
@Component({
template: \`
<ion-buttons start>
<ion-button>Secondary</ion-button>
</ion-buttons>
\`
})
class Bar {}
`;

const fail = {
message: 'The start attribute of ion-buttons has been renamed. Use slot="secondary" instead.',
startPosition: {
line: 3,
character: 25
},
endPosition: {
line: 3,
character: 30
}
};

const failures = assertFailure(ruleName, source, fail);
const fixes = failures.map(f => f.getFix());
const res = Replacement.applyAll(source, Utils.flatMap(fixes, Utils.arrayify));

let expected = `
@Component({
template: \`
<ion-buttons slot="secondary">
<ion-button>Secondary</ion-button>
</ion-buttons>
\`
})
class Bar {}
`;

expect(res).to.eq(expected);
});

it('should replace end with slot="primary"', () => {
let source = `
@Component({
template: \`
<ion-buttons end>
<ion-button>Primary</ion-button>
</ion-buttons>
\`
})
class Bar {}
`;

const fail = {
message: 'The end attribute of ion-buttons has been renamed. Use slot="primary" instead.',
startPosition: {
line: 3,
character: 25
},
endPosition: {
line: 3,
character: 28
}
};

const failures = assertFailure(ruleName, source, fail);
const fixes = failures.map(f => f.getFix());
const res = Replacement.applyAll(source, Utils.flatMap(fixes, Utils.arrayify));

let expected = `
@Component({
template: \`
<ion-buttons slot="primary">
<ion-button>Primary</ion-button>
</ion-buttons>
\`
})
class Bar {}
`;

expect(res).to.eq(expected);
});

it('should replace left with slot="start"', () => {
let source = `
@Component({
template: \`
<ion-buttons left>
<ion-button>Left</ion-button>
</ion-buttons>
\`
})
class Bar {}
`;

const fail = {
message: 'The left attribute of ion-buttons has been renamed. Use slot="start" instead.',
startPosition: {
line: 3,
character: 25
},
endPosition: {
line: 3,
character: 29
}
};

const failures = assertFailure(ruleName, source, fail);
const fixes = failures.map(f => f.getFix());
const res = Replacement.applyAll(source, Utils.flatMap(fixes, Utils.arrayify));

let expected = `
@Component({
template: \`
<ion-buttons slot="start">
<ion-button>Left</ion-button>
</ion-buttons>
\`
})
class Bar {}
`;

expect(res).to.eq(expected);
});

it('should replace right with slot="end"', () => {
let source = `
@Component({
template: \`
<ion-buttons right>
<ion-button>Right</ion-button>
</ion-buttons>
\`
})
class Bar {}
`;

const fail = {
message: 'The right attribute of ion-buttons has been renamed. Use slot="end" instead.',
startPosition: {
line: 3,
character: 25
},
endPosition: {
line: 3,
character: 30
}
};

const failures = assertFailure(ruleName, source, fail);
const fixes = failures.map(f => f.getFix());
const res = Replacement.applyAll(source, Utils.flatMap(fixes, Utils.arrayify));

let expected = `
@Component({
template: \`
<ion-buttons slot="end">
<ion-button>Right</ion-button>
</ion-buttons>
\`
})
class Bar {}
`;

expect(res).to.eq(expected);
});
});
});

0 comments on commit 2a480dd

Please sign in to comment.