eslint-plugin-jsx-a11y
Advanced tools
Comparing version 0.1.1 to 0.1.2
'use strict'; | ||
const hasAttribute = (attributes, attribute) => { | ||
let idx = 0; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
var hasAttribute = function hasAttribute(attributes, attribute) { | ||
var idx = 0; | ||
const hasAttr = attributes.some((attr, index) => { | ||
var hasAttr = attributes.some(function (attr, index) { | ||
// If the attributes contain a spread attribute, then skip. | ||
@@ -24,2 +27,2 @@ if (attr.type === 'JSXSpreadAttribute') { | ||
export default hasAttribute; | ||
exports.default = hasAttribute; |
@@ -21,2 +21,2 @@ 'use strict'; | ||
} | ||
}; | ||
}; |
'use strict'; | ||
const isHiddenFromScreenReader = attributes => ( | ||
attributes.some(attribute => { | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
var isHiddenFromScreenReader = function isHiddenFromScreenReader(attributes) { | ||
return attributes.some(function (attribute) { | ||
if (attribute.type === 'JSXSpreadAttribute') { | ||
@@ -9,9 +12,9 @@ return false; | ||
const name = attribute.name.name.toUpperCase(); | ||
const value = attribute.value && attribute.value.value; | ||
var name = attribute.name.name.toUpperCase(); | ||
var value = attribute.value && attribute.value.value; | ||
return name === 'ARIA-HIDDEN' && (value === true || value === null); | ||
}) | ||
); | ||
}); | ||
}; | ||
export default isHiddenFromScreenReader; | ||
exports.default = isHiddenFromScreenReader; |
'use strict'; | ||
import hasAttribute from './hasAttribute'; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
const interactiveMap = { | ||
a: attributes => { | ||
const hasHref = hasAttribute(attributes, 'href'); | ||
const hasTabIndex = hasAttribute(attributes, 'tabIndex'); | ||
return (Boolean(hasHref) || !hasHref && Boolean(hasTabIndex)); | ||
var _hasAttribute = require('./hasAttribute'); | ||
var _hasAttribute2 = _interopRequireDefault(_hasAttribute); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
var interactiveMap = { | ||
a: function a(attributes) { | ||
var hasHref = (0, _hasAttribute2.default)(attributes, 'href'); | ||
var hasTabIndex = (0, _hasAttribute2.default)(attributes, 'tabIndex'); | ||
return Boolean(hasHref) || !hasHref && Boolean(hasTabIndex); | ||
}, | ||
button: () => true, | ||
input: attributes => { | ||
const hasTypeAttr = hasAttribute(attributes, 'type'); | ||
button: function button() { | ||
return true; | ||
}, | ||
input: function input(attributes) { | ||
var hasTypeAttr = (0, _hasAttribute2.default)(attributes, 'type'); | ||
return hasTypeAttr ? hasTypeAttr.value.value.toUpperCase() !== 'HIDDEN' : true; | ||
}, | ||
option: () => true, | ||
select: () => true, | ||
textarea: () => true | ||
option: function option() { | ||
return true; | ||
}, | ||
select: function select() { | ||
return true; | ||
}, | ||
textarea: function textarea() { | ||
return true; | ||
} | ||
}; | ||
const isInteractiveElement = (tagName, attributes) => { | ||
var isInteractiveElement = function isInteractiveElement(tagName, attributes) { | ||
if (interactiveMap.hasOwnProperty(tagName) === false) { | ||
@@ -29,2 +45,2 @@ return false; | ||
export default isInteractiveElement; | ||
exports.default = isInteractiveElement; |
@@ -11,26 +11,30 @@ /** | ||
import hasAttribute from '../hasAttribute'; | ||
var _hasAttribute = require('../hasAttribute'); | ||
const errorMessage = 'img elements must have an alt tag.'; | ||
var _hasAttribute2 = _interopRequireDefault(_hasAttribute); | ||
module.exports = context => ({ | ||
JSXOpeningElement: node => { | ||
const type = node.name.name; | ||
if (type.toUpperCase() !== 'IMG') { | ||
return; | ||
} | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
const hasAltProp = hasAttribute(node.attributes, 'alt'); | ||
var errorMessage = 'img elements must have an alt tag.'; | ||
if (hasAltProp === false) { | ||
context.report({ | ||
node, | ||
message: errorMessage | ||
}); | ||
module.exports = function (context) { | ||
return { | ||
JSXOpeningElement: function JSXOpeningElement(node) { | ||
var type = node.name.name; | ||
if (type.toUpperCase() !== 'IMG') { | ||
return; | ||
} | ||
var hasAltProp = (0, _hasAttribute2.default)(node.attributes, 'alt'); | ||
if (hasAltProp === false) { | ||
context.report({ | ||
node: node, | ||
message: errorMessage | ||
}); | ||
} | ||
} | ||
} | ||
}); | ||
}; | ||
}; | ||
module.exports.schema = [ | ||
{ type: 'object' } | ||
]; | ||
module.exports.schema = [{ type: 'object' }]; |
@@ -12,39 +12,43 @@ /** | ||
import hasAttribute from '../hasAttribute'; | ||
var _hasAttribute = require('../hasAttribute'); | ||
const mouseOverErrorMessage = 'onMouseOver must be accompanied by onFocus for accessibility.'; | ||
const mouseOutErrorMessage = 'onMouseOut must be accompanied by onBlur for accessibility.'; | ||
var _hasAttribute2 = _interopRequireDefault(_hasAttribute); | ||
module.exports = context => ({ | ||
JSXOpeningElement: node => { | ||
const attributes = node.attributes; | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
// Check onmouseover / onfocus pairing. | ||
const hasOnMouseOver = hasAttribute(attributes, 'onMouseOver'); | ||
if (Boolean(hasOnMouseOver) === true) { | ||
const hasOnFocus = hasAttribute(attributes, 'onFocus'); | ||
if (hasOnFocus === false) { | ||
context.report({ | ||
node, | ||
message: mouseOverErrorMessage | ||
}); | ||
var mouseOverErrorMessage = 'onMouseOver must be accompanied by onFocus for accessibility.'; | ||
var mouseOutErrorMessage = 'onMouseOut must be accompanied by onBlur for accessibility.'; | ||
module.exports = function (context) { | ||
return { | ||
JSXOpeningElement: function JSXOpeningElement(node) { | ||
var attributes = node.attributes; | ||
// Check onmouseover / onfocus pairing. | ||
var hasOnMouseOver = (0, _hasAttribute2.default)(attributes, 'onMouseOver'); | ||
if (Boolean(hasOnMouseOver) === true) { | ||
var hasOnFocus = (0, _hasAttribute2.default)(attributes, 'onFocus'); | ||
if (hasOnFocus === false) { | ||
context.report({ | ||
node: node, | ||
message: mouseOverErrorMessage | ||
}); | ||
} | ||
} | ||
} | ||
// Checkout onmouseout / onblur pairing | ||
const hasOnMouseOut = hasAttribute(attributes, 'onMouseOut'); | ||
if (Boolean(hasOnMouseOut) === true) { | ||
const hasOnBlur = hasAttribute(attributes, 'onBlur'); | ||
if (hasOnBlur === false) { | ||
context.report({ | ||
node, | ||
message: mouseOutErrorMessage | ||
}); | ||
// Checkout onmouseout / onblur pairing | ||
var hasOnMouseOut = (0, _hasAttribute2.default)(attributes, 'onMouseOut'); | ||
if (Boolean(hasOnMouseOut) === true) { | ||
var hasOnBlur = (0, _hasAttribute2.default)(attributes, 'onBlur'); | ||
if (hasOnBlur === false) { | ||
context.report({ | ||
node: node, | ||
message: mouseOutErrorMessage | ||
}); | ||
} | ||
} | ||
} | ||
} | ||
}); | ||
}; | ||
}; | ||
module.exports.schema = [ | ||
{ type: 'object' } | ||
]; | ||
module.exports.schema = [{ type: 'object' }]; |
@@ -11,23 +11,25 @@ /** | ||
import hasAttribute from '../hasAttribute'; | ||
var _hasAttribute = require('../hasAttribute'); | ||
const errorMessage = 'No access key attribute allowed. Incosistencies ' + | ||
'between keyboard shortcuts and keyboard comments used by screenreader ' + | ||
'and keyboard only users create a11y complications.'; | ||
var _hasAttribute2 = _interopRequireDefault(_hasAttribute); | ||
module.exports = context => ({ | ||
JSXOpeningElement: node => { | ||
const hasAccessKey = hasAttribute(node.attributes, 'accesskey'); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
if (Boolean(hasAccessKey) === true) { | ||
context.report({ | ||
node, | ||
message: errorMessage | ||
}); | ||
var errorMessage = 'No access key attribute allowed. Incosistencies ' + 'between keyboard shortcuts and keyboard comments used by screenreader ' + 'and keyboard only users create a11y complications.'; | ||
module.exports = function (context) { | ||
return { | ||
JSXOpeningElement: function JSXOpeningElement(node) { | ||
var hasAccessKey = (0, _hasAttribute2.default)(node.attributes, 'accesskey'); | ||
if (Boolean(hasAccessKey) === true) { | ||
context.report({ | ||
node: node, | ||
message: errorMessage | ||
}); | ||
} | ||
} | ||
} | ||
}); | ||
}; | ||
}; | ||
module.exports.schema = [ | ||
{ type: 'object' } | ||
]; | ||
module.exports.schema = [{ type: 'object' }]; |
@@ -8,6 +8,16 @@ /** | ||
import isHiddenFromScreenReader from '../isHiddenFromScreenReader'; | ||
import isInteractiveElement from '../isInteractiveElement'; | ||
import hasAttribute from '../hasAttribute'; | ||
var _isHiddenFromScreenReader = require('../isHiddenFromScreenReader'); | ||
var _isHiddenFromScreenReader2 = _interopRequireDefault(_isHiddenFromScreenReader); | ||
var _isInteractiveElement = require('../isInteractiveElement'); | ||
var _isInteractiveElement2 = _interopRequireDefault(_isInteractiveElement); | ||
var _hasAttribute = require('../hasAttribute'); | ||
var _hasAttribute2 = _interopRequireDefault(_hasAttribute); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
// ---------------------------------------------------------------------------- | ||
@@ -17,28 +27,27 @@ // Rule Definition | ||
const errorMessage = 'Visible, non-interactive elements with click handlers must ' + | ||
'have role attribute.'; | ||
var errorMessage = 'Visible, non-interactive elements with click handlers must ' + 'have role attribute.'; | ||
module.exports = context => ({ | ||
JSXOpeningElement: node => { | ||
const attributes = node.attributes; | ||
if (hasAttribute(attributes, 'onclick') === false) { | ||
return; | ||
} | ||
module.exports = function (context) { | ||
return { | ||
JSXOpeningElement: function JSXOpeningElement(node) { | ||
var attributes = node.attributes; | ||
if ((0, _hasAttribute2.default)(attributes, 'onclick') === false) { | ||
return; | ||
} | ||
const isVisible = isHiddenFromScreenReader(attributes) === false; | ||
const isNonInteractive = isInteractiveElement(node.name.name, attributes) === false; | ||
const noRoleAttribute = hasAttribute(attributes, 'role') === false; | ||
var isVisible = (0, _isHiddenFromScreenReader2.default)(attributes) === false; | ||
var isNonInteractive = (0, _isInteractiveElement2.default)(node.name.name, attributes) === false; | ||
var noRoleAttribute = (0, _hasAttribute2.default)(attributes, 'role') === false; | ||
// Visible, non-interactive elements require role attribute. | ||
if (isVisible && isNonInteractive && noRoleAttribute) { | ||
context.report({ | ||
node, | ||
message: errorMessage | ||
}); | ||
// Visible, non-interactive elements require role attribute. | ||
if (isVisible && isNonInteractive && noRoleAttribute) { | ||
context.report({ | ||
node: node, | ||
message: errorMessage | ||
}); | ||
} | ||
} | ||
} | ||
}); | ||
}; | ||
}; | ||
module.exports.schema = [ | ||
{ type: 'object' } | ||
]; | ||
module.exports.schema = [{ type: 'object' }]; |
@@ -11,27 +11,30 @@ /** | ||
import hasAttribute from '../hasAttribute'; | ||
var _hasAttribute = require('../hasAttribute'); | ||
const errorMessage = 'Form controls using a label to identify them must be ' + | ||
'programmatically associated with the control using htmlFor'; | ||
var _hasAttribute2 = _interopRequireDefault(_hasAttribute); | ||
module.exports = context => ({ | ||
JSXOpeningElement: node => { | ||
const type = node.name.name; | ||
if (type.toUpperCase() !== 'LABEL') { | ||
return; | ||
} | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
const hasHtmlForAttr = hasAttribute(node.attributes, 'htmlFor'); | ||
var errorMessage = 'Form controls using a label to identify them must be ' + 'programmatically associated with the control using htmlFor'; | ||
if (hasHtmlForAttr === false) { | ||
context.report({ | ||
node, | ||
message: errorMessage | ||
}); | ||
module.exports = function (context) { | ||
return { | ||
JSXOpeningElement: function JSXOpeningElement(node) { | ||
var type = node.name.name; | ||
if (type.toUpperCase() !== 'LABEL') { | ||
return; | ||
} | ||
var hasHtmlForAttr = (0, _hasAttribute2.default)(node.attributes, 'htmlFor'); | ||
if (hasHtmlForAttr === false) { | ||
context.report({ | ||
node: node, | ||
message: errorMessage | ||
}); | ||
} | ||
} | ||
} | ||
}); | ||
}; | ||
}; | ||
module.exports.schema = [ | ||
{ type: 'object' } | ||
]; | ||
module.exports.schema = [{ type: 'object' }]; |
@@ -11,24 +11,26 @@ /** | ||
import hasAttribute from '../hasAttribute'; | ||
var _hasAttribute = require('../hasAttribute'); | ||
const errorMessage = 'onBlur must be used instead of onchange, ' + | ||
'unless absolutely necessary and it causes no negative consequences ' + | ||
'for keyboard only or screen reader users.'; | ||
var _hasAttribute2 = _interopRequireDefault(_hasAttribute); | ||
module.exports = context => ({ | ||
JSXOpeningElement: node => { | ||
const hasOnChange = hasAttribute(node.attributes, 'onChange'); | ||
const hasOnBlur = hasAttribute(node.attributes, 'onBlur'); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
if (Boolean(hasOnChange) === true && hasOnBlur === false) { | ||
context.report({ | ||
node, | ||
message: errorMessage | ||
}); | ||
var errorMessage = 'onBlur must be used instead of onchange, ' + 'unless absolutely necessary and it causes no negative consequences ' + 'for keyboard only or screen reader users.'; | ||
module.exports = function (context) { | ||
return { | ||
JSXOpeningElement: function JSXOpeningElement(node) { | ||
var hasOnChange = (0, _hasAttribute2.default)(node.attributes, 'onChange'); | ||
var hasOnBlur = (0, _hasAttribute2.default)(node.attributes, 'onBlur'); | ||
if (Boolean(hasOnChange) === true && hasOnBlur === false) { | ||
context.report({ | ||
node: node, | ||
message: errorMessage | ||
}); | ||
} | ||
} | ||
} | ||
}); | ||
}; | ||
}; | ||
module.exports.schema = [ | ||
{ type: 'object' } | ||
]; | ||
module.exports.schema = [{ type: 'object' }]; |
{ | ||
"name": "eslint-plugin-jsx-a11y", | ||
"version": "0.1.1", | ||
"version": "0.1.2", | ||
"description": "A static analysis linter of jsx and their accessibility with screen readers.", | ||
@@ -18,8 +18,8 @@ "keywords": [ | ||
}, | ||
"main": "index.js", | ||
"main": "lib/index.js", | ||
"scripts": { | ||
"build": "webpack --config .webpack.config.js --optimize-minimize", | ||
"build": "babel src --out-dir lib", | ||
"prepublish": "npm run lint && npm run test && npm run build", | ||
"coveralls": "cat ./reports/coverage/lcov.info | coveralls", | ||
"lint": "eslint --config .eslintrc.js ./", | ||
"lint": "eslint --config .eslintrc.js src tests", | ||
"pretest": "npm run lint", | ||
@@ -32,3 +32,2 @@ "test": "istanbul cover --dir reports/coverage node_modules/mocha/bin/_mocha tests/**/*.js -- --compilers js:babel-core/register --reporter nyan" | ||
"babel-eslint": "^5.0.0", | ||
"babel-loader": "^6.2.4", | ||
"babel-preset-es2015": "^6.6.0", | ||
@@ -38,4 +37,3 @@ "coveralls": "^2.11.8", | ||
"istanbul": "^1.0.0-alpha.2", | ||
"mocha": "^2.4.5", | ||
"webpack": "^1.12.14" | ||
"mocha": "^2.4.5" | ||
}, | ||
@@ -42,0 +40,0 @@ "engines": { |
/* eslint-env mocha */ | ||
'use strict'; | ||
import plugin from '../lib'; | ||
import plugin from '../src'; | ||
@@ -10,3 +10,3 @@ import assert from 'assert'; | ||
const rules = fs.readdirSync(path.resolve(__dirname, '../lib/rules/')) | ||
const rules = fs.readdirSync(path.resolve(__dirname, '../src/rules/')) | ||
.map(f => path.basename(f, '.js')); | ||
@@ -19,3 +19,3 @@ | ||
plugin.rules[ruleName], | ||
require(path.join('../lib/rules', ruleName)) | ||
require(path.join('../src/rules', ruleName)) | ||
); | ||
@@ -22,0 +22,0 @@ }); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
39478
8
35
973
1