Skip to content
This repository has been archived by the owner on Jul 15, 2023. It is now read-only.

Commit

Permalink
[Issue #194] react-a11y-lang - valid lang value
Browse files Browse the repository at this point in the history
Values that is passed to lang attribute must be a valid ISO language
code.

closes #194
closes #209
  • Loading branch information
danielmanesku authored and HamletDRC committed Sep 2, 2016
1 parent 0c64b83 commit bd5e195
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 10 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ Rule Name | Description | Since
`prefer-type-cast` | Prefer the tradition type casts instead of the new 'as-cast' syntax. For example, prefer '<string>myVariable' instead of 'myVariable as string'. Rule ignores any file ending in .tsx. If you prefer the opposite and want to see the 'as type' casts, then enable the tslint rule named 'no-angle-bracket-type-assertion'| 2.0.4
`promise-must-complete` | When a Promise instance is created, then either the reject() or resolve() parameter must be called on it within all code branches in the scope. For more examples see the [feature request](https://github.com/Microsoft/tslint-microsoft-contrib/issues/34). | 1.0
`react-iframe-missing-sandbox` | React iframes must specify a sandbox attribute. If specified as an empty string, this attribute enables extra restrictions on the content that can appear in the inline frame. The value of the attribute can either be an empty string (all the restrictions are applied), or a space-separated list of tokens that lift particular restrictions. You many not use both allow-scripts and allow-same-origin at the same time, as that allows the embedded document to programmatically remove the sandbox attribute in some scenarios. | 2.0.10
`react-a11y-lang` | For accessibility of your website, html elements must have a lang attribute.<br/>References:<br/>* [H58: Using language attributes to identify changes in the human language](https://www.w3.org/TR/WCAG20-TECHS/H58.html)<br/>* [lang attribute must have a valid value](https://dequeuniversity.com/rules/axe/1.1/valid-lang) | 2.0.11
`react-a11y-lang` | For accessibility of your website, html elements must have a lang attribute and the attribute must be a valid language code.<br/>References:<br/>* [H58: Using language attributes to identify changes in the human language](https://www.w3.org/TR/WCAG20-TECHS/H58.html)<br/>* [lang attribute must have a valid value](https://dequeuniversity.com/rules/axe/1.1/valid-lang)<br/>[List of ISO 639-1 codes](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) | 2.0.11
`react-a11y-meta` | For accessibility of your website, HTML meta elements must not have http-equiv="refresh". | 2.0.11
`react-a11y-titles` | For accessibility of your website, HTML title elements must not be empty, must be more than one word, and must not be more than 60 characters long.<br/>References:<br/>* [WCAG 2.0 - Requirement 2.4.2 Page Titled (Level A)](http://www.w3.org/TR/WCAG20/#navigation-mechanisms-title)<br/>* [OAA-Accessibility Rule 13: Title element should not be empty](http://oaa-accessibility.org/wcag20/rule/13/)<br/>* [OAA-Accessibility Rule 24: Title content should be concise](http://oaa-accessibility.org/wcag20/rule/24/)<br/>* [OAA-Accessibility Rule 25: Title text must contain more than one word](http://oaa-accessibility.org/wcag20/rule/25/)<br/> | 2.0.11
`react-no-dangerous-html` | Do not use React's dangerouslySetInnerHTML API. This rule finds usages of the dangerouslySetInnerHTML API (but not any JSX references). For more info see the [react-no-dangerous-html Rule wiki page](https://github.com/Microsoft/tslint-microsoft-contrib/wiki/react-no-dangerous-html-Rule). | 0.0.2
Expand Down
40 changes: 33 additions & 7 deletions src/reactA11yLangRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,22 @@ import {ErrorTolerantWalker} from './utils/ErrorTolerantWalker';
import {ExtendedMetadata} from './utils/ExtendedMetadata';
import {SyntaxKind} from './utils/SyntaxKind';

const FAILURE_STRING: string = 'An html element is missing the lang attribute';
const FAILURE_MISSING_LANG: string = 'An html element is missing the lang attribute';
const FAILURE_WRONG_LANG_CODE: string = 'Lang attribute does not have a valid value. Found: ';

const LANGUAGE_CODES: string[] = [
'ab', 'aa', 'af', 'sq', 'am', 'ar', 'an', 'hy', 'as', 'ay', 'az', 'ba', 'eu', 'bn',
'dz', 'bh', 'bi', 'br', 'bg', 'my', 'be', 'km', 'ca', 'zh', 'zh-Hans', 'zh-Hant',
'co', 'hr', 'cs', 'da', 'nl', 'en', 'eo', 'et', 'fo', 'fa', 'fj', 'fi', 'fr', 'fy',
'gl', 'gd', 'gv', 'ka', 'de', 'el', 'kl', 'gn', 'gu', 'ht', 'ha', 'he', 'iw', 'hi',
'hu', 'is', 'io', 'id', 'in', 'ia', 'ie', 'iu', 'ik', 'ga', 'it', 'ja', 'jv', 'kn',
'ks', 'kk', 'rw', 'ky', 'rn', 'ko', 'ku', 'lo', 'la', 'lv', 'li', 'ln', 'lt', 'mk',
'mg', 'ms', 'ml', 'mt', 'mi', 'mr', 'mo', 'mn', 'na', 'ne', 'no', 'oc', 'or', 'om',
'ps', 'pl', 'pt', 'pa', 'qu', 'rm', 'ro', 'ru', 'sm', 'sg', 'sa', 'sr', 'sh', 'st',
'tn', 'sn', 'ii', 'sd', 'si', 'ss', 'sk', 'sl', 'so', 'es', 'su', 'sw', 'sv', 'tl',
'tg', 'ta', 'tt', 'te', 'th', 'bo', 'ti', 'to', 'ts', 'tr', 'tk', 'tw', 'ug', 'uk',
'ur', 'uz', 'vi', 'vo', 'wa', 'cy', 'wo', 'xh', 'yi', 'ji', 'yo', 'zu'
];

/**
* Implementation of the react-a11y-lang rule.
Expand All @@ -15,9 +30,9 @@ export class Rule extends Lint.Rules.AbstractRule {
public static metadata: ExtendedMetadata = {
ruleName: 'react-a11y-lang',
type: 'functionality',
description: 'For accessibility of your website, html elements must have a lang attribute.',
description: 'For accessibility of your website, html elements must have a valid lang attribute.',
options: null,
issueClass: 'Ignored',
issueClass: 'Non-SDL',
issueType: 'Warning',
severity: 'Low',
level: 'Opportunity for Excellence',
Expand Down Expand Up @@ -48,16 +63,27 @@ class ReactA11yLangRuleWalker extends ErrorTolerantWalker {
private validateOpeningElement(parent: ts.Node, openingElement: ts.JsxOpeningElement): void {
if (openingElement.tagName.getText() === 'html') {
const attributes: ts.NodeArray<ts.JsxAttribute | ts.JsxSpreadAttribute> = openingElement.attributes;
let found: boolean = false;
let langFound: boolean = false;

attributes.forEach((attribute: ts.JsxAttribute | ts.JsxSpreadAttribute): void => {
if (attribute.kind === SyntaxKind.current().JsxAttribute) {
if ((<ts.JsxAttribute>attribute).name.getText() === 'lang') {
found = true;
langFound = true;
if ((<ts.JsxAttribute>attribute).initializer.kind === SyntaxKind.current().StringLiteral) {
const langText: string = (<ts.StringLiteral>(<ts.JsxAttribute>attribute).initializer).text;
if ((LANGUAGE_CODES.indexOf(langText)) === -1) {
this.addFailure(this.createFailure(
parent.getStart(),
parent.getWidth(),
FAILURE_WRONG_LANG_CODE + langText
));
}
}
}
}
});
if (!found) {
this.addFailure(this.createFailure(parent.getStart(), parent.getWidth(), FAILURE_STRING));
if (!langFound) {
this.addFailure(this.createFailure(parent.getStart(), parent.getWidth(), FAILURE_MISSING_LANG));
}
}
}
Expand Down
29 changes: 27 additions & 2 deletions tests/ReactA11yLangRuleTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ describe('reactA11yLangRule', () : void => {
const script : string = `
import React = require('react');
const x = <html lang='en'></html>;
const y = <html lang='en' />;
const x = <html lang='en' title="asdf"></html>;
const y = <html lang='no' />;
`;

TestHelper.assertViolations(ruleName, script, [ ]);
Expand Down Expand Up @@ -54,4 +54,29 @@ describe('reactA11yLangRule', () : void => {
}
]);
});

it('should fail on invalid language code', () : void => {
const script : string = `
import React = require('react');
const x = <html lang='foo'></html>;
const y = <html lang='bar' />;
`;

TestHelper.assertViolations(ruleName, script, [
{
"failure": "Lang attribute does not have a valid value. Found: foo",
"name": "file.tsx",
"ruleName": "react-a11y-lang",
"startPosition": { "character": 23, "line": 4 }
},
{
"failure": "Lang attribute does not have a valid value. Found: bar",
"name": "file.tsx",
"ruleName": "react-a11y-lang",
"startPosition": { "character": 23, "line": 5 }
}
]);
});

});
1 change: 1 addition & 0 deletions tslint-warnings.csv
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ promise-must-complete,"When a Promise instance is created, then either the rejec
quotemark,Requires single or double quotes for string literals.,TSLINTU8MMGA,tslint,Non-SDL,Warning,Low,Opportunity for Excellence,See description on the tslint or tslint-microsoft-contrib website,TSLint Procedure,"398, 710","CWE 398 - Indicator of Poor Code Quality
CWE 710 - Coding Standards Violation"
radix,Requires the radix parameter to be specified when calling `parseInt`.,TSLINTTLKJQ5,tslint,Non-SDL,Warning,Low,Opportunity for Excellence,See description on the tslint or tslint-microsoft-contrib website,TSLint Procedure,710,"CWE 710 - Coding Standards Violation"
react-a11y-lang,"For accessibility of your website, html elements must have a valid lang attribute.",TSLINTQ046RM,tslint,Non-SDL,Warning,Low,Opportunity for Excellence,See description on the tslint or tslint-microsoft-contrib website,TSLint Procedure,,
react-a11y-titles,"For accessibility of your website, HTML title elements must be concise and non-empty.",TSLINT1506S53,tslint,Non-SDL,Warning,Moderate,Opportunity for Excellence,See description on the tslint or tslint-microsoft-contrib website,TSLint Procedure,,
react-iframe-missing-sandbox,React iframes must specify a sandbox attribute,TSLINTU1H6V4,tslint,Non-SDL,Error,Critical,Opportunity for Excellence,See description on the tslint or tslint-microsoft-contrib website,TSLint Procedure,915,"CWE 915 - Improperly Controlled Modification of Dynamically-Determined Object Attributes"
react-no-dangerous-html,Do not use React's dangerouslySetInnerHTML API.,TSLINTPH7BOD,tslint,SDL,Error,Critical,Mandatory,See description on the tslint or tslint-microsoft-contrib website,TSLint Procedure,"79, 85, 710","CWE 79 - Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Expand Down

0 comments on commit bd5e195

Please sign in to comment.