This repository has been archived by the owner on Jul 15, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 199
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Issue #247] new rule: react-a11y-aria-unsupported-elements
- Loading branch information
Showing
8 changed files
with
296 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
/** | ||
* Enforce that elements that do not support ARIA roles, states, and properties do not have those attributes. | ||
*/ | ||
import * as ts from 'typescript'; | ||
import * as Lint from 'tslint/lib/lint'; | ||
|
||
import { ExtendedMetadata } from './utils/ExtendedMetadata'; | ||
import { getJsxAttributesFromJsxElement} from './utils/JsxAttribute'; | ||
import { IDom } from './utils/attributes/IDom'; | ||
import { IAria } from './utils/attributes/IAria'; | ||
|
||
// tslint:disable:no-require-imports no-var-requires | ||
const DOM_SCHEMA: IDom[] = require('./utils/attributes/domSchema.json'); | ||
const ARIA_SCHEMA: IAria[] = require('./utils/attributes/ariaSchema.json'); | ||
// tslint:enable:no-require-imports no-var-requires | ||
|
||
export function getFailureString(tagName: string, ariaAttributeNames: string[]): string { | ||
return `This element ${tagName} does not support ARIA roles, states and properties. ` | ||
+ `Try removing attribute(s): ${ariaAttributeNames.join(', ')}.`; | ||
} | ||
|
||
export class Rule extends Lint.Rules.AbstractRule { | ||
public static metadata: ExtendedMetadata = { | ||
ruleName: 'react-a11y-aria-unsupported-elements', | ||
type: 'maintainability', | ||
description: 'Enforce that elements that do not support ARIA roles, states, and properties do not have those attributes.', | ||
options: null, | ||
issueClass: 'Non-SDL', | ||
issueType: 'Warning', | ||
severity: 'Important', | ||
level: 'Opportunity for Excellence', | ||
group: 'Accessibility' | ||
}; | ||
|
||
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { | ||
return sourceFile.languageVariant === ts.LanguageVariant.JSX | ||
? this.applyWithWalker(new ReactA11yAriaUnsupportedElementsWalker(sourceFile, this.getOptions())) | ||
: []; | ||
} | ||
} | ||
|
||
class ReactA11yAriaUnsupportedElementsWalker extends Lint.RuleWalker { | ||
public visitJsxElement(node: ts.JsxElement): void { | ||
this.validateOpeningElement(node.openingElement); | ||
super.visitJsxElement(node); | ||
} | ||
|
||
public visitJsxSelfClosingElement(node: ts.JsxSelfClosingElement): void { | ||
this.validateOpeningElement(node); | ||
super.visitJsxSelfClosingElement(node); | ||
} | ||
|
||
private validateOpeningElement(node: ts.JsxOpeningElement): void { | ||
const tagName: string = node.tagName.getText(); | ||
|
||
if (!DOM_SCHEMA[tagName]) { | ||
return; | ||
} | ||
|
||
const unsupportedAria: boolean = DOM_SCHEMA[tagName].unsupportedAria != null | ||
? DOM_SCHEMA[tagName].unsupportedAria | ||
: false; | ||
|
||
if (!unsupportedAria) { | ||
return; | ||
} | ||
|
||
const checkAttributeNames: string[] = Object.keys(ARIA_SCHEMA).concat('role'); | ||
const attributes: { [propName: string]: ts.JsxAttribute } = getJsxAttributesFromJsxElement(node); | ||
const invalidAttributeNames: string[] = | ||
checkAttributeNames.filter((attributeName: string): boolean => !!attributes[attributeName]); | ||
|
||
if (invalidAttributeNames.length > 0) { | ||
const message: string = getFailureString(tagName, invalidAttributeNames); | ||
this.addFailure(this.createFailure(node.getStart(), node.getWidth(), message)); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
/** | ||
* Interface of dom | ||
*/ | ||
export interface IDom { | ||
unsupportedAria: boolean; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
{ | ||
"a": {}, | ||
"abbr": {}, | ||
"address": {}, | ||
"area": {}, | ||
"article": {}, | ||
"aside": {}, | ||
"audio": {}, | ||
"b": {}, | ||
"base": { | ||
"unsupportedAria": true | ||
}, | ||
"bdi": {}, | ||
"bdo": {}, | ||
"big": {}, | ||
"blockquote": {}, | ||
"body": {}, | ||
"br": {}, | ||
"button": {}, | ||
"canvas": {}, | ||
"caption": {}, | ||
"cite": {}, | ||
"code": {}, | ||
"col": { | ||
"unsupportedAria": true | ||
}, | ||
"colgroup": { | ||
"unsupportedAria": true | ||
}, | ||
"data": {}, | ||
"datalist": {}, | ||
"dd": {}, | ||
"del": {}, | ||
"details": {}, | ||
"dfn": {}, | ||
"dialog": {}, | ||
"div": {}, | ||
"dl": {}, | ||
"dt": {}, | ||
"em": {}, | ||
"embed": {}, | ||
"fieldset": {}, | ||
"figcaption": {}, | ||
"figure": {}, | ||
"footer": {}, | ||
"form": {}, | ||
"h1": {}, | ||
"h2": {}, | ||
"h3": {}, | ||
"h4": {}, | ||
"h5": {}, | ||
"h6": {}, | ||
"head": { | ||
"unsupportedAria": true | ||
}, | ||
"header": {}, | ||
"hgroup": {}, | ||
"hr": {}, | ||
"html": { | ||
"unsupportedAria": true | ||
}, | ||
"i": {}, | ||
"iframe": {}, | ||
"img": {}, | ||
"input": {}, | ||
"ins": {}, | ||
"kbd": {}, | ||
"keygen": {}, | ||
"label": {}, | ||
"legend": {}, | ||
"li": {}, | ||
"link": { | ||
"unsupportedAria": true | ||
}, | ||
"main": {}, | ||
"map": {}, | ||
"mark": {}, | ||
"menu": {}, | ||
"menuitem": {}, | ||
"meta": { | ||
"unsupportedAria": true | ||
}, | ||
"meter": {}, | ||
"nav": {}, | ||
"noscript": { | ||
"unsupportedAria": true | ||
}, | ||
"object": {}, | ||
"ol": {}, | ||
"optgroup": {}, | ||
"option": {}, | ||
"output": {}, | ||
"p": {}, | ||
"param": { | ||
"unsupportedAria": true | ||
}, | ||
"picture": { | ||
"unsupportedAria": true | ||
}, | ||
"pre": {}, | ||
"progress": {}, | ||
"q": {}, | ||
"rp": {}, | ||
"rt": {}, | ||
"ruby": {}, | ||
"s": {}, | ||
"samp": {}, | ||
"script": { | ||
"unsupportedAria": true | ||
}, | ||
"section": {}, | ||
"select": {}, | ||
"small": {}, | ||
"source": { | ||
"unsupportedAria": true | ||
}, | ||
"span": {}, | ||
"strong": {}, | ||
"style": { | ||
"unsupportedAria": true | ||
}, | ||
"sub": {}, | ||
"summary": {}, | ||
"sup": {}, | ||
"table": {}, | ||
"tbody": {}, | ||
"td": {}, | ||
"textarea": {}, | ||
"tfoot": {}, | ||
"th": {}, | ||
"thead": {}, | ||
"time": {}, | ||
"title": { | ||
"unsupportedAria": true | ||
}, | ||
"tr": {}, | ||
"track": { | ||
"unsupportedAria": true | ||
}, | ||
"u": {}, | ||
"ul": {}, | ||
"var": {}, | ||
"video": {}, | ||
"wbr": {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { TestHelper } from './TestHelper'; | ||
import { getFailureString } from '../src/reactA11yAriaUnsupportedElementsRule'; | ||
|
||
/** | ||
* Unit test for react-a11y-aria-unsupported-elements rule. | ||
*/ | ||
describe('reactA11yAriaUnsupportedElementsRule', () => { | ||
const ruleName: string = 'react-a11y-aria-unsupported-elements'; | ||
|
||
it('should pass when tag name is not dom elements', (): void => { | ||
const script: string = ` | ||
import React = require('react); | ||
const a = <DIV aria-label/>; | ||
const b = <DIV role></DIV>; | ||
`; | ||
TestHelper.assertNoViolation(ruleName, script); | ||
}); | ||
|
||
it('should pass when tag name is supported aria element', (): void => { | ||
const script: string = ` | ||
import React = require('react); | ||
const a = <div />; | ||
const b = <div aria-label role { ...this.props }></div>; | ||
`; | ||
TestHelper.assertNoViolation(ruleName, script); | ||
}); | ||
|
||
it('should fail when unsupported aria elements have aria-* or role attributes', (): void => { | ||
const script: string = ` | ||
import React = require('react'); | ||
const a = <base aria-label role { ...this.props }></base>; | ||
const b = <base aria-label role { ...this.props } />; | ||
`; | ||
TestHelper.assertViolations( | ||
ruleName, | ||
script, | ||
[ | ||
{ | ||
name: 'file.tsx', | ||
ruleName: ruleName, | ||
startPosition: { character: 23, line: 4 }, | ||
failure: getFailureString('base', ['aria-label', 'role']) | ||
}, | ||
{ | ||
name: 'file.tsx', | ||
ruleName: ruleName, | ||
startPosition: { character: 23, line: 5 }, | ||
failure: getFailureString('base', ['aria-label', 'role']) | ||
} | ||
] | ||
); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters