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 198
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
react-a11y-img-has-alt react-a11y-props react-a11y-role-has-required-aria-props react-a11y-role react-a11y-role-supports-aria-props
- Loading branch information
Showing
76 changed files
with
2,887 additions
and
2,800 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,89 @@ | ||
/** | ||
* @copyright Microsoft Corporation. All rights reserved. | ||
* | ||
* @a11yImgHasAltRule tslint rule for accessibility. | ||
*/ | ||
|
||
import * as ts from 'typescript'; | ||
import * as Lint from 'tslint/lib/lint'; | ||
|
||
import { | ||
getAllAttributesFromJsxElement, | ||
getJsxAttributesFromJsxElement, | ||
getStringLiteral | ||
} from './utils/JsxAttribute'; | ||
import { isJsxSpreadAttribute } from './utils/TypeGuard'; | ||
|
||
const roleString: string = 'role'; | ||
const altString: string = 'alt'; | ||
|
||
export function getFailureStringNoAlt(tagName: string): string { | ||
return `<${tagName}> elements must have an alt attribute or use role='presentation' for presentational images. \ | ||
A reference for the presentation role can be found at https://www.w3.org/TR/wai-aria/roles#presentation.`; | ||
} | ||
|
||
export function getFailureStringEmptyAlt(tagName: string): string { | ||
return `The value of 'alt' attribute in <${tagName}> tag is undefined or empty. \ | ||
Add more details in 'alt' attribute or use role='presentation' for presentational images. \ | ||
A reference for the presentation role can be found at https://www.w3.org/TR/wai-aria/roles#presentation.`; | ||
} | ||
|
||
export class Rule extends Lint.Rules.AbstractRule { | ||
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { | ||
return sourceFile.languageVariant === ts.LanguageVariant.JSX | ||
? this.applyWithWalker(new ImgHasAltWalker(sourceFile, this.getOptions())) | ||
: []; | ||
} | ||
} | ||
|
||
class ImgHasAltWalker extends Lint.RuleWalker { | ||
public visitJsxSelfClosingElement(node: ts.JsxSelfClosingElement): void { | ||
// Tag name is sensitive on lowercase or uppercase, we shoudn't normalize tag names in this rule. | ||
const tagName: string = node.tagName && node.tagName.getText(); | ||
const options: any[] = this.getOptions(); // tslint:disable-line:no-any | ||
|
||
// The additionalTagNames are specified by tslint config to check not only 'img' tag but also customized tag. | ||
// @example checking a customized component 'Image' which should require 'alt' attribute. | ||
const additionalTagNames: string[] = options.length > 1 ? options[1] : []; | ||
|
||
// The targetTagNames is the list of tag names we want to check. | ||
const targetTagNames: string[] = ['img'].concat(additionalTagNames); | ||
|
||
if (!tagName || targetTagNames.indexOf(tagName) === -1) { | ||
return; | ||
} | ||
|
||
// If element contains JsxSpreadElement in which there could possibly be alt attribute, don't check it. | ||
if (getAllAttributesFromJsxElement(node).some(isJsxSpreadAttribute)) { | ||
return; | ||
} | ||
|
||
const attributes: { [propName: string]: ts.JsxAttribute } = getJsxAttributesFromJsxElement(node); | ||
const role: ts.JsxAttribute = attributes[roleString]; | ||
const roleValue: string = role && getStringLiteral(role); | ||
|
||
// if <img> element has role of 'presentation', it's presentational image, don't check it; | ||
// @example <img role='presentation' /> | ||
if (roleValue && roleValue.match(/\bpresentation\b/)) { | ||
return; | ||
} | ||
|
||
const altProp: ts.JsxAttribute = attributes[altString]; | ||
|
||
if (!altProp) { | ||
this.addFailure(this.createFailure( | ||
node.getStart(), | ||
node.getWidth(), | ||
getFailureStringNoAlt(tagName) | ||
)); | ||
} else if (getStringLiteral(altProp) === '') { | ||
this.addFailure(this.createFailure( | ||
altProp.getStart(), | ||
altProp.getWidth(), | ||
getFailureStringEmptyAlt(tagName) | ||
)); | ||
} | ||
|
||
super.visitJsxSelfClosingElement(node); | ||
} | ||
} |
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,46 @@ | ||
/** | ||
* @copyright Microsoft Corporation. All rights reserved. | ||
* | ||
* @a11yPropsRule tslint rule for accessibility. | ||
*/ | ||
|
||
import * as ts from 'typescript'; | ||
import * as Lint from 'tslint/lib/lint'; | ||
|
||
import { getPropName } from './utils/JsxAttribute'; | ||
import { IAria } from './utils/attributes/IAria'; | ||
|
||
// tslint:disable-next-line:no-require-imports no-var-requires | ||
const aria: { [attributeName: string]: IAria } = require('./utils/attributes/ariaSchema.json'); | ||
|
||
export function getFailureString(name: string): string { | ||
return `This attribute name '${name}' is an invalid ARIA attribute. \ | ||
A reference to valid ARIA attributes can be found at \ | ||
https://www.w3.org/TR/2014/REC-wai-aria-20140320/states_and_properties#state_prop_def `; | ||
} | ||
|
||
export class Rule extends Lint.Rules.AbstractRule { | ||
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { | ||
return sourceFile.languageVariant === ts.LanguageVariant.JSX | ||
? this.applyWithWalker(new A11yPropsWalker(sourceFile, this.getOptions())) | ||
: []; | ||
} | ||
} | ||
|
||
class A11yPropsWalker extends Lint.RuleWalker { | ||
public visitJsxAttribute(node: ts.JsxAttribute): void { | ||
const name: string = getPropName(node); | ||
|
||
if (!name || !name.match(/^aria-/i)) { | ||
return; | ||
} | ||
|
||
if (!aria[name.toLowerCase()]) { | ||
this.addFailure(this.createFailure( | ||
node.getStart(), | ||
node.getWidth(), | ||
getFailureString(name) | ||
)); | ||
} | ||
} | ||
} |
Oops, something went wrong.