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

feat: add jsx-a11y/iframe-has-title lint rule #437

Merged
merged 3 commits into from
May 16, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/@romejs/diagnostics/categories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ type LintDiagnosticCategory =
| 'lint/getterReturn'
| 'lint/importDefaultBasename'
| 'lint/inconsiderateLanguage'
| 'lint/jsxA11yIframeHasTitle'
| 'lint/jsxA11yHTMLHasLang'
| 'lint/jsxKey'
| 'lint/jsxNoCommentText'
Expand Down
4 changes: 4 additions & 0 deletions packages/@romejs/diagnostics/descriptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,10 @@ export const descriptions = createMessages({
category: 'lint/jsxNoCommentText',
message: 'Comments inside children should be placed in braces',
},
REACT_JSX_A11Y_IFRAME_HAS_TITLE: {
category: 'lint/jsxA11yIframeHasTitle',
message: markup`<emphasis>iframe</emphasis> elements should have a <emphasis>title prop</emphasis>.`,
sebmck marked this conversation as resolved.
Show resolved Hide resolved
},
REACT_JSX_KEY: (origin: string) => ({
category: 'lint/jsxKey',
message: markup`Missing the "key" prop for element in ${origin}`,
Expand Down
2 changes: 2 additions & 0 deletions packages/@romejs/js-compiler/lint/rules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import emptyMatches from './regular/emptyMatches';
import getterReturn from './regular/getterReturn';
import importDefaultBasename from './regular/importDefaultBasename';
import inconsiderateLanguage from './regular/inconsiderateLanguage';
import jsxA11YIframeHasTitle from './react/jsxA11yIframeHasTitle';
import jsxA11YHTMLHasLang from './react/jsxA11yHTMLHasLang';
import jsxKey from './react/jsxKey';
import jsxNoCommentText from './react/jsxNoCommentText';
Expand Down Expand Up @@ -76,6 +77,7 @@ export const lintTransforms = [
getterReturn,
importDefaultBasename,
inconsiderateLanguage,
jsxA11YIframeHasTitle,
jsxA11YHTMLHasLang,
jsxKey,
jsxNoCommentText,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
# `jsxA11yIframeHasTitle.test.ts`

**DO NOT MODIFY**. This file has been autogenerated. Run `rome test packages/@romejs/js-compiler/lint/rules/react/jsxA11yIframeHasTitle.test.ts --update-snapshots` to update.

## `require a title attribute on <iframe> JSX elements`

### `0`

```

unknown:1 lint/jsxA11yIframeHasTitle ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ iframe elements should have a title prop.

<iframe />
^^^^^^^^^^

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ Found 1 problem

```

### `0: formatted`

```
<iframe />;

```

### `1`

```

unknown:1 lint/jsxA11yIframeHasTitle ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ iframe elements should have a title prop.

<iframe {...props} />
^^^^^^^^^^^^^^^^^^^^^

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ Found 1 problem

```

### `10`

```
✔ No known problems!

```

### `10: formatted`

```
<iframe title={title}></iframe>;

```

### `1: formatted`

```
<iframe {...props} />;

```

### `2`

```

unknown:1 lint/jsxA11yIframeHasTitle ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ iframe elements should have a title prop.

<iframe title="" />
^^^^^^^^^^^^^^^^^^^

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ Found 1 problem

```

### `2: formatted`

```
<iframe title="" />;

```

### `3`

```

unknown:1 lint/jsxA11yIframeHasTitle ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ iframe elements should have a title prop.

<iframe title={""} />
^^^^^^^^^^^^^^^^^^^^^

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ Found 1 problem

```

### `3: formatted`

```
<iframe title={''} />;

```

### `4`

```

unknown:1 lint/jsxA11yIframeHasTitle ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ iframe elements should have a title prop.

<iframe title={``} />
^^^^^^^^^^^^^^^^^^^^^

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ Found 1 problem

```

### `4: formatted`

```
<iframe title={``} />;

```

### `5`

```

unknown:1 lint/jsxA11yIframeHasTitle ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ iframe elements should have a title prop.

<iframe title={undefined} />
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ Found 1 problem

```

### `5: formatted`

```
<iframe title={undefined} />;

```

### `6`

```

unknown:1 lint/jsxA11yIframeHasTitle ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ iframe elements should have a title prop.

<iframe title={false} />
^^^^^^^^^^^^^^^^^^^^^^^^

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ Found 1 problem

```

### `6: formatted`

```
<iframe title={false} />;

```

### `7`

```

unknown:1 lint/jsxA11yIframeHasTitle ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ iframe elements should have a title prop.

<iframe title={true} />
^^^^^^^^^^^^^^^^^^^^^^^

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ Found 1 problem

```

### `7: formatted`

```
<iframe title={true} />;

```

### `8`

```

unknown:1 lint/jsxA11yIframeHasTitle ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ iframe elements should have a title prop.

<iframe title={42} />
^^^^^^^^^^^^^^^^^^^^^

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ Found 1 problem

```

### `8: formatted`

```
<iframe title={42} />;

```

### `9`

```
✔ No known problems!

```

### `9: formatted`

```
<iframe title="title" />;

```
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import {test} from 'rome';

import {testLintMultiple} from '../testHelpers';

test(
'require a title attribute on <iframe> JSX elements',
async (t) => {
await testLintMultiple(
t,
[
// INVALID
'<iframe />',
'<iframe {...props} />',
'<iframe title="" />',
'<iframe title={""} />',
'<iframe title={``} />',
'<iframe title={undefined} />',
'<iframe title={false} />',
'<iframe title={true} />',
'<iframe title={42} />',
// VALID
'<iframe title="title" />',
'<iframe title={title} >',
],
{category: 'lint/jsxA11yIframeHasTitle'},
);
},
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import {descriptions} from '@romejs/diagnostics';
import {AnyNode} from '@romejs/js-ast';
import {Path} from '@romejs/js-compiler';

function jsxIframeMissingTitle(node: AnyNode) {
return (
node.type === 'JSXElement' &&
node.name.type === 'JSXIdentifier' &&
node.name.name === 'iframe' &&
!node.attributes.some((attribute) =>
attribute.type === 'JSXAttribute' &&
attribute.name.name === 'title' &&
attribute.value &&
((attribute.value.type === 'StringLiteral' &&
attribute.value.value.length > 0) ||
(attribute.value.type === 'JSXExpressionContainer' &&
((attribute.value.expression.type === 'ReferenceIdentifier' &&
attribute.value.expression.name !== 'undefined') ||
(attribute.value.expression.type === 'StringLiteral' &&
attribute.value.expression.value.length > 0))))
)
);
Comment on lines +14 to +29
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should abstract some of the attribute checking out into a util method since it seems to be a common pattern for JSX rules.

}

export default {
name: 'jsxA11yIframeHasTitle',

enter(path: Path): AnyNode {
const {node} = path;

if (jsxIframeMissingTitle(node)) {
path.context.addNodeDiagnostic(
node,
descriptions.LINT.REACT_JSX_A11Y_IFRAME_HAS_TITLE,
);
}

return node;
},
};