Skip to content

Commit 6b21a9e

Browse files
mohammedzamakhanmgechev
authored andcommitted
feat(rule): no distracting elements should be used (#760)
1 parent fdcb07a commit 6b21a9e

File tree

3 files changed

+110
-0
lines changed

3 files changed

+110
-0
lines changed

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export { Rule as TemplatesAccessibilityAnchorContentRule } from './templateAcces
3636
export { Rule as TemplateClickEventsHaveKeyEventsRule } from './templateClickEventsHaveKeyEventsRule';
3737
export { Rule as TemplateAccessibilityAltTextRule } from './templateAccessibilityAltTextRule';
3838
export { Rule as TemplateAccessibilityTableScopeRule } from './templateAccessibilityTableScopeRule';
39+
export { Rule as TemplateNoDistractingElementsRule } from './templateNoDistractingElementsRule';
3940
export { Rule as TemplatesNoNegatedAsync } from './templatesNoNegatedAsyncRule';
4041
export { Rule as TemplateNoAutofocusRule } from './templateNoAutofocusRule';
4142
export { Rule as TrackByFunctionRule } from './trackByFunctionRule';
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { ElementAst } from '@angular/compiler';
2+
import { sprintf } from 'sprintf-js';
3+
import { IRuleMetadata, RuleFailure, Rules } from 'tslint/lib';
4+
import { SourceFile } from 'typescript/lib/typescript';
5+
import { NgWalker } from './angular/ngWalker';
6+
import { BasicTemplateAstVisitor } from './angular/templates/basicTemplateAstVisitor';
7+
8+
export class Rule extends Rules.AbstractRule {
9+
static readonly metadata: IRuleMetadata = {
10+
description: 'Enforces that no distracting elements are used',
11+
options: null,
12+
optionsDescription: 'Not configurable.',
13+
rationale: 'Elements that can be visually distracting can cause accessibility issues with visually impaired users.',
14+
ruleName: 'template-no-distracting-elements',
15+
type: 'functionality',
16+
typescriptOnly: true
17+
};
18+
19+
static readonly FAILURE_STRING = 'Avoid using <%s/> elements as they create visual accessibility issues.';
20+
21+
apply(sourceFile: SourceFile): RuleFailure[] {
22+
return this.applyWithWalker(
23+
new NgWalker(sourceFile, this.getOptions(), {
24+
templateVisitorCtrl: TemplateNoDistractingElementsVisitor
25+
})
26+
);
27+
}
28+
}
29+
30+
export function getFailureMessage(element: string) {
31+
return sprintf(Rule.FAILURE_STRING, element);
32+
}
33+
34+
class TemplateNoDistractingElementsVisitor extends BasicTemplateAstVisitor {
35+
visitElement(prop: ElementAst, context: any): any {
36+
this.validateElement(prop);
37+
super.visitElement(prop, context);
38+
}
39+
40+
private validateElement(el: ElementAst): void {
41+
if (el.name === 'marquee' || el.name === 'blink') {
42+
const {
43+
sourceSpan: {
44+
end: { offset: endOffset },
45+
start: { offset: startOffset }
46+
}
47+
} = el;
48+
this.addFailureFromStartToEnd(startOffset, endOffset, getFailureMessage(el.name));
49+
}
50+
}
51+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { getFailureMessage, Rule } from '../src/templateNoDistractingElementsRule';
2+
import { assertAnnotated, assertSuccess } from './testHelper';
3+
4+
const {
5+
metadata: { ruleName }
6+
} = Rule;
7+
8+
describe(ruleName, () => {
9+
describe('failure', () => {
10+
it('should fail when distracting element marquee is used', () => {
11+
const source = `
12+
@Component({
13+
template: \`
14+
<marquee></marquee>
15+
~~~~~~~~~
16+
\`
17+
})
18+
class Bar {}
19+
`;
20+
assertAnnotated({
21+
message: getFailureMessage('marquee'),
22+
ruleName,
23+
source
24+
});
25+
});
26+
27+
it('should fail when distracting element blink is used', () => {
28+
const source = `
29+
@Component({
30+
template: \`
31+
<blink></blink>
32+
~~~~~~~
33+
\`
34+
})
35+
class Bar {}
36+
`;
37+
assertAnnotated({
38+
message: getFailureMessage('blink'),
39+
ruleName,
40+
source
41+
});
42+
});
43+
});
44+
45+
describe('success', () => {
46+
it('should work when distracting element is not used', () => {
47+
const source = `
48+
@Component({
49+
template: \`
50+
<div>Valid</div>
51+
\`
52+
})
53+
class Bar {}
54+
`;
55+
assertSuccess(ruleName, source);
56+
});
57+
});
58+
});

0 commit comments

Comments
 (0)