Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Flow warnings #785

Merged
merged 1 commit into from Apr 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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);