From 356944af1e8ae9fb8fa3dfb260726df793ae2647 Mon Sep 17 00:00:00 2001 From: Ethan Cohen Date: Sat, 21 Oct 2017 21:36:56 -0400 Subject: [PATCH] Upgrade dependencies. --- __mocks__/genInteractives.js | 19 ++-- __tests__/__util__/parserOptionsMapper.js | 2 +- .../__util__/ruleOptionsMapperFactory.js | 19 ++-- __tests__/src/rules/aria-role-test.js | 8 +- .../rules/interactive-supports-focus-test.js | 10 +-- __tests__/src/util/getTabIndex-test.js | 80 ++++------------- __tests__/src/util/hasAccessibleChild-test.js | 4 +- __tests__/src/util/isAbstractRole-test.js | 40 ++++----- .../src/util/isInteractiveElement-test.js | 90 +++++++++---------- __tests__/src/util/isInteractiveRole-test.js | 40 ++++----- .../src/util/isNonInteractiveElement-test.js | 90 +++++++++---------- .../src/util/isNonInteractiveRole-test.js | 40 ++++----- package.json | 20 ++--- scripts/addRuleToIndex.js | 16 ++-- scripts/create-rule.js | 2 +- src/rules/accessible-emoji.js | 4 +- src/rules/alt-text.js | 5 +- src/rules/anchor-is-valid.js | 8 +- src/rules/aria-proptypes.js | 1 + src/rules/aria-role.js | 4 +- src/rules/interactive-supports-focus.js | 20 ++--- src/rules/mouse-events-have-key-events.js | 2 +- ...eractive-element-to-noninteractive-role.js | 8 +- .../no-noninteractive-element-interactions.js | 8 +- ...interactive-element-to-interactive-role.js | 8 +- src/rules/no-noninteractive-tabindex.js | 16 ++-- src/rules/no-static-element-interactions.js | 8 +- src/rules/tabindex-no-positive.js | 1 + src/util/attributesComparator.js | 38 ++++---- src/util/hasAccessibleChild.js | 3 +- src/util/isInteractiveElement.js | 68 ++++++-------- src/util/isInteractiveRole.js | 4 +- src/util/isNonInteractiveElement.js | 68 ++++++-------- src/util/isNonInteractiveRole.js | 4 +- src/util/isPresentationRole.js | 4 +- 35 files changed, 294 insertions(+), 468 deletions(-) diff --git a/__mocks__/genInteractives.js b/__mocks__/genInteractives.js index 01cca74a2..9dd7b4261 100644 --- a/__mocks__/genInteractives.js +++ b/__mocks__/genInteractives.js @@ -142,8 +142,8 @@ export function genElementSymbol(openingElement: Object) { openingElement.name.name + (openingElement.attributes.length > 0 ? `${openingElement.attributes - .map(attr => `[${attr.name.name}="${attr.value.value}"]`) - .join('')}` + .map(attr => `[${attr.name.name}="${attr.value.value}"]`) + .join('')}` : '') ); } @@ -156,16 +156,14 @@ export function genInteractiveElements() { name = elementSymbol.slice(0, bracketIndex); } const attributes = interactiveElementsMap[elementSymbol].map(({ prop, value }) => - JSXAttributeMock(prop, value), - ); + JSXAttributeMock(prop, value)); return JSXElementMock(name, attributes); }); } export function genInteractiveRoleElements() { return [...interactiveRoles, 'button article', 'fakerole button article'].map(value => - JSXElementMock('div', [JSXAttributeMock('role', value)]), - ); + JSXElementMock('div', [JSXAttributeMock('role', value)])); } export function genNonInteractiveElements() { @@ -176,16 +174,14 @@ export function genNonInteractiveElements() { name = elementSymbol.slice(0, bracketIndex); } const attributes = nonInteractiveElementsMap[elementSymbol].map(({ prop, value }) => - JSXAttributeMock(prop, value), - ); + JSXAttributeMock(prop, value)); return JSXElementMock(name, attributes); }); } export function genNonInteractiveRoleElements() { return [...nonInteractiveRoles, 'article button', 'fakerole article button'].map(value => - JSXElementMock('div', [JSXAttributeMock('role', value)]), - ); + JSXElementMock('div', [JSXAttributeMock('role', value)])); } export function genAbstractRoleElements() { @@ -199,8 +195,7 @@ export function genNonAbstractRoleElements() { export function genIndeterminantInteractiveElements() { return Object.keys(indeterminantInteractiveElementsMap).map((name) => { const attributes = indeterminantInteractiveElementsMap[name].map(({ prop, value }) => - JSXAttributeMock(prop, value), - ); + JSXAttributeMock(prop, value)); return JSXElementMock(name, attributes); }); } diff --git a/__tests__/__util__/parserOptionsMapper.js b/__tests__/__util__/parserOptionsMapper.js index f38e466db..0e9e99029 100644 --- a/__tests__/__util__/parserOptionsMapper.js +++ b/__tests__/__util__/parserOptionsMapper.js @@ -8,7 +8,7 @@ const defaultParserOptions = { export default function parserOptionsMapper({ code, errors, - options, + options = [], parserOptions = {}, }) { return { diff --git a/__tests__/__util__/ruleOptionsMapperFactory.js b/__tests__/__util__/ruleOptionsMapperFactory.js index 6d5790a09..e601b0496 100644 --- a/__tests__/__util__/ruleOptionsMapperFactory.js +++ b/__tests__/__util__/ruleOptionsMapperFactory.js @@ -4,23 +4,14 @@ type ESLintTestRunnerTestCase = { code: string, - errors: ?Array<{ - message: string, - type: string, - }>, + errors: ?Array<{ message: string, type: string }>, options: ?Array, - parserOptions: ?Array, + parserOptions: ?Array }; -export default function ruleOptionsMapperFactory( - ruleOptions: Array = [], -) { - return ({ - code, - errors, - options, - parserOptions, - }: ESLintTestRunnerTestCase): ESLintTestRunnerTestCase => ({ +export default function ruleOptionsMapperFactory(ruleOptions: Array = []) { + // eslint-disable-next-line + return ({ code, errors, options, parserOptions }: ESLintTestRunnerTestCase): ESLintTestRunnerTestCase => ({ code, errors, options: (options || []).concat(ruleOptions), diff --git a/__tests__/src/rules/aria-role-test.js b/__tests__/src/rules/aria-role-test.js index 989a55bbe..fe26d56f2 100644 --- a/__tests__/src/rules/aria-role-test.js +++ b/__tests__/src/rules/aria-role-test.js @@ -26,12 +26,8 @@ const errorMessage = { const roleKeys = [...roles.keys()]; -const validRoles = roleKeys.filter( - role => roles.get(role).abstract === false, -); -const invalidRoles = roleKeys.filter( - role => roles.get(role).abstract === true, -); +const validRoles = roleKeys.filter(role => roles.get(role).abstract === false); +const invalidRoles = roleKeys.filter(role => roles.get(role).abstract === true); const createTests = roleNames => roleNames.map(role => ({ code: `
`, diff --git a/__tests__/src/rules/interactive-supports-focus-test.js b/__tests__/src/rules/interactive-supports-focus-test.js index 407c9c957..55a6df916 100644 --- a/__tests__/src/rules/interactive-supports-focus-test.js +++ b/__tests__/src/rules/interactive-supports-focus-test.js @@ -175,10 +175,7 @@ const passReducer = (roles, handlers, messageTemplate) => roleAcc.concat(handlers .map(handler => ({ code: messageTemplate(element, role, handler), - }), - ), - ), []), - ), []); + }))), [])), []); const failReducer = (roles, handlers, messageTemplate) => staticElements.reduce((elementAcc, element) => @@ -190,10 +187,7 @@ const failReducer = (roles, handlers, messageTemplate) => type, message: messageTemplate(role), }], - }), - ), - ), []), - ), []); + }))), [])), []); ruleTester.run(`${ruleName}:recommended`, rule, { valid: [ diff --git a/__tests__/src/util/getTabIndex-test.js b/__tests__/src/util/getTabIndex-test.js index ac0ee7506..792fe339a 100644 --- a/__tests__/src/util/getTabIndex-test.js +++ b/__tests__/src/util/getTabIndex-test.js @@ -8,87 +8,51 @@ describe('getTabIndex', () => { describe('as a number ', () => { describe('zero', () => { it('should return zero', () => { - expect( - getTabIndex( - JSXAttributeMock('tabIndex', 0), - ), - ).toBe(0); + expect(getTabIndex(JSXAttributeMock('tabIndex', 0))).toBe(0); }); }); describe('positive integer', () => { it('should return the integer', () => { - expect( - getTabIndex( - JSXAttributeMock('tabIndex', 1), - ), - ).toBe(1); + expect(getTabIndex(JSXAttributeMock('tabIndex', 1))).toBe(1); }); }); describe('negative integer', () => { it('should return the integer', () => { - expect( - getTabIndex( - JSXAttributeMock('tabIndex', -1), - ), - ).toBe(-1); + expect(getTabIndex(JSXAttributeMock('tabIndex', -1))).toBe(-1); }); }); describe('float', () => { it('should return undefined', () => { - expect( - getTabIndex( - JSXAttributeMock('tabIndex', 9.1), - ), - ).toBeUndefined(); + expect(getTabIndex(JSXAttributeMock('tabIndex', 9.1))).toBeUndefined(); }); }); }); describe('as a string', () => { describe('empty', () => { it('should return undefined', () => { - expect( - getTabIndex( - JSXAttributeMock('tabIndex', ''), - ), - ).toBeUndefined(); + expect(getTabIndex(JSXAttributeMock('tabIndex', ''))).toBeUndefined(); }); }); describe('which converts to a number', () => { it('should return an integer', () => { - expect( - getTabIndex( - JSXAttributeMock('tabIndex', '0'), - ), - ).toBe(0); + expect(getTabIndex(JSXAttributeMock('tabIndex', '0'))).toBe(0); }); }); describe('which is NaN', () => { it('should return undefined', () => { - expect( - getTabIndex( - JSXAttributeMock('tabIndex', '0a'), - ), - ).toBeUndefined(); + expect(getTabIndex(JSXAttributeMock('tabIndex', '0a'))).toBeUndefined(); }); }); }); describe('as a boolean', () => { describe('true', () => { it('should return undefined', () => { - expect( - getTabIndex( - JSXAttributeMock('tabIndex', true), - ), - ).toBeUndefined(); + expect(getTabIndex(JSXAttributeMock('tabIndex', true))).toBeUndefined(); }); }); describe('false', () => { it('should return undefined', () => { - expect( - getTabIndex( - JSXAttributeMock('tabIndex', false), - ), - ).toBeUndefined(); + expect(getTabIndex(JSXAttributeMock('tabIndex', false))).toBeUndefined(); }); }); }); @@ -96,36 +60,24 @@ describe('getTabIndex', () => { describe('function expression', () => { it('should return the correct type', () => { const attr = function mockFn() { return 0; }; - expect( - typeof getTabIndex( - JSXAttributeMock('tabIndex', attr), - ), - ).toEqual('function'); + expect(typeof getTabIndex(JSXAttributeMock('tabIndex', attr))).toEqual('function'); }); }); describe('variable expression', () => { it('should return the Identifier name', () => { const name = 'identName'; - expect( - getTabIndex( - JSXAttributeMock( - 'tabIndex', - IdentifierMock(name), - true, - ), - ), - ).toEqual(name); + expect(getTabIndex(JSXAttributeMock( + 'tabIndex', + IdentifierMock(name), + true, + ))).toEqual(name); }); }); }); }); describe('tabIndex is not defined', () => { it('should return undefined', () => { - expect( - getTabIndex( - JSXAttributeMock('tabIndex', undefined), - ), - ).toBeUndefined(); + expect(getTabIndex(JSXAttributeMock('tabIndex', undefined))).toBeUndefined(); }); }); }); diff --git a/__tests__/src/util/hasAccessibleChild-test.js b/__tests__/src/util/hasAccessibleChild-test.js index a216329c5..bbdd2f846 100644 --- a/__tests__/src/util/hasAccessibleChild-test.js +++ b/__tests__/src/util/hasAccessibleChild-test.js @@ -7,9 +7,7 @@ import JSXExpressionContainerMock from '../../../__mocks__/JSXExpressionContaine describe('hasAccessibleChild', () => { describe('has no children and does not set dangerouslySetInnerHTML', () => { it('returns false', () => { - expect( - hasAccessibleChild(JSXElementMock('div', [])), - ).toBe(false); + expect(hasAccessibleChild(JSXElementMock('div', []))).toBe(false); }); }); diff --git a/__tests__/src/util/isAbstractRole-test.js b/__tests__/src/util/isAbstractRole-test.js index 15f385f49..5b0750965 100644 --- a/__tests__/src/util/isAbstractRole-test.js +++ b/__tests__/src/util/isAbstractRole-test.js @@ -16,29 +16,25 @@ describe('isAbstractRole', () => { }); }); describe('elements with an abstract role', () => { - genAbstractRoleElements().forEach( - ({ openingElement }) => { - const attributes = openingElement.attributes; - it(`should identify \`${genElementSymbol(openingElement)}\` as an abstract role element`, () => { - expect(isAbstractRole( - elementType(openingElement), - attributes, - )).toBe(true); - }); - }, - ); + genAbstractRoleElements().forEach(({ openingElement }) => { + const { attributes } = openingElement; + it(`should identify \`${genElementSymbol(openingElement)}\` as an abstract role element`, () => { + expect(isAbstractRole( + elementType(openingElement), + attributes, + )).toBe(true); + }); + }); }); describe('elements with a non-abstract role', () => { - genNonAbstractRoleElements().forEach( - ({ openingElement }) => { - const attributes = openingElement.attributes; - it(`should NOT identify \`${genElementSymbol(openingElement)}\` as an abstract role element`, () => { - expect(isAbstractRole( - elementType(openingElement), - attributes, - )).toBe(false); - }); - }, - ); + genNonAbstractRoleElements().forEach(({ openingElement }) => { + const { attributes } = openingElement; + it(`should NOT identify \`${genElementSymbol(openingElement)}\` as an abstract role element`, () => { + expect(isAbstractRole( + elementType(openingElement), + attributes, + )).toBe(false); + }); + }); }); }); diff --git a/__tests__/src/util/isInteractiveElement-test.js b/__tests__/src/util/isInteractiveElement-test.js index a183812fb..559fc0741 100644 --- a/__tests__/src/util/isInteractiveElement-test.js +++ b/__tests__/src/util/isInteractiveElement-test.js @@ -20,64 +20,54 @@ describe('isInteractiveElement', () => { }); }); describe('interactive elements', () => { - genInteractiveElements().forEach( - ({ openingElement }) => { - it(`should identify \`${genElementSymbol(openingElement)}\` as an interactive element`, () => { - expect(isInteractiveElement( - elementType(openingElement), - openingElement.attributes, - )).toBe(true); - }); - }, - ); + genInteractiveElements().forEach(({ openingElement }) => { + it(`should identify \`${genElementSymbol(openingElement)}\` as an interactive element`, () => { + expect(isInteractiveElement( + elementType(openingElement), + openingElement.attributes, + )).toBe(true); + }); + }); }); describe('interactive role elements', () => { - genInteractiveRoleElements().forEach( - ({ openingElement }) => { - it(`should NOT identify \`${genElementSymbol(openingElement)}\` as an interactive element`, () => { - expect(isInteractiveElement( - elementType(openingElement), - openingElement.attributes, - )).toBe(false); - }); - }, - ); + genInteractiveRoleElements().forEach(({ openingElement }) => { + it(`should NOT identify \`${genElementSymbol(openingElement)}\` as an interactive element`, () => { + expect(isInteractiveElement( + elementType(openingElement), + openingElement.attributes, + )).toBe(false); + }); + }); }); describe('non-interactive elements', () => { - genNonInteractiveElements().forEach( - ({ openingElement }) => { - it(`should NOT identify \`${genElementSymbol(openingElement)}\` as an interactive element`, () => { - expect(isInteractiveElement( - elementType(openingElement), - openingElement.attributes, - )).toBe(false); - }); - }, - ); + genNonInteractiveElements().forEach(({ openingElement }) => { + it(`should NOT identify \`${genElementSymbol(openingElement)}\` as an interactive element`, () => { + expect(isInteractiveElement( + elementType(openingElement), + openingElement.attributes, + )).toBe(false); + }); + }); }); describe('non-interactive role elements', () => { - genNonInteractiveRoleElements().forEach( - ({ openingElement }) => { - it(`should NOT identify \`${genElementSymbol(openingElement)}\` as an interactive element`, () => { - expect(isInteractiveElement( - elementType(openingElement), - openingElement.attributes, - )).toBe(false); - }); - }, - ); + genNonInteractiveRoleElements().forEach(({ openingElement }) => { + it(`should NOT identify \`${genElementSymbol(openingElement)}\` as an interactive element`, () => { + expect(isInteractiveElement( + elementType(openingElement), + openingElement.attributes, + )).toBe(false); + }); + }); }); describe('indeterminate elements', () => { - genIndeterminantInteractiveElements().forEach( - ({ openingElement }) => { - it(`should NOT identify \`${openingElement.name.name}\` as an interactive element`, () => { - expect(isInteractiveElement( - elementType(openingElement), - openingElement.attributes, - )).toBe(false); - }); - }, - ); + genIndeterminantInteractiveElements().forEach(({ openingElement }) => { + it(`should NOT identify \`${openingElement.name.name}\` as an interactive element`, () => { + expect(isInteractiveElement( + elementType(openingElement), + openingElement.attributes, + )).toBe(false); + }); + }); }); describe('JSX elements', () => { it('is not interactive', () => { diff --git a/__tests__/src/util/isInteractiveRole-test.js b/__tests__/src/util/isInteractiveRole-test.js index d49d1fd2a..048f43475 100644 --- a/__tests__/src/util/isInteractiveRole-test.js +++ b/__tests__/src/util/isInteractiveRole-test.js @@ -16,17 +16,15 @@ describe('isInteractiveRole', () => { }); }); describe('elements with a non-interactive role', () => { - genNonInteractiveRoleElements().forEach( - ({ openingElement }) => { - const attributes = openingElement.attributes; - it(`should not identify \`${genElementSymbol(openingElement)}\` as an interactive role element`, () => { - expect(isInteractiveRole( - elementType(openingElement), - attributes, - )).toBe(false); - }); - }, - ); + genNonInteractiveRoleElements().forEach(({ openingElement }) => { + const { attributes } = openingElement; + it(`should not identify \`${genElementSymbol(openingElement)}\` as an interactive role element`, () => { + expect(isInteractiveRole( + elementType(openingElement), + attributes, + )).toBe(false); + }); + }); }); describe('elements without a role', () => { it('should not identify them as interactive role elements', () => { @@ -34,16 +32,14 @@ describe('isInteractiveRole', () => { }); }); describe('elements with an interactive role', () => { - genInteractiveRoleElements().forEach( - ({ openingElement }) => { - const attributes = openingElement.attributes; - it(`should identify \`${genElementSymbol(openingElement)}\` as an interactive role element`, () => { - expect(isInteractiveRole( - elementType(openingElement), - attributes, - )).toBe(true); - }); - }, - ); + genInteractiveRoleElements().forEach(({ openingElement }) => { + const { attributes } = openingElement; + it(`should identify \`${genElementSymbol(openingElement)}\` as an interactive role element`, () => { + expect(isInteractiveRole( + elementType(openingElement), + attributes, + )).toBe(true); + }); + }); }); }); diff --git a/__tests__/src/util/isNonInteractiveElement-test.js b/__tests__/src/util/isNonInteractiveElement-test.js index b664dccdd..ea2fb36ed 100644 --- a/__tests__/src/util/isNonInteractiveElement-test.js +++ b/__tests__/src/util/isNonInteractiveElement-test.js @@ -19,63 +19,53 @@ describe('isNonInteractiveElement', () => { }); }); describe('non-interactive elements', () => { - genNonInteractiveElements().forEach( - ({ openingElement }) => { - it(`should identify \`${genElementSymbol(openingElement)}\` as a non-interactive element`, () => { - expect(isNonInteractiveElement( - elementType(openingElement), - openingElement.attributes, - )).toBe(true); - }); - }, - ); + genNonInteractiveElements().forEach(({ openingElement }) => { + it(`should identify \`${genElementSymbol(openingElement)}\` as a non-interactive element`, () => { + expect(isNonInteractiveElement( + elementType(openingElement), + openingElement.attributes, + )).toBe(true); + }); + }); }); describe('non-interactive role elements', () => { - genNonInteractiveRoleElements().forEach( - ({ openingElement }) => { - it(`should NOT identify \`${genElementSymbol(openingElement)}\` as a non-interactive element`, () => { - expect(isNonInteractiveElement( - elementType(openingElement), - openingElement.attributes, - )).toBe(false); - }); - }, - ); + genNonInteractiveRoleElements().forEach(({ openingElement }) => { + it(`should NOT identify \`${genElementSymbol(openingElement)}\` as a non-interactive element`, () => { + expect(isNonInteractiveElement( + elementType(openingElement), + openingElement.attributes, + )).toBe(false); + }); + }); }); describe('interactive elements', () => { - genInteractiveElements().forEach( - ({ openingElement }) => { - it(`should NOT identify \`${genElementSymbol(openingElement)}\` as a non-interactive element`, () => { - expect(isNonInteractiveElement( - elementType(openingElement), - openingElement.attributes, - )).toBe(false); - }); - }, - ); + genInteractiveElements().forEach(({ openingElement }) => { + it(`should NOT identify \`${genElementSymbol(openingElement)}\` as a non-interactive element`, () => { + expect(isNonInteractiveElement( + elementType(openingElement), + openingElement.attributes, + )).toBe(false); + }); + }); }); describe('interactive role elements', () => { - genInteractiveRoleElements().forEach( - ({ openingElement }) => { - it(`should NOT identify \`${genElementSymbol(openingElement)}\` as a non-interactive element`, () => { - expect(isNonInteractiveElement( - elementType(openingElement), - openingElement.attributes, - )).toBe(false); - }); - }, - ); + genInteractiveRoleElements().forEach(({ openingElement }) => { + it(`should NOT identify \`${genElementSymbol(openingElement)}\` as a non-interactive element`, () => { + expect(isNonInteractiveElement( + elementType(openingElement), + openingElement.attributes, + )).toBe(false); + }); + }); }); describe('indeterminate elements', () => { - genIndeterminantInteractiveElements().forEach( - ({ openingElement }) => { - it(`should NOT identify \`${openingElement.name.name}\` as a non-interactive element`, () => { - expect(isNonInteractiveElement( - elementType(openingElement), - openingElement.attributes, - )).toBe(false); - }); - }, - ); + genIndeterminantInteractiveElements().forEach(({ openingElement }) => { + it(`should NOT identify \`${openingElement.name.name}\` as a non-interactive element`, () => { + expect(isNonInteractiveElement( + elementType(openingElement), + openingElement.attributes, + )).toBe(false); + }); + }); }); }); diff --git a/__tests__/src/util/isNonInteractiveRole-test.js b/__tests__/src/util/isNonInteractiveRole-test.js index 316c7305e..4d241dadb 100644 --- a/__tests__/src/util/isNonInteractiveRole-test.js +++ b/__tests__/src/util/isNonInteractiveRole-test.js @@ -16,17 +16,15 @@ describe('isNonInteractiveRole', () => { }); }); describe('elements with a non-interactive role', () => { - genNonInteractiveRoleElements().forEach( - ({ openingElement }) => { - const attributes = openingElement.attributes; - it(`should identify \`${genElementSymbol(openingElement)}\` as non-interactive role element`, () => { - expect(isNonInteractiveRole( - elementType(openingElement), - attributes, - )).toBe(true); - }); - }, - ); + genNonInteractiveRoleElements().forEach(({ openingElement }) => { + const { attributes } = openingElement; + it(`should identify \`${genElementSymbol(openingElement)}\` as non-interactive role element`, () => { + expect(isNonInteractiveRole( + elementType(openingElement), + attributes, + )).toBe(true); + }); + }); }); describe('elements without a role', () => { it('should not identify them as non-interactive role elements', () => { @@ -34,16 +32,14 @@ describe('isNonInteractiveRole', () => { }); }); describe('elements with an interactive role', () => { - genInteractiveRoleElements().forEach( - ({ openingElement }) => { - const attributes = openingElement.attributes; - it(`should NOT identify \`${genElementSymbol(openingElement)}\` as a non-interactive role element`, () => { - expect(isNonInteractiveRole( - elementType(openingElement), - attributes, - )).toBe(false); - }); - }, - ); + genInteractiveRoleElements().forEach(({ openingElement }) => { + const { attributes } = openingElement; + it(`should NOT identify \`${genElementSymbol(openingElement)}\` as a non-interactive role element`, () => { + expect(isNonInteractiveRole( + elementType(openingElement), + attributes, + )).toBe(false); + }); + }); }); }); diff --git a/package.json b/package.json index 4d7f16ec5..7e486ee2f 100644 --- a/package.json +++ b/package.json @@ -32,22 +32,22 @@ "devDependencies": { "babel-cli": "^6.24.1", "babel-core": "^6.25.0", - "babel-eslint": "^7.2.3", - "babel-jest": "^20.0.3", + "babel-eslint": "^8.0.1", + "babel-jest": "^21.2.0", "babel-plugin-transform-es2015-template-literals": "^6.22.0", "babel-plugin-transform-flow-strip-types": "^6.22.0", "babel-plugin-transform-object-rest-spread": "^6.23.0", "babel-polyfill": "^6.23.0", "babel-preset-es2015": "^6.24.1", - "coveralls": "^2.13.1", - "eslint": "^3.19.0", - "eslint-config-airbnb-base": "^11.2.0", - "eslint-plugin-flowtype": "^2.34.0", - "eslint-plugin-import": "^2.3.0", - "expect": "^1.20.2", - "flow-bin": "^0.51.0", + "coveralls": "^3.0.0", + "eslint": "^4.9.0", + "eslint-config-airbnb-base": "^12.1.0", + "eslint-plugin-flowtype": "^2.39.1", + "eslint-plugin-import": "^2.8.0", + "expect": "^21.2.1", + "flow-bin": "^0.57.3", "in-publish": "^2.0.0", - "jest": "^20.0.4", + "jest": "^21.2.1", "jscodeshift": "^0.3.30", "minimist": "^1.2.0", "object.assign": "^4.0.4", diff --git a/scripts/addRuleToIndex.js b/scripts/addRuleToIndex.js index 86278b66e..12657a2ac 100644 --- a/scripts/addRuleToIndex.js +++ b/scripts/addRuleToIndex.js @@ -28,20 +28,16 @@ export default function transformer(file, api, options) { .forEach((path, index) => { // Add rule path. if (index === 0) { - path.parentPath.value.value.properties.unshift( - j.property( - 'init', - j.literal(ruleName), - j.callExpression(j.identifier('require'), [j.literal(rulePathInSrc)]), - ), - ); + path.parentPath.value.value.properties.unshift(j.property( + 'init', + j.literal(ruleName), + j.callExpression(j.identifier('require'), [j.literal(rulePathInSrc)]), + )); path.parentPath.value.value.properties.sort(nameSort); } // Set default reporting to error. if (index === 1) { - path.parentPath.value.value.properties.unshift( - j.property('init', j.literal(`jsx-a11y/${ruleName}`), j.literal('error')), - ); + path.parentPath.value.value.properties.unshift(j.property('init', j.literal(`jsx-a11y/${ruleName}`), j.literal('error'))); path.parentPath.value.value.properties.sort(nameSort); } }).length; diff --git a/scripts/create-rule.js b/scripts/create-rule.js index ed9f31ac5..8bfdcb645 100755 --- a/scripts/create-rule.js +++ b/scripts/create-rule.js @@ -5,7 +5,7 @@ const argv = require('minimist')(process.argv.slice(2)); // eslint-disable-line const ruleBoilerplateGenerator = require('./boilerplate/rule'); const testBoilerplateGenerator = require('./boilerplate/test'); const docBoilerplateGenerator = require('./boilerplate/doc'); -const exec = require('child_process').exec; +const { exec } = require('child_process'); const ruleName = argv._[0]; const author = argv.author || '$AUTHOR'; diff --git a/src/rules/accessible-emoji.js b/src/rules/accessible-emoji.js index 4c95eab24..57320be3b 100644 --- a/src/rules/accessible-emoji.js +++ b/src/rules/accessible-emoji.js @@ -24,9 +24,7 @@ module.exports = { create: context => ({ JSXOpeningElement: (node) => { - const literalChildValue = node.parent.children.find( - child => child.type === 'Literal', - ); + const literalChildValue = node.parent.children.find(child => child.type === 'Literal'); if (literalChildValue && emojiRegex().test(literalChildValue.value)) { const rolePropValue = getLiteralPropValue(getProp(node.attributes, 'role')); diff --git a/src/rules/alt-text.js b/src/rules/alt-text.js index ea8e4d79b..28b1946bc 100644 --- a/src/rules/alt-text.js +++ b/src/rules/alt-text.js @@ -164,9 +164,8 @@ module.exports = { const customComponents = elementOptions .map(element => options[element]) .reduce( - (components, customComponentsForElement) => components.concat( - customComponentsForElement || [], - ), + (components, customComponentsForElement) => + components.concat(customComponentsForElement || []), [], ); const typesToValidate = new Set([] diff --git a/src/rules/anchor-is-valid.js b/src/rules/anchor-is-valid.js index 628492a2f..989b348ae 100644 --- a/src/rules/anchor-is-valid.js +++ b/src/rules/anchor-is-valid.js @@ -39,7 +39,7 @@ module.exports = { create: (context: ESLintContext) => ({ JSXOpeningElement: (node: JSXOpeningElement) => { - const attributes = node.attributes; + const { attributes } = node; const options = context.options[0] || {}; const componentOptions = options.components || []; const typeCheck = ['a'].concat(componentOptions); @@ -67,11 +67,11 @@ module.exports = { .map(prop => getPropValue(prop)); // Checks if any actual or custom href prop is provided. const hasAnyHref = values - .filter(value => value === undefined || value === null).length !== values.length; + .filter(value => value === undefined || value === null).length !== values.length; // Need to check for spread operator as props can be spread onto the element // leading to an incorrect validation error. const hasSpreadOperator = attributes - .filter(prop => prop.type === 'JSXSpreadAttribute').length > 0; + .filter(prop => prop.type === 'JSXSpreadAttribute').length > 0; const onClick = getProp(attributes, 'onClick'); // When there is no href at all, specific scenarios apply: @@ -99,7 +99,7 @@ module.exports = { const invalidHrefValues = values .filter(value => value !== undefined && value !== null) .filter(value => - typeof value === 'string' && + typeof value === 'string' && (!value.length || value === '#' || /^\W*?javascript/.test(value) diff --git a/src/rules/aria-proptypes.js b/src/rules/aria-proptypes.js index 27bd1fb4e..9385a7ebb 100644 --- a/src/rules/aria-proptypes.js +++ b/src/rules/aria-proptypes.js @@ -40,6 +40,7 @@ const validityCheck = (value, expectedType, permittedValues) => { case 'integer': case 'number': // Booleans resolve to 0/1 values so hard check that it's not first. + // eslint-disable-next-line no-restricted-globals return typeof value !== 'boolean' && isNaN(Number(value)) === false; case 'token': return permittedValues.indexOf(typeof value === 'string' ? value.toLowerCase() : value) > -1; diff --git a/src/rules/aria-role.js b/src/rules/aria-role.js index aff184991..c45cb8074 100644 --- a/src/rules/aria-role.js +++ b/src/rules/aria-role.js @@ -53,9 +53,7 @@ module.exports = { if (value === undefined || value === null) { return; } const normalizedValues = String(value).toLowerCase().split(' '); - const validRoles = [...roles.keys()].filter( - role => roles.get(role).abstract === false, - ); + const validRoles = [...roles.keys()].filter(role => roles.get(role).abstract === false); const isValid = normalizedValues.every(val => validRoles.indexOf(val) > -1); if (isValid === true) { return; } diff --git a/src/rules/interactive-supports-focus.js b/src/rules/interactive-supports-focus.js index c8ca1dc39..a19403b3f 100644 --- a/src/rules/interactive-supports-focus.js +++ b/src/rules/interactive-supports-focus.js @@ -35,13 +35,9 @@ import getTabIndex from '../util/getTabIndex'; // ---------------------------------------------------------------------------- const schema = generateObjSchema({ - tabbable: enumArraySchema( - [...roles.keys()] - .filter(name => !roles.get(name).abstract) - .filter(name => roles.get(name).superClass.some( - klasses => includes(klasses, 'widget')), - ), - ), + tabbable: enumArraySchema([...roles.keys()] + .filter(name => !roles.get(name).abstract) + .filter(name => roles.get(name).superClass.some(klasses => includes(klasses, 'widget')))), }); const domElements = [...dom.keys()]; @@ -61,18 +57,14 @@ module.exports = { tabbable: Array } }) => ({ - JSXOpeningElement: ( - node: JSXOpeningElement, - ) => { + JSXOpeningElement: (node: JSXOpeningElement) => { const tabbable = ( context.options && context.options[0] && context.options[0].tabbable ) || []; - const attributes = node.attributes; + const { attributes } = node; const type = elementType(node); const hasInteractiveProps = hasAnyProp(attributes, interactiveProps); - const hasTabindex = getTabIndex( - getProp(attributes, 'tabIndex'), - ) !== undefined; + const hasTabindex = getTabIndex(getProp(attributes, 'tabIndex')) !== undefined; if (!includes(domElements, type)) { // Do not test higher level JSX components, as we do not know what diff --git a/src/rules/mouse-events-have-key-events.js b/src/rules/mouse-events-have-key-events.js index 6feaf2da7..1838c8449 100644 --- a/src/rules/mouse-events-have-key-events.js +++ b/src/rules/mouse-events-have-key-events.js @@ -24,7 +24,7 @@ module.exports = { create: context => ({ JSXOpeningElement: (node) => { - const attributes = node.attributes; + const { attributes } = node; // Check onmouseover / onfocus pairing. const onMouseOver = getProp(attributes, 'onMouseOver'); diff --git a/src/rules/no-interactive-element-to-noninteractive-role.js b/src/rules/no-interactive-element-to-noninteractive-role.js index dbf06d6e3..fac941add 100644 --- a/src/rules/no-interactive-element-to-noninteractive-role.js +++ b/src/rules/no-interactive-element-to-noninteractive-role.js @@ -47,17 +47,15 @@ module.exports = { }, create: (context: ESLintContext) => { - const options = context.options; + const { options } = context; return { - JSXAttribute: ( - attribute: ESLintJSXAttribute, - ) => { + JSXAttribute: (attribute: ESLintJSXAttribute) => { const attributeName: JSXIdentifier = propName(attribute); if (attributeName !== 'role') { return; } const node = attribute.parent; - const attributes = node.attributes; + const { attributes } = node; const type = elementType(node); const role = getLiteralPropValue(getProp(node.attributes, 'role')); diff --git a/src/rules/no-noninteractive-element-interactions.js b/src/rules/no-noninteractive-element-interactions.js index 0384bd4d4..79d2187c3 100644 --- a/src/rules/no-noninteractive-element-interactions.js +++ b/src/rules/no-noninteractive-element-interactions.js @@ -49,12 +49,10 @@ module.exports = { }, create: (context: ESLintContext) => { - const options = context.options; + const { options } = context; return { - JSXOpeningElement: ( - node: JSXOpeningElement, - ) => { - const attributes = node.attributes; + JSXOpeningElement: (node: JSXOpeningElement) => { + const { attributes } = node; const type = elementType(node); const interactiveProps = options[0] ? options[0].handlers diff --git a/src/rules/no-noninteractive-element-to-interactive-role.js b/src/rules/no-noninteractive-element-to-interactive-role.js index 27353041b..51705a0ab 100644 --- a/src/rules/no-noninteractive-element-to-interactive-role.js +++ b/src/rules/no-noninteractive-element-to-interactive-role.js @@ -48,17 +48,15 @@ module.exports = { }, create: (context: ESLintContext) => { - const options = context.options; + const { options } = context; return { - JSXAttribute: ( - attribute: ESLintJSXAttribute, - ) => { + JSXAttribute: (attribute: ESLintJSXAttribute) => { const attributeName: JSXIdentifier = propName(attribute); if (attributeName !== 'role') { return; } const node = attribute.parent; - const attributes = node.attributes; + const { attributes } = node; const type = elementType(node); const role = getLiteralPropValue(getProp(node.attributes, 'role')); diff --git a/src/rules/no-noninteractive-tabindex.js b/src/rules/no-noninteractive-tabindex.js index 7fb6e89ba..e975a0fe4 100644 --- a/src/rules/no-noninteractive-tabindex.js +++ b/src/rules/no-noninteractive-tabindex.js @@ -47,27 +47,23 @@ module.exports = { }, create: (context: ESLintContext) => { - const options = context.options; + const { options } = context; return { - JSXOpeningElement: ( - node: JSXOpeningElement, - ) => { + JSXOpeningElement: (node: JSXOpeningElement) => { const type = elementType(node); - const attributes = node.attributes; + const { attributes } = node; const tabIndexProp = getProp(attributes, 'tabIndex'); const tabIndex = getTabIndex(tabIndexProp); // Early return; if (typeof tabIndex === 'undefined') { return; } - const role = getLiteralPropValue( - getProp(node.attributes, 'role'), - ); + const role = getLiteralPropValue(getProp(node.attributes, 'role')); if (!dom.has(type)) { - // Do not test higher level JSX components, as we do not know what - // low-level DOM element this maps to. + // Do not test higher level JSX components, as we do not know what + // low-level DOM element this maps to. return; } // Allow for configuration overrides. diff --git a/src/rules/no-static-element-interactions.js b/src/rules/no-static-element-interactions.js index ae93af529..f5aab1bb1 100644 --- a/src/rules/no-static-element-interactions.js +++ b/src/rules/no-static-element-interactions.js @@ -50,12 +50,10 @@ module.exports = { }, create: (context: ESLintContext) => { - const options = context.options; + const { options } = context; return { - JSXOpeningElement: ( - node: JSXOpeningElement, - ) => { - const attributes = node.attributes; + JSXOpeningElement: (node: JSXOpeningElement) => { + const { attributes } = node; const type = elementType(node); const interactiveProps = options[0] ? options[0].handlers diff --git a/src/rules/tabindex-no-positive.js b/src/rules/tabindex-no-positive.js index 2f69e1087..fea52eb8f 100644 --- a/src/rules/tabindex-no-positive.js +++ b/src/rules/tabindex-no-positive.js @@ -32,6 +32,7 @@ module.exports = { // Only check literals because we can't infer values from certain expressions. const value = Number(getLiteralPropValue(attribute)); + // eslint-disable-next-line no-restricted-globals if (isNaN(value) || value <= 0) { return; } diff --git a/src/util/attributesComparator.js b/src/util/attributesComparator.js index 2329c4e6b..f95412cb2 100644 --- a/src/util/attributesComparator.js +++ b/src/util/attributesComparator.js @@ -16,28 +16,24 @@ function attributesComparator( baseAttributes: Array<{[key: string]: mixed}> = [], attributes: Array = [], ): boolean { - return baseAttributes.every( - (baseAttr): boolean => attributes.some( - (attribute): boolean => { - // Guard against non-JSXAttribute nodes like JSXSpreadAttribute - if (attribute.type !== 'JSXAttribute') { - return false; - } - // Attribute matches. - if (baseAttr.name !== propName(attribute)) { - return false; - } - // Value exists and does not match. - if ( - baseAttr.value + return baseAttributes.every((baseAttr): boolean => attributes.some((attribute): boolean => { + // Guard against non-JSXAttribute nodes like JSXSpreadAttribute + if (attribute.type !== 'JSXAttribute') { + return false; + } + // Attribute matches. + if (baseAttr.name !== propName(attribute)) { + return false; + } + // Value exists and does not match. + if ( + baseAttr.value && baseAttr.value !== getLiteralPropValue(attribute) - ) { - return false; - } - return true; - }, - ), - ); + ) { + return false; + } + return true; + })); } export default attributesComparator; diff --git a/src/util/hasAccessibleChild.js b/src/util/hasAccessibleChild.js index 3a57b0248..23196f106 100644 --- a/src/util/hasAccessibleChild.js +++ b/src/util/hasAccessibleChild.js @@ -12,7 +12,8 @@ export default function hasAccessibleChild(node: JSXElement): boolean { case 'JSXElement': return !isHiddenFromScreenReader( elementType(child.openingElement), - child.openingElement.attributes); + child.openingElement.attributes, + ); case 'JSXExpressionContainer': if (child.expression.type === 'Identifier') { return child.expression.name !== 'undefined'; diff --git a/src/util/isInteractiveElement.js b/src/util/isInteractiveElement.js index 33742222b..56a875996 100644 --- a/src/util/isInteractiveElement.js +++ b/src/util/isInteractiveElement.js @@ -18,36 +18,28 @@ const domKeys = [...dom.keys()]; const roleKeys = [...roles.keys()]; const elementRoleEntries = [...elementRoles]; -const nonInteractiveRoles = new Set( - roleKeys - .filter((name) => { - const role = roles.get(name); - return ( - !role.abstract - && !role.superClass.some( - classes => includes(classes, 'widget'), - ) - ); - }), -); +const nonInteractiveRoles = new Set(roleKeys + .filter((name) => { + const role = roles.get(name); + return ( + !role.abstract + && !role.superClass.some(classes => includes(classes, 'widget')) + ); + })); -const interactiveRoles = new Set( - [].concat( - roleKeys, - // 'toolbar' does not descend from widget, but it does support - // aria-activedescendant, thus in practice we treat it as a widget. - 'toolbar', - ) - .filter((name) => { - const role = roles.get(name); - return ( - !role.abstract - && role.superClass.some( - classes => includes(classes, 'widget'), - ) - ); - }), -); +const interactiveRoles = new Set([].concat( + roleKeys, + // 'toolbar' does not descend from widget, but it does support + // aria-activedescendant, thus in practice we treat it as a widget. + 'toolbar', +) + .filter((name) => { + const role = roles.get(name); + return ( + !role.abstract + && role.superClass.some(classes => includes(classes, 'widget')) + ); + })); const nonInteractiveElementRoleSchemas = elementRoleEntries @@ -58,9 +50,7 @@ const nonInteractiveElementRoleSchemas = elementRoleEntries roleSet, ], ) => { - if ([...roleSet].every( - (role): boolean => nonInteractiveRoles.has(role), - )) { + if ([...roleSet].every((role): boolean => nonInteractiveRoles.has(role))) { accumulator.push(elementSchema); } return accumulator; @@ -74,18 +64,14 @@ const interactiveElementRoleSchemas = elementRoleEntries roleSet, ], ) => { - if ([...roleSet].some( - (role): boolean => interactiveRoles.has(role), - )) { + if ([...roleSet].some((role): boolean => interactiveRoles.has(role))) { accumulator.push(elementSchema); } return accumulator; }, []); -const interactiveAXObjects = new Set( - [...AXObjects.keys()] - .filter(name => AXObjects.get(name).type === 'widget'), -); +const interactiveAXObjects = new Set([...AXObjects.keys()] + .filter(name => AXObjects.get(name).type === 'widget')); const interactiveElementAXObjectSchemas = [...elementAXObjects] .reduce(( @@ -95,9 +81,7 @@ const interactiveElementAXObjectSchemas = [...elementAXObjects] AXObjectSet, ], ) => { - if ([...AXObjectSet].every( - (role): boolean => interactiveAXObjects.has(role), - )) { + if ([...AXObjectSet].every((role): boolean => interactiveAXObjects.has(role))) { accumulator.push(elementSchema); } return accumulator; diff --git a/src/util/isInteractiveRole.js b/src/util/isInteractiveRole.js index c030e54bb..1e3e3fe77 100644 --- a/src/util/isInteractiveRole.js +++ b/src/util/isInteractiveRole.js @@ -9,9 +9,7 @@ import includes from 'array-includes'; const roles = [...rolesMap.keys()]; const interactiveRoles = roles .filter(name => !rolesMap.get(name).abstract) - .filter(name => rolesMap.get(name).superClass.some( - klasses => includes(klasses, 'widget')), - ); + .filter(name => rolesMap.get(name).superClass.some(klasses => includes(klasses, 'widget'))); // 'toolbar' does not descend from widget, but it does support // aria-activedescendant, thus in practice we treat it as a widget. diff --git a/src/util/isNonInteractiveElement.js b/src/util/isNonInteractiveElement.js index 6c781df4a..050240d0e 100644 --- a/src/util/isNonInteractiveElement.js +++ b/src/util/isNonInteractiveElement.js @@ -18,36 +18,28 @@ import attributesComparator from './attributesComparator'; const roleKeys = [...roles.keys()]; const elementRoleEntries = [...elementRoles]; -const nonInteractiveRoles = new Set( - roleKeys - .filter((name) => { - const role = roles.get(name); - return ( - !role.abstract - && !role.superClass.some( - classes => includes(classes, 'widget'), - ) - ); - }), -); +const nonInteractiveRoles = new Set(roleKeys + .filter((name) => { + const role = roles.get(name); + return ( + !role.abstract + && !role.superClass.some(classes => includes(classes, 'widget')) + ); + })); -const interactiveRoles = new Set( - [].concat( - roleKeys, - // 'toolbar' does not descend from widget, but it does support - // aria-activedescendant, thus in practice we treat it as a widget. - 'toolbar', - ) - .filter((name) => { - const role = roles.get(name); - return ( - !role.abstract - && role.superClass.some( - classes => includes(classes, 'widget'), - ) - ); - }), -); +const interactiveRoles = new Set([].concat( + roleKeys, + // 'toolbar' does not descend from widget, but it does support + // aria-activedescendant, thus in practice we treat it as a widget. + 'toolbar', +) + .filter((name) => { + const role = roles.get(name); + return ( + !role.abstract + && role.superClass.some(classes => includes(classes, 'widget')) + ); + })); const nonInteractiveElementRoleSchemas = elementRoleEntries .reduce(( @@ -57,9 +49,7 @@ const nonInteractiveElementRoleSchemas = elementRoleEntries roleSet, ], ) => { - if ([...roleSet].every( - (role): boolean => nonInteractiveRoles.has(role), - )) { + if ([...roleSet].every((role): boolean => nonInteractiveRoles.has(role))) { accumulator.push(elementSchema); } return accumulator; @@ -73,18 +63,14 @@ const interactiveElementRoleSchemas = elementRoleEntries roleSet, ], ) => { - if ([...roleSet].some( - (role): boolean => interactiveRoles.has(role), - )) { + if ([...roleSet].some((role): boolean => interactiveRoles.has(role))) { accumulator.push(elementSchema); } return accumulator; }, []); -const nonInteractiveAXObjects = new Set( - [...AXObjects.keys()] - .filter(name => includes(['window', 'structure'], AXObjects.get(name).type)), -); +const nonInteractiveAXObjects = new Set([...AXObjects.keys()] + .filter(name => includes(['window', 'structure'], AXObjects.get(name).type))); const nonInteractiveElementAXObjectSchemas = [...elementAXObjects] .reduce(( @@ -94,9 +80,7 @@ const nonInteractiveElementAXObjectSchemas = [...elementAXObjects] AXObjectSet, ], ) => { - if ([...AXObjectSet].every( - (role): boolean => nonInteractiveAXObjects.has(role), - )) { + if ([...AXObjectSet].every((role): boolean => nonInteractiveAXObjects.has(role))) { accumulator.push(elementSchema); } return accumulator; diff --git a/src/util/isNonInteractiveRole.js b/src/util/isNonInteractiveRole.js index 839655d3b..a78059e5a 100644 --- a/src/util/isNonInteractiveRole.js +++ b/src/util/isNonInteractiveRole.js @@ -13,9 +13,7 @@ import includes from 'array-includes'; const roles = [...rolesMap.keys()]; const nonInteractiveRoles = roles .filter(name => !rolesMap.get(name).abstract) - .filter(name => !rolesMap.get(name).superClass.some( - klasses => includes(klasses, 'widget')), - ); + .filter(name => !rolesMap.get(name).superClass.some(klasses => includes(klasses, 'widget'))); /** * Returns boolean indicating whether the given element has a role diff --git a/src/util/isPresentationRole.js b/src/util/isPresentationRole.js index 9e5ff7ce7..3192fbe51 100644 --- a/src/util/isPresentationRole.js +++ b/src/util/isPresentationRole.js @@ -5,8 +5,6 @@ const presentationRoles = new Set([ 'none', ]); -const isPresentationRole = (tagName, attributes) => presentationRoles.has( - getLiteralPropValue(getProp(attributes, 'role')), - ); +const isPresentationRole = (tagName, attributes) => presentationRoles.has(getLiteralPropValue(getProp(attributes, 'role'))); export default isPresentationRole;