Skip to content

Commit

Permalink
Fix Flow warnings
Browse files Browse the repository at this point in the history
  • Loading branch information
jessebeach authored and ljharb committed Apr 6, 2021
1 parent ecec8e4 commit 426d4c2
Show file tree
Hide file tree
Showing 23 changed files with 144 additions and 79 deletions.
2 changes: 2 additions & 0 deletions .flowconfig
Expand Up @@ -2,3 +2,5 @@
<PROJECT_ROOT>/lib/.*
<PROJECT_ROOT>/docs/.*
<PROJECT_ROOT>/reports/.*
[options]
suppress_type=$FlowFixMe
11 changes: 10 additions & 1 deletion __mocks__/IdentifierMock.js
@@ -1,4 +1,13 @@
export default function IdentifierMock(ident) {
/**
* @flow
*/

export type IdentifierMockType = {|
type: 'Identifier',
name: string,
|};

export default function IdentifierMock(ident: string): IdentifierMockType {
return {
type: 'Identifier',
name: ident,
Expand Down
15 changes: 14 additions & 1 deletion __mocks__/JSXAttributeMock.js
@@ -1,7 +1,20 @@
/**
* @flow
*/

import toAST from 'to-ast'; // eslint-disable-line import/no-extraneous-dependencies
import JSXExpressionContainerMock from './JSXExpressionContainerMock';

export default function JSXAttributeMock(prop, value, isExpressionContainer = false) {
export type JSXAttributeMockType = {
type: 'JSXAttribute',
name: {
type: 'JSXIdentifier',
name: string,
},
value: mixed,
};

export default function JSXAttributeMock(prop: string, value: mixed, isExpressionContainer?: boolean = false): JSXAttributeMockType {
let astValue;
if (value && value.type !== undefined) {
astValue = value;
Expand Down
12 changes: 6 additions & 6 deletions __mocks__/JSXElementMock.js
Expand Up @@ -2,26 +2,26 @@
* @flow
*/

import JSXAttributeMock from './JSXAttributeMock';
import type { JSXAttributeMockType } from './JSXAttributeMock';

export type TJSXElementMock = {
export type JSXElementMockType = {
type: 'JSXElement',
openingElement: {
type: 'JSXOpeningElement',
name: {
type: 'JSXIdentifier',
name: string,
},
attributes: Array<JSXAttributeMock>,
attributes: Array<JSXAttributeMockType>,
},
children: Array<Node>,
};

export default function JSXElementMock(
tagName: string,
attributes: Array<JSXAttributeMock> = [],
children: Array<Node> = [],
): TJSXElementMock {
attributes: Array<JSXAttributeMockType> = [],
children?: Array<Node> = [],
): JSXElementMockType {
return {
type: 'JSXElement',
openingElement: {
Expand Down
11 changes: 10 additions & 1 deletion __mocks__/JSXExpressionContainerMock.js
@@ -1,4 +1,13 @@
export default function JSXExpressionContainerMock(exp) {
/**
* @flow
*/

export type JSXExpressionContainerMockType = {
type: 'JSXExpressionContainer',
expression: mixed,
}

export default function JSXExpressionContainerMock(exp: mixed): JSXExpressionContainerMockType {
return {
type: 'JSXExpressionContainer',
expression: exp,
Expand Down
8 changes: 7 additions & 1 deletion __mocks__/JSXSpreadAttributeMock.js
Expand Up @@ -3,8 +3,14 @@
*/

import IdentifierMock from './IdentifierMock';
import type { IdentifierMockType } from './IdentifierMock';

export default function JSXSpreadAttributeMock(identifier: string) {
export type JSXSpreadAttributeMockType = {
type: 'JSXSpreadAttribute',
argument: IdentifierMockType,
};

export default function JSXSpreadAttributeMock(identifier: string): JSXSpreadAttributeMockType {
return {
type: 'JSXSpreadAttribute',
argument: IdentifierMock(identifier),
Expand Down
9 changes: 8 additions & 1 deletion __mocks__/JSXTextMock.js
@@ -1,7 +1,14 @@
/**
* @flow
*/
export default function JSXTextMock(value: string) {

export type JSXTextMockType = {|
type: 'JSXText',
value: string,
raw: string,
|};

export default function JSXTextMock(value: string): JSXTextMockType {
return {
type: 'JSXText',
value,
Expand Down
9 changes: 8 additions & 1 deletion __mocks__/LiteralMock.js
@@ -1,7 +1,14 @@
/**
* @flow
*/
export default function LiteralMock(value: string) {

export type LiteralMockType = {|
type: 'Literal',
value: string,
raw: string,
|};

export default function LiteralMock(value: string): LiteralMockType {
return {
type: 'Literal',
value,
Expand Down
27 changes: 14 additions & 13 deletions __mocks__/genInteractives.js
Expand Up @@ -7,7 +7,8 @@ import includes from 'array-includes';
import JSXAttributeMock from './JSXAttributeMock';
import JSXElementMock from './JSXElementMock';

import type { TJSXElementMock } from './JSXElementMock';
import type { JSXElementMockType } from './JSXElementMock';
import type { JSXAttributeMockType } from './JSXAttributeMock';

const domElements = [...dom.keys()];
const roleNames = [...roles.keys()];
Expand Down Expand Up @@ -147,7 +148,7 @@ const nonInteractiveRoles = roleNames
// aria-activedescendant, thus in practice we treat it as a widget.
.filter((role) => !includes(['toolbar'], role));

export function genElementSymbol(openingElement: Object) {
export function genElementSymbol(openingElement: Object): string {
return (
openingElement.name.name + (openingElement.attributes.length > 0
? `${openingElement.attributes
Expand All @@ -158,8 +159,8 @@ export function genElementSymbol(openingElement: Object) {
);
}

export function genInteractiveElements(): Array<TJSXElementMock> {
return Object.keys(interactiveElementsMap).map((elementSymbol: string): TJSXElementMock => {
export function genInteractiveElements(): Array<JSXElementMockType> {
return Object.keys(interactiveElementsMap).map((elementSymbol: string): JSXElementMockType => {
const bracketIndex = elementSymbol.indexOf('[');
let name = elementSymbol;
if (bracketIndex > -1) {
Expand All @@ -170,15 +171,15 @@ export function genInteractiveElements(): Array<TJSXElementMock> {
});
}

export function genInteractiveRoleElements(): Array<TJSXElementMock> {
return [...interactiveRoles, 'button article', 'fakerole button article'].map((value): TJSXElementMock => JSXElementMock(
export function genInteractiveRoleElements(): Array<JSXElementMockType> {
return [...interactiveRoles, 'button article', 'fakerole button article'].map((value): JSXElementMockType => JSXElementMock(
'div',
[JSXAttributeMock('role', value)],
));
}

export function genNonInteractiveElements(): Array<TJSXElementMock> {
return Object.keys(nonInteractiveElementsMap).map((elementSymbol): TJSXElementMock => {
export function genNonInteractiveElements(): Array<JSXElementMockType> {
return Object.keys(nonInteractiveElementsMap).map((elementSymbol): JSXElementMockType => {
const bracketIndex = elementSymbol.indexOf('[');
let name = elementSymbol;
if (bracketIndex > -1) {
Expand All @@ -189,25 +190,25 @@ export function genNonInteractiveElements(): Array<TJSXElementMock> {
});
}

export function genNonInteractiveRoleElements() {
export function genNonInteractiveRoleElements(): Array<JSXElementMockType> {
return [
...nonInteractiveRoles,
'article button',
'fakerole article button',
].map((value) => JSXElementMock('div', [JSXAttributeMock('role', value)]));
}

export function genAbstractRoleElements() {
export function genAbstractRoleElements(): Array<JSXElementMockType> {
return abstractRoles.map((value) => JSXElementMock('div', [JSXAttributeMock('role', value)]));
}

export function genNonAbstractRoleElements() {
export function genNonAbstractRoleElements(): Array<JSXElementMockType> {
return nonAbstractRoles.map((value) => JSXElementMock('div', [JSXAttributeMock('role', value)]));
}

export function genIndeterminantInteractiveElements(): Array<TJSXElementMock> {
export function genIndeterminantInteractiveElements(): Array<JSXElementMockType> {
return Object.keys(indeterminantInteractiveElementsMap).map((name) => {
const attributes = indeterminantInteractiveElementsMap[name].map(({ prop, value }): TJSXElementMock => JSXAttributeMock(prop, value));
const attributes = indeterminantInteractiveElementsMap[name].map(({ prop, value }): JSXAttributeMockType => JSXAttributeMock(prop, value));
return JSXElementMock(name, attributes);
});
}
6 changes: 5 additions & 1 deletion __tests__/__util__/ruleOptionsMapperFactory.js
Expand Up @@ -9,7 +9,11 @@ type ESLintTestRunnerTestCase = {
parserOptions: ?Array<mixed>
};

export default function ruleOptionsMapperFactory(ruleOptions: Array<mixed> = []) {
type RuleOptionsMapperFactoryType = (
params: ESLintTestRunnerTestCase
) => ESLintTestRunnerTestCase;

export default function ruleOptionsMapperFactory(ruleOptions: Array<mixed> = []): RuleOptionsMapperFactoryType {
// eslint-disable-next-line
return ({ code, errors, options, parserOptions }: ESLintTestRunnerTestCase): ESLintTestRunnerTestCase => {
return {
Expand Down
9 changes: 9 additions & 0 deletions flow/eslint.js
Expand Up @@ -10,3 +10,12 @@ export type ESLintContext = {
options: Array<Object>,
report: (ESLintReport) => void,
};

export type ESLintConfig = {
meta?: {[string]: mixed},
create: (context: ESLintContext) => mixed,
}

export type ESLintVisitorSelectorConfig = {
[string]: mixed,
};
10 changes: 5 additions & 5 deletions src/rules/anchor-is-valid.js
Expand Up @@ -10,7 +10,7 @@

import { elementType, getProp, getPropValue } from 'jsx-ast-utils';
import type { JSXOpeningElement } from 'ast-types-flow';
import type { ESLintContext } from '../../flow/eslint';
import type { ESLintConfig, ESLintContext, ESLintVisitorSelectorConfig } from '../../flow/eslint';
import { generateObjSchema, arraySchema, enumArraySchema } from '../util/schemas';

const allAspects = ['noHref', 'invalidHref', 'preferButton'];
Expand All @@ -27,16 +27,16 @@ const schema = generateObjSchema({
aspects: enumArraySchema(allAspects, 1),
});

module.exports = {
module.exports = ({
meta: {
docs: {
url: 'https://github.com/evcohen/eslint-plugin-jsx-a11y/tree/master/docs/rules/anchor-is-valid.md',
},
schema: [schema],
},

create: (context: ESLintContext) => ({
JSXOpeningElement: (node: JSXOpeningElement) => {
create: (context: ESLintContext): ESLintVisitorSelectorConfig => ({
JSXOpeningElement: (node: JSXOpeningElement): void => {
const { attributes } = node;
const options = context.options[0] || {};
const componentOptions = options.components || [];
Expand Down Expand Up @@ -115,4 +115,4 @@ module.exports = {
}
},
}),
};
}: ESLintConfig);
10 changes: 5 additions & 5 deletions src/rules/control-has-associated-label.js
Expand Up @@ -13,7 +13,7 @@ import { elementType, getProp, getLiteralPropValue } from 'jsx-ast-utils';
import type { JSXElement } from 'ast-types-flow';
import includes from 'array-includes';
import { generateObjSchema, arraySchema } from '../util/schemas';
import type { ESLintContext } from '../../flow/eslint';
import type { ESLintConfig, ESLintContext, ESLintVisitorSelectorConfig } from '../../flow/eslint';
import isDOMElement from '../util/isDOMElement';
import isHiddenFromScreenReader from '../util/isHiddenFromScreenReader';
import isInteractiveElement from '../util/isInteractiveElement';
Expand All @@ -36,13 +36,13 @@ const schema = generateObjSchema({
},
});

module.exports = {
module.exports = ({
meta: {
docs: {},
schema: [schema],
},

create: (context: ESLintContext) => {
create: (context: ESLintContext): ESLintVisitorSelectorConfig => {
const options = context.options[0] || {};
const {
labelAttributes = [],
Expand All @@ -53,7 +53,7 @@ module.exports = {

const newIgnoreElements = new Set([...ignoreElements, ...ignoreList]);

const rule = (node: JSXElement) => {
const rule = (node: JSXElement): void => {
const tag = elementType(node.openingElement);
const role = getLiteralPropValue(getProp(node.openingElement.attributes, 'role'));
// Ignore interactive elements that might get their label from a source
Expand Down Expand Up @@ -112,4 +112,4 @@ module.exports = {
JSXElement: rule,
};
},
};
}: ESLintConfig);
12 changes: 4 additions & 8 deletions src/rules/interactive-supports-focus.js
Expand Up @@ -17,7 +17,7 @@ import {
} from 'jsx-ast-utils';
import type { JSXOpeningElement } from 'ast-types-flow';
import includes from 'array-includes';
import type { ESLintContext } from '../../flow/eslint';
import type { ESLintConfig, ESLintContext, ESLintVisitorSelectorConfig } from '../../flow/eslint';
import {
enumArraySchema,
generateObjSchema,
Expand Down Expand Up @@ -47,19 +47,15 @@ const interactiveProps = [
...eventHandlersByType.keyboard,
];

module.exports = {
module.exports = ({
meta: {
docs: {
url: 'https://github.com/evcohen/eslint-plugin-jsx-a11y/tree/master/docs/rules/interactive-supports-focus.md',
},
schema: [schema],
},

create: (context: ESLintContext & {
options: {
tabbable: Array<string>
}
}) => ({
create: (context: ESLintContext): ESLintVisitorSelectorConfig => ({
JSXOpeningElement: (node: JSXOpeningElement) => {
const tabbable = (
context.options && context.options[0] && context.options[0].tabbable
Expand Down Expand Up @@ -111,4 +107,4 @@ module.exports = {
}
},
}),
};
}: ESLintConfig);
8 changes: 4 additions & 4 deletions src/rules/label-has-associated-control.js
Expand Up @@ -12,7 +12,7 @@
import { getProp, getPropValue, elementType } from 'jsx-ast-utils';
import type { JSXElement } from 'ast-types-flow';
import { generateObjSchema, arraySchema } from '../util/schemas';
import type { ESLintContext } from '../../flow/eslint';
import type { ESLintConfig, ESLintContext, ESLintVisitorSelectorConfig } from '../../flow/eslint';
import mayContainChildComponent from '../util/mayContainChildComponent';
import mayHaveAccessibleLabel from '../util/mayHaveAccessibleLabel';

Expand Down Expand Up @@ -41,13 +41,13 @@ const validateId = (node) => {
return htmlForAttr !== false && !!htmlForValue;
};

module.exports = {
module.exports = ({
meta: {
docs: {},
schema: [schema],
},

create: (context: ESLintContext) => {
create: (context: ESLintContext): ESLintVisitorSelectorConfig => {
const options = context.options[0] || {};
const labelComponents = options.labelComponents || [];
const assertType = options.assert || 'either';
Expand Down Expand Up @@ -122,4 +122,4 @@ module.exports = {
JSXElement: rule,
};
},
};
}: ESLintConfig);

0 comments on commit 426d4c2

Please sign in to comment.