Skip to content

Commit

Permalink
feat(rules): allow rule to work with ion-loading, ion-infinite-scroll…
Browse files Browse the repository at this point in the history
…, and ion-refresher
  • Loading branch information
imhoffd committed Jul 6, 2018
1 parent c6affd3 commit 9e8f626
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 17 deletions.
30 changes: 16 additions & 14 deletions src/helpers/attributeValuesRenamed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,27 @@ function generateErrorMessage(elementName: string, attrName: string, attrValue:
return `The ${attrName}="${attrValue}" attribute/value of ${elementName} should be written as ${replacement}.`;
}

export function createAttributeValuesRenamedTemplateVisitorClass(elementName: string, replacementMap: Map<string, Map<string, string>>) {
export function createAttributeValuesRenamedTemplateVisitorClass(elementNames: string[], replacementMap: Map<string, 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 attrValueMap = replacementMap.get(attr.name);
for (const elementName of elementNames) {
if (element.name === elementName) {
for (const attr of element.attrs) {
const attrValueMap = replacementMap.get(attr.name);

if (attrValueMap) {
const replacementValue = attrValueMap.get(attr.value);
if (attrValueMap) {
const replacementValue = attrValueMap.get(attr.value);

if (replacementValue) {
const start = attr.sourceSpan.start.offset;
const end = attr.sourceSpan.end.offset;
const position = this.getSourcePosition(start);
const replacement = `${attr.name}="${replacementValue}"`;
if (replacementValue) {
const start = attr.sourceSpan.start.offset;
const end = attr.sourceSpan.end.offset;
const position = this.getSourcePosition(start);
const replacement = `${attr.name}="${replacementValue}"`;

this.addFailureAt(start, end - start, generateErrorMessage(elementName, attr.name, attr.value, replacement), [
Lint.Replacement.replaceFromTo(position, position + end - start, replacement)
]);
this.addFailureAt(start, end - start, generateErrorMessage(elementName, attr.name, attr.value, replacement), [
Lint.Replacement.replaceFromTo(position, position + end - start, replacement)
]);
}
}
}
}
Expand Down
7 changes: 4 additions & 3 deletions src/ionSpinnerAttributeValuesRenamedRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ import { createAttributeValuesRenamedTemplateVisitorClass } from './helpers/attr
export const ruleName = 'ion-spinner-attribute-values-renamed';

const replacementMap = new Map([['name', new Map([['ios', 'lines'], ['ios-small', 'lines-small']])]]);
const affectedElements = ['ion-spinner', 'ion-loading', 'ion-infinite-scroll', 'ion-refresher'];

const IonSpinnerAttributeValuesRenamedTemplateVisitor = createAttributeValuesRenamedTemplateVisitorClass('ion-spinner', replacementMap);
const TemplateVisitor = createAttributeValuesRenamedTemplateVisitorClass(affectedElements, replacementMap);

export class Rule extends Lint.Rules.AbstractRule {
public static metadata: Lint.IRuleMetadata = {
ruleName: ruleName,
type: 'functionality',
description: 'Attribute values of ion-spinner have been renamed.',
description: `Attribute values of ${affectedElements.join(', ')} have been renamed.`,
options: null,
optionsDescription: 'Not configurable.',
typescriptOnly: false,
Expand All @@ -24,7 +25,7 @@ export class Rule extends Lint.Rules.AbstractRule {
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithWalker(
new NgWalker(sourceFile, this.getOptions(), {
templateVisitorCtrl: IonSpinnerAttributeValuesRenamedTemplateVisitor
templateVisitorCtrl: TemplateVisitor
})
);
}
Expand Down
63 changes: 63 additions & 0 deletions test/ionSpinnerAttributeValuesRenamed.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ describe(ruleName, () => {
`;
assertSuccess(ruleName, source);
});

it('should work with proper style for ion-loading', () => {
let source = `
@Component({
template: \`<ion-loading name="lines"></ion-loading>\`
})
class Bar{}
`;
assertSuccess(ruleName, source);
});
});

describe('failure', () => {
Expand Down Expand Up @@ -60,6 +70,23 @@ describe(ruleName, () => {
source
});
});

it('should fail when name="ios" is used on ion-loading', () => {
let source = `
@Component({
template: \`
<ion-loading name="ios"></ion-loading>\`
~~~~~~~~~~
})
class Bar{}
`;

assertAnnotated({
ruleName,
message: 'The name="ios" attribute/value of ion-loading should be written as name="lines".',
source
});
});
});

describe('replacements', () => {
Expand Down Expand Up @@ -134,5 +161,41 @@ describe(ruleName, () => {

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

it('should replace name="ios" with name="lines" for ion-loading', () => {
let source = `
@Component({
template: \`
<ion-loading name="ios"></ion-loading>\`
})
class Bar {}
`;

const fail = {
message: 'The name="ios" attribute/value of ion-loading should be written as name="lines".',
startPosition: {
line: 3,
character: 25
},
endPosition: {
line: 3,
character: 35
}
};

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-loading name="lines"></ion-loading>\`
})
class Bar {}
`;

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

0 comments on commit 9e8f626

Please sign in to comment.