eslint-plugin-smarthr 0.3.14 → 0.3.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/libs/format_styled_components.js +33 -18
- package/package.json +1 -1
- package/rules/a11y-delegate-element-has-role-presentation/README.md +55 -0
- package/rules/a11y-delegate-element-has-role-presentation/index.js +135 -0
- package/rules/a11y-input-has-name-attribute/README.md +2 -2
- package/rules/a11y-input-has-name-attribute/index.js +1 -0
- package/test/a11y-anchor-has-href-attribute.js +4 -0
- package/test/a11y-clickable-element-has-text.js +12 -0
- package/test/a11y-delegate-element-has-role-presantation.js +70 -0
- package/test/a11y-heading-in-sectioning-content.js +14 -0
- package/test/a11y-image-has-alt-attribute.js +6 -0
- package/test/a11y-input-has-name-attribute.js +18 -0
- package/test/a11y-prohhibit-input-placeholder.js +10 -0
- package/test/a11y-trigger-has-button.js +12 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [0.3.16](https://github.com/kufu/eslint-plugin-smarthr/compare/v0.3.15...v0.3.16) (2023-12-30)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* a11y-delegate-element-has-role-presantation を追加 ([#92](https://github.com/kufu/eslint-plugin-smarthr/issues/92)) ([c211ffb](https://github.com/kufu/eslint-plugin-smarthr/commit/c211ffb7e698d010ca639d0bdda9ea82cb31033a))
|
|
11
|
+
|
|
12
|
+
### [0.3.15](https://github.com/kufu/eslint-plugin-smarthr/compare/v0.3.14...v0.3.15) (2023-11-29)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* a11y系ruleに "import時のasでのrename内容をチェックする" 処理を追加 ([#90](https://github.com/kufu/eslint-plugin-smarthr/issues/90)) ([2eab779](https://github.com/kufu/eslint-plugin-smarthr/commit/2eab77960985e7c52bd262ff674ae31cb2c6008e))
|
|
18
|
+
|
|
5
19
|
### [0.3.14](https://github.com/kufu/eslint-plugin-smarthr/compare/v0.3.13...v0.3.14) (2023-11-05)
|
|
6
20
|
|
|
7
21
|
|
|
@@ -3,6 +3,21 @@ const STYLED_COMPONENTS = `${STYLED_COMPONENTS_METHOD}-components`
|
|
|
3
3
|
|
|
4
4
|
const findInvalidImportNameNode = (s) => s.type === 'ImportDefaultSpecifier' && s.local.name !== STYLED_COMPONENTS_METHOD
|
|
5
5
|
|
|
6
|
+
const checkImportStyledComponents = (node, context) => {
|
|
7
|
+
if (node.source.value !== STYLED_COMPONENTS) {
|
|
8
|
+
return
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const invalidNameNode = node.specifiers.find(findInvalidImportNameNode)
|
|
12
|
+
|
|
13
|
+
if (invalidNameNode) {
|
|
14
|
+
context.report({
|
|
15
|
+
node: invalidNameNode,
|
|
16
|
+
message: `${STYLED_COMPONENTS} をimportする際は、名称が"${STYLED_COMPONENTS_METHOD}" となるようにしてください。例: "import ${STYLED_COMPONENTS_METHOD} from '${STYLED_COMPONENTS}'"`,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
6
21
|
const generateTagFormatter = ({ context, EXPECTED_NAMES, UNEXPECTED_NAMES }) => {
|
|
7
22
|
const entriesesTagNames = Object.entries(EXPECTED_NAMES).map(([b, e]) => [ new RegExp(b), new RegExp(e) ])
|
|
8
23
|
const entriesesUnTagNames = UNEXPECTED_NAMES ? Object.entries(UNEXPECTED_NAMES).map(([b, e]) => {
|
|
@@ -11,20 +26,27 @@ const generateTagFormatter = ({ context, EXPECTED_NAMES, UNEXPECTED_NAMES }) =>
|
|
|
11
26
|
return [ new RegExp(b), new RegExp(auctualE), messageTemplate ]
|
|
12
27
|
}) : []
|
|
13
28
|
|
|
14
|
-
return {
|
|
15
|
-
ImportDeclaration: (node) => {
|
|
16
|
-
if (node.source.value !== STYLED_COMPONENTS) {
|
|
17
|
-
return
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const invalidNameNode = node.specifiers.find(findInvalidImportNameNode)
|
|
21
29
|
|
|
22
|
-
|
|
30
|
+
const checkImportedNameToLocalName = (node, base, extended) => {
|
|
31
|
+
entriesesTagNames.forEach(([b, e]) => {
|
|
32
|
+
if (base.match(b) && !extended.match(e)) {
|
|
23
33
|
context.report({
|
|
24
|
-
node
|
|
25
|
-
message: `${
|
|
34
|
+
node,
|
|
35
|
+
message: `${extended}を正規表現 "${e.toString()}" がmatchする名称に変更してください`,
|
|
26
36
|
});
|
|
27
37
|
}
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
ImportDeclaration: (node) => {
|
|
43
|
+
checkImportStyledComponents(node, context)
|
|
44
|
+
|
|
45
|
+
node.specifiers.forEach((s) => {
|
|
46
|
+
if (s.imported && s.imported.name !== s.local.name) {
|
|
47
|
+
checkImportedNameToLocalName(node, s.imported.name, s.local.name)
|
|
48
|
+
}
|
|
49
|
+
})
|
|
28
50
|
},
|
|
29
51
|
VariableDeclarator: (node) => {
|
|
30
52
|
if (!node.init) {
|
|
@@ -64,14 +86,7 @@ const generateTagFormatter = ({ context, EXPECTED_NAMES, UNEXPECTED_NAMES }) =>
|
|
|
64
86
|
if (base) {
|
|
65
87
|
const extended = node.id.name
|
|
66
88
|
|
|
67
|
-
|
|
68
|
-
if (base.match(b) && !extended.match(e)) {
|
|
69
|
-
context.report({
|
|
70
|
-
node,
|
|
71
|
-
message: `${extended}を正規表現 "${e.toString()}" がmatchする名称に変更してください`,
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
})
|
|
89
|
+
checkImportedNameToLocalName(node, base, extended)
|
|
75
90
|
|
|
76
91
|
entriesesUnTagNames.forEach(([b, e, m]) => {
|
|
77
92
|
const matcher = extended.match(e)
|
package/package.json
CHANGED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# smarthr/a11y-delegate-element-has-role-presantation
|
|
2
|
+
|
|
3
|
+
- 'role="presantation"'を適切に設定することを促すルールです
|
|
4
|
+
- インタラクティブな要素に対して'role="presantation"'が設定されている場合、エラーになります
|
|
5
|
+
- インタラクティブな要素とは form, inputなどの入力要素、button, a などのクリッカブルな要素を指します
|
|
6
|
+
- インタラクティブな要素から発生するイベントを親要素でキャッチする場合、親要素に 'role="presantation"' を設定することを促します
|
|
7
|
+
- インタラクティブではない要素でイベントをキャッチしており、かつ'role="presantation"'を設定しているにも関わらず、子要素にインタラクティブな要素がない場合はエラーになります
|
|
8
|
+
- additionalInteractiveComponentRegexオプションに独自コンポーネントの名称を正規表現で設定することで、インタラクティブな要素として判定することが可能です
|
|
9
|
+
|
|
10
|
+
## rules
|
|
11
|
+
|
|
12
|
+
```js
|
|
13
|
+
{
|
|
14
|
+
rules: {
|
|
15
|
+
'smarthr/a11y-delegate-element-has-role-presantation': [
|
|
16
|
+
'error', // 'warn', 'off'
|
|
17
|
+
// { additionalInteractiveComponentRegex: ['^InteractiveComponent%'] }
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## ❌ Incorrect
|
|
24
|
+
|
|
25
|
+
```jsx
|
|
26
|
+
// インタラクティブな要素に対して role="presantation" は設定できない
|
|
27
|
+
<Button role="presantation">text.</Button>
|
|
28
|
+
<input type="text" role="presantation" />
|
|
29
|
+
|
|
30
|
+
// インタラクティブな要素で発生するイベントを非インタラクティブな要素でキャッチする場合
|
|
31
|
+
// role="presantation" を設定する必要がある
|
|
32
|
+
<div onClick={hoge}>
|
|
33
|
+
<Button>text.</Button>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
// 非インタラクティブな要素でイベントをキャッチする場合、
|
|
37
|
+
// 子要素にインタラクティブな要素がない場合はエラー
|
|
38
|
+
<div onClick={hoge} role="presentation">
|
|
39
|
+
<Text>hoge.</Text>
|
|
40
|
+
</div>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## ✅ Correct
|
|
44
|
+
|
|
45
|
+
```jsx
|
|
46
|
+
// インタラクティブな要素で発生するイベントを非インタラクティブな要素でキャッチする場合
|
|
47
|
+
// role="presantation" を設定する
|
|
48
|
+
<div onClick={hoge} role="presentation">
|
|
49
|
+
<Button>text.</Button>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<div onClick={hoge} role="presentation">
|
|
53
|
+
<AnyForm />
|
|
54
|
+
</div>
|
|
55
|
+
```
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
const { generateTagFormatter } = require('../../libs/format_styled_components');
|
|
2
|
+
|
|
3
|
+
const EXPECTED_NAMES = {
|
|
4
|
+
'(i|I)nput$': 'Input$',
|
|
5
|
+
'(t|T)extarea$': 'Textarea$',
|
|
6
|
+
'(s|S)elect$': 'Select$',
|
|
7
|
+
'InputFile$': 'InputFile$',
|
|
8
|
+
'RadioButtonPanel$': 'RadioButtonPanel$',
|
|
9
|
+
'Check(b|B)ox$': 'CheckBox$',
|
|
10
|
+
'Combo(b|B)ox$': 'ComboBox$',
|
|
11
|
+
'DatePicker$': 'DatePicker$',
|
|
12
|
+
'DropZone$': 'DropZone$',
|
|
13
|
+
'FieldSet$': 'FieldSet$',
|
|
14
|
+
'(b|B)utton$': 'Button$',
|
|
15
|
+
'Anchor$': 'Anchor$',
|
|
16
|
+
'Link$': 'Link$',
|
|
17
|
+
'TabItem$': 'TabItem$',
|
|
18
|
+
'^a$': '(Anchor|Link)$',
|
|
19
|
+
|
|
20
|
+
'(f|F)orm$': 'Form$',
|
|
21
|
+
'ActionDialogWithTrigger$': 'ActionDialogWithTrigger$',
|
|
22
|
+
'RemoteDialogTrigger$': 'RemoteDialogTrigger$',
|
|
23
|
+
'RemoteTrigger(.+)Dialog$': 'RemoteTrigger(.+)Dialog$',
|
|
24
|
+
'Pagination$': 'Pagination$',
|
|
25
|
+
'SideNav$': 'SideNav$',
|
|
26
|
+
'AccordionPanel$': 'AccordionPanel$',
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const UNEXPECTED_NAMES = {
|
|
30
|
+
'(B|^b)utton$': '(Button)$',
|
|
31
|
+
'(Anchor|^a)$': '(Anchor)$',
|
|
32
|
+
'(Link|^a)$': '(Link)$',
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const INTERACTIVE_COMPONENT_NAMES = Object.values(EXPECTED_NAMES)
|
|
36
|
+
const INTERACTIVE_ON_REGEX = /^on(Change|Input|Focus|Blur|(Double)?Click|Key(Down|Up|Press)|Mouse(Enter|Over|Down|Up|Leave)|Select|Submit)$/
|
|
37
|
+
|
|
38
|
+
const messageNonInteractiveEventHandler = (nodeName, interactiveComponentRegex, onAttrs) => {
|
|
39
|
+
const onAttrsText = onAttrs.join(', ')
|
|
40
|
+
|
|
41
|
+
return `${nodeName} に${onAttrsText}を設定するとブラウザが正しく解釈が行えず、ユーザーが利用することが出来ない場合があるため、以下のいずれかの対応をおこなってください。
|
|
42
|
+
- 方法1: ${nodeName}がinput、buttonやaなどのインタラクティブな要素の場合、コンポーネント名の末尾をインタラクティブなコンポーネントであることがわかる名称に変更してください
|
|
43
|
+
- "${interactiveComponentRegex}" の正規表現にmatchする名称に変更してください
|
|
44
|
+
- 方法2: インタラクティブな親要素、もしくは子要素が存在する場合、直接${onAttrsText}を設定することを検討してください
|
|
45
|
+
- 方法3: インタラクティブな親要素、もしくは子要素が存在しない場合、インタラクティブな要素を必ず持つようにマークアップを修正後、${onAttrsText}の設定要素を検討してください
|
|
46
|
+
- 方法4: インタラクティブな子要素から発生したイベントをキャッチすることが目的で${onAttrsText}を設定している場合、'role="presentation"' を設定してください`
|
|
47
|
+
}
|
|
48
|
+
const messageRolePresentationNotHasInteractive = (nodeName, interactiveComponentRegex, onAttrs) => `${nodeName}に 'role="presentation"' が設定されているにも関わらず、子要素にinput、buttonやaなどのインタラクティブな要素が見つからないため、ブラウザが正しく解釈が行えず、ユーザーが利用することが出来ない場合があるため、以下のいずれかの対応をおこなってください。
|
|
49
|
+
- 方法1: 子要素にインタラクティブな要素が存在するにも関わらずこのエラーが表示されている場合、子要素の名称を変更してください
|
|
50
|
+
- "${interactiveComponentRegex}" の正規表現にmatchするよう、インタラクティブな子要素全ての名称を変更してください
|
|
51
|
+
- 方法2: ${nodeName}自体がインタラクティブな要素の場合、'role="presentation"'を削除した上で名称を変更してください
|
|
52
|
+
- "${interactiveComponentRegex}" の正規表現にmatchするよう、${nodeName}の名称を変更してください
|
|
53
|
+
- 方法3: 子要素にインタラクティブな要素が存在し、${onAttrs.join(', ')}全属性をそれらの要素に移動させられる場合、'role="presentation"'を消した上で実施してください`
|
|
54
|
+
const messageInteractiveHasRolePresentation = (nodeName, interactiveComponentRegex) => `${nodeName}はinput、buttonやaなどのインタラクティブな要素にもかかわらず 'role="presentation"' が設定されているため、ブラウザが正しく解釈が行えず、ユーザーが利用することが出来ない場合があるため、以下のいずれかの対応をおこなってください。
|
|
55
|
+
- 方法1: 'role="presentation"' を削除してください
|
|
56
|
+
- 方法2: ${nodeName}の名称を "${interactiveComponentRegex}" とマッチしない名称に変更してください`
|
|
57
|
+
|
|
58
|
+
const SCHEMA = [
|
|
59
|
+
{
|
|
60
|
+
type: 'object',
|
|
61
|
+
properties: {
|
|
62
|
+
additionalInteractiveComponentRegex: { type: 'array', items: { type: 'string' } },
|
|
63
|
+
},
|
|
64
|
+
additionalProperties: false,
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
module.exports = {
|
|
69
|
+
meta: {
|
|
70
|
+
type: 'problem',
|
|
71
|
+
schema: SCHEMA,
|
|
72
|
+
},
|
|
73
|
+
create(context) {
|
|
74
|
+
const options = context.options[0]
|
|
75
|
+
const interactiveComponentRegex = new RegExp(`(${INTERACTIVE_COMPONENT_NAMES.join('|')}${options?.additionalInteractiveComponentRegex ? `|${options.additionalInteractiveComponentRegex.join('|')}` : ''})`)
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
...generateTagFormatter({ context, EXPECTED_NAMES, UNEXPECTED_NAMES }),
|
|
79
|
+
JSXOpeningElement: (node) => {
|
|
80
|
+
const nodeName = node.name.name || '';
|
|
81
|
+
|
|
82
|
+
let onAttrs = []
|
|
83
|
+
let isRolePresentation = false
|
|
84
|
+
|
|
85
|
+
node.attributes.forEach((a) => {
|
|
86
|
+
const aName = a.name?.name || ''
|
|
87
|
+
|
|
88
|
+
if (aName.match(INTERACTIVE_ON_REGEX)) {
|
|
89
|
+
onAttrs.push(aName)
|
|
90
|
+
} else if (aName === 'role' && a.value?.value === 'presentation') {
|
|
91
|
+
isRolePresentation = true
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
if (!nodeName.match(interactiveComponentRegex)) {
|
|
96
|
+
if (onAttrs.length > 0) {
|
|
97
|
+
if (!isRolePresentation) {
|
|
98
|
+
context.report({
|
|
99
|
+
node,
|
|
100
|
+
message: messageNonInteractiveEventHandler(nodeName, interactiveComponentRegex, onAttrs),
|
|
101
|
+
});
|
|
102
|
+
} else {
|
|
103
|
+
const isHasInteractive = (c) => {
|
|
104
|
+
if (c.type === 'JSXElement') {
|
|
105
|
+
if ((c.openingElement.name.name || '').match(interactiveComponentRegex)) {
|
|
106
|
+
return true
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (c.children.length > 0) {
|
|
110
|
+
return c.children.find(isHasInteractive)
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return false
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (!node.parent.children.find(isHasInteractive)) {
|
|
118
|
+
context.report({
|
|
119
|
+
node,
|
|
120
|
+
message: messageRolePresentationNotHasInteractive(nodeName, interactiveComponentRegex, onAttrs)
|
|
121
|
+
})
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
} else if (isRolePresentation) {
|
|
126
|
+
context.report({
|
|
127
|
+
node,
|
|
128
|
+
message: messageInteractiveHasRolePresentation(nodeName, interactiveComponentRegex)
|
|
129
|
+
})
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
module.exports.schema = SCHEMA;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# smarthr/a11y-input-has-name-attribute
|
|
2
2
|
|
|
3
|
-
- input, textarea, select
|
|
4
|
-
-
|
|
3
|
+
- input, textarea, select など入力要素に name 属性を設定することを強制するルールです。
|
|
4
|
+
- 入力要素は name を設定することでブラウザの補完機能が有効になる可能性が高まります。
|
|
5
5
|
- 補完機能はブラウザによって異なるため、補完される可能性が上がるよう、name には半角英数の小文字・大文字と一部記号(`_ , [, ]`)のみ利用可能です。
|
|
6
6
|
- input[type="radio"] は name を適切に設定することでラジオグループが確立され、キーボード操作しやすくなる等のメリットがあります。
|
|
7
7
|
- checkTypeオプションに 'smart' を指定することで spread attributeが設定されている場合はcorrectに出来ます。
|
|
@@ -25,6 +25,8 @@ ruleTester.run('a11y-anchor-has-href-attribute', rule, {
|
|
|
25
25
|
{ code: `import styled from 'styled-components'` },
|
|
26
26
|
{ code: `import styled, { css } from 'styled-components'` },
|
|
27
27
|
{ code: `import { css } from 'styled-components'` },
|
|
28
|
+
{ code: `import { HogeAnchor as FugaAnchor } from './hoge'` },
|
|
29
|
+
{ code: `import { Link as FugaLink } from './hoge'` },
|
|
28
30
|
{ code: 'const HogeAnchor = styled.a``' },
|
|
29
31
|
{ code: 'const HogeLink = styled.a``' },
|
|
30
32
|
{ code: 'const HogeAnchor = styled(Anchor)``' },
|
|
@@ -39,6 +41,8 @@ ruleTester.run('a11y-anchor-has-href-attribute', rule, {
|
|
|
39
41
|
],
|
|
40
42
|
invalid: [
|
|
41
43
|
{ code: `import hoge from 'styled-components'`, errors: [ { message: `styled-components をimportする際は、名称が"styled" となるようにしてください。例: "import styled from 'styled-components'"` } ] },
|
|
44
|
+
{ code: `import { Anchor as AnchorHoge } from './hoge'`, errors: [ { message: `AnchorHogeを正規表現 "/Anchor$/" がmatchする名称に変更してください` } ] },
|
|
45
|
+
{ code: `import { HogeLink as HogeLinkFuga } from './hoge'`, errors: [ { message: `HogeLinkFugaを正規表現 "/Link$/" がmatchする名称に変更してください` } ] },
|
|
42
46
|
{ code: 'const Hoge = styled.a``', errors: [ { message: `Hogeを正規表現 "/(Anchor|Link)$/" がmatchする名称に変更してください` } ] },
|
|
43
47
|
{ code: 'const Hoge = styled(Anchor)``', errors: [ { message: `Hogeを正規表現 "/Anchor$/" がmatchする名称に変更してください` } ] },
|
|
44
48
|
{ code: 'const Hoge = styled(Link)``', errors: [ { message: `Hogeを正規表現 "/Link$/" がmatchする名称に変更してください` } ] },
|
|
@@ -22,6 +22,12 @@ ruleTester.run('a11y-clickable-element-has-text', rule, {
|
|
|
22
22
|
{ code: `import styled from 'styled-components'` },
|
|
23
23
|
{ code: `import styled, { css } from 'styled-components'` },
|
|
24
24
|
{ code: `import { css } from 'styled-components'` },
|
|
25
|
+
{ code: `import { SmartHRLogo as HogeSmartHRLogo } from './hoge'` },
|
|
26
|
+
{ code: `import { AbcButton as StyledAbcButton } from './hoge'` },
|
|
27
|
+
{ code: `import { HogeAnchor as FugaAnchor } from './hoge'` },
|
|
28
|
+
{ code: `import { Link as FugaLink } from './hoge'` },
|
|
29
|
+
{ code: `import { FugaText as HogeFugaText } from './hoge'` },
|
|
30
|
+
{ code: `import { FugaMessage as HogeFugaMessage } from './hoge'` },
|
|
25
31
|
{ code: 'const HogeAnchor = styled.a``' },
|
|
26
32
|
{ code: 'const HogeLink = styled.a``' },
|
|
27
33
|
{ code: 'const HogeButton = styled.button``' },
|
|
@@ -128,6 +134,12 @@ ruleTester.run('a11y-clickable-element-has-text', rule, {
|
|
|
128
134
|
],
|
|
129
135
|
invalid: [
|
|
130
136
|
{ code: `import hoge from 'styled-components'`, errors: [ { message: `styled-components をimportする際は、名称が"styled" となるようにしてください。例: "import styled from 'styled-components'"` } ] },
|
|
137
|
+
{ code: `import { SmartHRLogo as SmartHRLogoHoge } from './hoge'`, errors: [ { message: `SmartHRLogoHogeを正規表現 "/SmartHRLogo$/" がmatchする名称に変更してください` } ] },
|
|
138
|
+
{ code: `import { AbcButton as AbcButtonFuga } from './hoge'`, errors: [ { message: `AbcButtonFugaを正規表現 "/Button$/" がmatchする名称に変更してください` } ] },
|
|
139
|
+
{ code: `import { Anchor as AnchorHoge } from './hoge'`, errors: [ { message: `AnchorHogeを正規表現 "/Anchor$/" がmatchする名称に変更してください` } ] },
|
|
140
|
+
{ code: `import { HogeLink as HogeLinkFuga } from './hoge'`, errors: [ { message: `HogeLinkFugaを正規表現 "/Link$/" がmatchする名称に変更してください` } ] },
|
|
141
|
+
{ code: `import { FugaText as FugaTextFuga } from './hoge'`, errors: [ { message: `FugaTextFugaを正規表現 "/Text$/" がmatchする名称に変更してください` } ] },
|
|
142
|
+
{ code: `import { FugaMessage as FugaMessageFuga } from './hoge'`, errors: [ { message: `FugaMessageFugaを正規表現 "/Message$/" がmatchする名称に変更してください` } ] },
|
|
131
143
|
{ code: 'const Hoge = styled.a``', errors: [ { message: `Hogeを正規表現 "/(Anchor|Link)$/" がmatchする名称に変更してください` } ] },
|
|
132
144
|
{ code: 'const Hoge = styled.button``', errors: [ { message: `Hogeを正規表現 "/Button$/" がmatchする名称に変更してください` } ] },
|
|
133
145
|
{ code: 'const Hoge = styled(Anchor)``', errors: [ { message: `Hogeを正規表現 "/Anchor$/" がmatchする名称に変更してください` } ] },
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
const rule = require('../rules/a11y-delegate-element-has-role-presentation');
|
|
2
|
+
const RuleTester = require('eslint').RuleTester;
|
|
3
|
+
|
|
4
|
+
const ruleTester = new RuleTester({
|
|
5
|
+
parserOptions: {
|
|
6
|
+
ecmaVersion: 2018,
|
|
7
|
+
ecmaFeatures: {
|
|
8
|
+
experimentalObjectRestSpread: true,
|
|
9
|
+
jsx: true,
|
|
10
|
+
},
|
|
11
|
+
sourceType: 'module',
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
ruleTester.run('smarthr/a11y-delegate-element-has-role-presentation', rule, {
|
|
16
|
+
valid: [
|
|
17
|
+
{ code: '<Input />' },
|
|
18
|
+
{ code: '<HogeForm>any</HogeForm>' },
|
|
19
|
+
{ code: '<FugaButton>any</FugaButton>' },
|
|
20
|
+
{ code: '<Link />' },
|
|
21
|
+
{ code: '<div onClick={any} role="presentation"><Link /></div>' },
|
|
22
|
+
{ code: '<Wrapper onClick={any} role="presentation"><Link /></Wrapper>' },
|
|
23
|
+
{ code: '<Wrapper onClick={any} role="presentation"><Hoge /></Wrapper>', options: [{ additionalInteractiveComponentRegex: ['^Hoge$'] }] },
|
|
24
|
+
{ code: '<Wrapper onClick={any} role="presentation"><any><Link /></any></Wrapper>' },
|
|
25
|
+
],
|
|
26
|
+
invalid: [
|
|
27
|
+
{ code: '<Input role="presentation" />', errors: [ { message: `Inputはinput、buttonやaなどのインタラクティブな要素にもかかわらず 'role="presentation"' が設定されているため、ブラウザが正しく解釈が行えず、ユーザーが利用することが出来ない場合があるため、以下のいずれかの対応をおこなってください。
|
|
28
|
+
- 方法1: 'role="presentation"' を削除してください
|
|
29
|
+
- 方法2: Inputの名称を "/(Input$|Textarea$|Select$|InputFile$|RadioButtonPanel$|CheckBox$|ComboBox$|DatePicker$|DropZone$|FieldSet$|Button$|Anchor$|Link$|TabItem$|(Anchor|Link)$|Form$|ActionDialogWithTrigger$|RemoteDialogTrigger$|RemoteTrigger(.+)Dialog$|Pagination$|SideNav$|AccordionPanel$)/" とマッチしない名称に変更してください` } ] },
|
|
30
|
+
{ code: '<HogeForm role="presentation">any</HogeForm>', errors: [ { message: `HogeFormはinput、buttonやaなどのインタラクティブな要素にもかかわらず 'role=\"presentation\"' が設定されているため、ブラウザが正しく解釈が行えず、ユーザーが利用することが出来ない場合があるため、以下のいずれかの対応をおこなってください。
|
|
31
|
+
- 方法1: 'role="presentation"' を削除してください
|
|
32
|
+
- 方法2: HogeFormの名称を "/(Input$|Textarea$|Select$|InputFile$|RadioButtonPanel$|CheckBox$|ComboBox$|DatePicker$|DropZone$|FieldSet$|Button$|Anchor$|Link$|TabItem$|(Anchor|Link)$|Form$|ActionDialogWithTrigger$|RemoteDialogTrigger$|RemoteTrigger(.+)Dialog$|Pagination$|SideNav$|AccordionPanel$)/" とマッチしない名称に変更してください` } ] },
|
|
33
|
+
{ code: '<FugaButton role="presentation">any</FugaButton>', errors: [ { message: `FugaButtonはinput、buttonやaなどのインタラクティブな要素にもかかわらず 'role="presentation"' が設定されているため、ブラウザが正しく解釈が行えず、ユーザーが利用することが出来ない場合があるため、以下のいずれかの対応をおこなってください。
|
|
34
|
+
- 方法1: 'role="presentation"' を削除してください
|
|
35
|
+
- 方法2: FugaButtonの名称を "/(Input$|Textarea$|Select$|InputFile$|RadioButtonPanel$|CheckBox$|ComboBox$|DatePicker$|DropZone$|FieldSet$|Button$|Anchor$|Link$|TabItem$|(Anchor|Link)$|Form$|ActionDialogWithTrigger$|RemoteDialogTrigger$|RemoteTrigger(.+)Dialog$|Pagination$|SideNav$|AccordionPanel$)/" とマッチしない名称に変更してください` } ] },
|
|
36
|
+
{ code: '<Link role="presentation" />', errors: [ { message: `Linkはinput、buttonやaなどのインタラクティブな要素にもかかわらず 'role="presentation"' が設定されているため、ブラウザが正しく解釈が行えず、ユーザーが利用することが出来ない場合があるため、以下のいずれかの対応をおこなってください。
|
|
37
|
+
- 方法1: 'role="presentation"' を削除してください
|
|
38
|
+
- 方法2: Linkの名称を "/(Input$|Textarea$|Select$|InputFile$|RadioButtonPanel$|CheckBox$|ComboBox$|DatePicker$|DropZone$|FieldSet$|Button$|Anchor$|Link$|TabItem$|(Anchor|Link)$|Form$|ActionDialogWithTrigger$|RemoteDialogTrigger$|RemoteTrigger(.+)Dialog$|Pagination$|SideNav$|AccordionPanel$)/" とマッチしない名称に変更してください` } ] },
|
|
39
|
+
{ code: '<div onClick={any} onSubmit={any2} role="presentation"><Hoge /></div>', errors: [ { message: `divに 'role="presentation"' が設定されているにも関わらず、子要素にinput、buttonやaなどのインタラクティブな要素が見つからないため、ブラウザが正しく解釈が行えず、ユーザーが利用することが出来ない場合があるため、以下のいずれかの対応をおこなってください。
|
|
40
|
+
- 方法1: 子要素にインタラクティブな要素が存在するにも関わらずこのエラーが表示されている場合、子要素の名称を変更してください
|
|
41
|
+
- "/(Input$|Textarea$|Select$|InputFile$|RadioButtonPanel$|CheckBox$|ComboBox$|DatePicker$|DropZone$|FieldSet$|Button$|Anchor$|Link$|TabItem$|(Anchor|Link)$|Form$|ActionDialogWithTrigger$|RemoteDialogTrigger$|RemoteTrigger(.+)Dialog$|Pagination$|SideNav$|AccordionPanel$)/" の正規表現にmatchするよう、インタラクティブな子要素全ての名称を変更してください
|
|
42
|
+
- 方法2: div自体がインタラクティブな要素の場合、'role="presentation"'を削除した上で名称を変更してください
|
|
43
|
+
- "/(Input$|Textarea$|Select$|InputFile$|RadioButtonPanel$|CheckBox$|ComboBox$|DatePicker$|DropZone$|FieldSet$|Button$|Anchor$|Link$|TabItem$|(Anchor|Link)$|Form$|ActionDialogWithTrigger$|RemoteDialogTrigger$|RemoteTrigger(.+)Dialog$|Pagination$|SideNav$|AccordionPanel$)/" の正規表現にmatchするよう、divの名称を変更してください
|
|
44
|
+
- 方法3: 子要素にインタラクティブな要素が存在し、onClick, onSubmit全属性をそれらの要素に移動させられる場合、'role="presentation"'を消した上で実施してください` } ] },
|
|
45
|
+
{ code: '<div onClick={any}><Link /></div>', errors: [ { message: `div にonClickを設定するとブラウザが正しく解釈が行えず、ユーザーが利用することが出来ない場合があるため、以下のいずれかの対応をおこなってください。
|
|
46
|
+
- 方法1: divがinput、buttonやaなどのインタラクティブな要素の場合、コンポーネント名の末尾をインタラクティブなコンポーネントであることがわかる名称に変更してください
|
|
47
|
+
- "/(Input$|Textarea$|Select$|InputFile$|RadioButtonPanel$|CheckBox$|ComboBox$|DatePicker$|DropZone$|FieldSet$|Button$|Anchor$|Link$|TabItem$|(Anchor|Link)$|Form$|ActionDialogWithTrigger$|RemoteDialogTrigger$|RemoteTrigger(.+)Dialog$|Pagination$|SideNav$|AccordionPanel$)/" の正規表現にmatchする名称に変更してください
|
|
48
|
+
- 方法2: インタラクティブな親要素、もしくは子要素が存在する場合、直接onClickを設定することを検討してください
|
|
49
|
+
- 方法3: インタラクティブな親要素、もしくは子要素が存在しない場合、インタラクティブな要素を必ず持つようにマークアップを修正後、onClickの設定要素を検討してください
|
|
50
|
+
- 方法4: インタラクティブな子要素から発生したイベントをキャッチすることが目的でonClickを設定している場合、'role="presentation"' を設定してください` } ] },
|
|
51
|
+
{ code: '<Wrapper onClick={any}><Link /></Wrapper>', errors: [ { message: `Wrapper にonClickを設定するとブラウザが正しく解釈が行えず、ユーザーが利用することが出来ない場合があるため、以下のいずれかの対応をおこなってください。
|
|
52
|
+
- 方法1: Wrapperがinput、buttonやaなどのインタラクティブな要素の場合、コンポーネント名の末尾をインタラクティブなコンポーネントであることがわかる名称に変更してください
|
|
53
|
+
- "/(Input$|Textarea$|Select$|InputFile$|RadioButtonPanel$|CheckBox$|ComboBox$|DatePicker$|DropZone$|FieldSet$|Button$|Anchor$|Link$|TabItem$|(Anchor|Link)$|Form$|ActionDialogWithTrigger$|RemoteDialogTrigger$|RemoteTrigger(.+)Dialog$|Pagination$|SideNav$|AccordionPanel$)/" の正規表現にmatchする名称に変更してください
|
|
54
|
+
- 方法2: インタラクティブな親要素、もしくは子要素が存在する場合、直接onClickを設定することを検討してください
|
|
55
|
+
- 方法3: インタラクティブな親要素、もしくは子要素が存在しない場合、インタラクティブな要素を必ず持つようにマークアップを修正後、onClickの設定要素を検討してください
|
|
56
|
+
- 方法4: インタラクティブな子要素から発生したイベントをキャッチすることが目的でonClickを設定している場合、'role="presentation"' を設定してください` } ] },
|
|
57
|
+
{ code: '<Wrapper onSubmit={any}><Hoge /></Wrapper>', options: [{ additionalInteractiveComponentRegex: ['^Hoge$'] }], errors: [ { message: `Wrapper にonSubmitを設定するとブラウザが正しく解釈が行えず、ユーザーが利用することが出来ない場合があるため、以下のいずれかの対応をおこなってください。
|
|
58
|
+
- 方法1: Wrapperがinput、buttonやaなどのインタラクティブな要素の場合、コンポーネント名の末尾をインタラクティブなコンポーネントであることがわかる名称に変更してください
|
|
59
|
+
- "/(Input$|Textarea$|Select$|InputFile$|RadioButtonPanel$|CheckBox$|ComboBox$|DatePicker$|DropZone$|FieldSet$|Button$|Anchor$|Link$|TabItem$|(Anchor|Link)$|Form$|ActionDialogWithTrigger$|RemoteDialogTrigger$|RemoteTrigger(.+)Dialog$|Pagination$|SideNav$|AccordionPanel$|^Hoge$)/" の正規表現にmatchする名称に変更してください
|
|
60
|
+
- 方法2: インタラクティブな親要素、もしくは子要素が存在する場合、直接onSubmitを設定することを検討してください
|
|
61
|
+
- 方法3: インタラクティブな親要素、もしくは子要素が存在しない場合、インタラクティブな要素を必ず持つようにマークアップを修正後、onSubmitの設定要素を検討してください
|
|
62
|
+
- 方法4: インタラクティブな子要素から発生したイベントをキャッチすることが目的でonSubmitを設定している場合、'role="presentation"' を設定してください` } ] },
|
|
63
|
+
{ code: '<Wrapper onClick={any} onChange={anyany}><any><Link /></any></Wrapper>', errors: [ { message: `Wrapper にonClick, onChangeを設定するとブラウザが正しく解釈が行えず、ユーザーが利用することが出来ない場合があるため、以下のいずれかの対応をおこなってください。
|
|
64
|
+
- 方法1: Wrapperがinput、buttonやaなどのインタラクティブな要素の場合、コンポーネント名の末尾をインタラクティブなコンポーネントであることがわかる名称に変更してください
|
|
65
|
+
- "/(Input$|Textarea$|Select$|InputFile$|RadioButtonPanel$|CheckBox$|ComboBox$|DatePicker$|DropZone$|FieldSet$|Button$|Anchor$|Link$|TabItem$|(Anchor|Link)$|Form$|ActionDialogWithTrigger$|RemoteDialogTrigger$|RemoteTrigger(.+)Dialog$|Pagination$|SideNav$|AccordionPanel$)/" の正規表現にmatchする名称に変更してください
|
|
66
|
+
- 方法2: インタラクティブな親要素、もしくは子要素が存在する場合、直接onClick, onChangeを設定することを検討してください
|
|
67
|
+
- 方法3: インタラクティブな親要素、もしくは子要素が存在しない場合、インタラクティブな要素を必ず持つようにマークアップを修正後、onClick, onChangeの設定要素を検討してください
|
|
68
|
+
- 方法4: インタラクティブな子要素から発生したイベントをキャッチすることが目的でonClick, onChangeを設定している場合、'role="presentation"' を設定してください` } ] },
|
|
69
|
+
],
|
|
70
|
+
});
|
|
@@ -26,6 +26,13 @@ const noTagAttrMessage = `tag属性を指定せず、smarthr-uiのArticle, Aside
|
|
|
26
26
|
ruleTester.run('a11y-heading-in-sectioning-content', rule, {
|
|
27
27
|
valid: [
|
|
28
28
|
{ code: `import styled from 'styled-components'` },
|
|
29
|
+
{ code: `import { PageHeading as HogePageHeading } from './hoge'` },
|
|
30
|
+
{ code: `import { HogeHeading as FugaHeading } from './hoge'` },
|
|
31
|
+
{ code: `import { HogeArticle as FugaArticle } from './hoge'` },
|
|
32
|
+
{ code: `import { HogeAside as FugaAside } from './hoge'` },
|
|
33
|
+
{ code: `import { HogeNav as FugaNav } from './hoge'` },
|
|
34
|
+
{ code: `import { HogeSection as FugaSection } from './hoge'` },
|
|
35
|
+
{ code: `import { ModelessDialog as FugaModelessDialog } from './hoge'` },
|
|
29
36
|
{ code: 'const HogePageHeading = styled.h1``' },
|
|
30
37
|
{ code: 'const HogeHeading = styled.h2``' },
|
|
31
38
|
{ code: 'const HogeHeading = styled.h3``' },
|
|
@@ -47,6 +54,13 @@ ruleTester.run('a11y-heading-in-sectioning-content', rule, {
|
|
|
47
54
|
],
|
|
48
55
|
invalid: [
|
|
49
56
|
{ code: `import hoge from 'styled-components'`, errors: [ { message: `styled-components をimportする際は、名称が"styled" となるようにしてください。例: "import styled from 'styled-components'"` } ] },
|
|
57
|
+
{ code: `import { HogePageHeading as PageHeadingAbc } from './hoge'`, errors: [ { message: `PageHeadingAbcを正規表現 "/PageHeading$/" がmatchする名称に変更してください` }, { message: `PageHeadingAbcを正規表現 "/Heading$/" がmatchする名称に変更してください` } ] },
|
|
58
|
+
{ code: `import { Heading as HeadingHoge } from './hoge'`, errors: [ { message: `HeadingHogeを正規表現 "/Heading$/" がmatchする名称に変更してください` } ] },
|
|
59
|
+
{ code: `import { HogeArticle as HogeArticleFuga } from './hoge'`, errors: [ { message: `HogeArticleFugaを正規表現 "/Article$/" がmatchする名称に変更してください` } ] },
|
|
60
|
+
{ code: `import { HogeAside as HogeAsideFuga } from './hoge'`, errors: [ { message: `HogeAsideFugaを正規表現 "/Aside$/" がmatchする名称に変更してください` } ] },
|
|
61
|
+
{ code: `import { HogeNav as HogeNavFuga } from './hoge'`, errors: [ { message: `HogeNavFugaを正規表現 "/Nav$/" がmatchする名称に変更してください` } ] },
|
|
62
|
+
{ code: `import { HogeSection as HogeSectionFuga } from './hoge'`, errors: [ { message: `HogeSectionFugaを正規表現 "/Section$/" がmatchする名称に変更してください` } ] },
|
|
63
|
+
{ code: `import { HogeModelessDialog as HogeModelessDialogFuga } from './hoge'`, errors: [ { message: `HogeModelessDialogFugaを正規表現 "/ModelessDialog$/" がmatchする名称に変更してください` } ] },
|
|
50
64
|
{ code: 'const Hoge = styled.h1``', errors: [ { message: `Hogeを正規表現 "/PageHeading$/" がmatchする名称に変更してください` } ] },
|
|
51
65
|
{ code: 'const Hoge = styled.h2``', errors: [ { message: `Hogeを正規表現 "/Heading$/" がmatchする名称に変更してください` } ] },
|
|
52
66
|
{ code: 'const Hoge = styled.h3``', errors: [ { message: `Hogeを正規表現 "/Heading$/" がmatchする名称に変更してください` } ] },
|
|
@@ -26,6 +26,9 @@ ruleTester.run('a11y-image-has-alt-attribute', rule, {
|
|
|
26
26
|
{ code: `import styled from 'styled-components'` },
|
|
27
27
|
{ code: `import styled, { css } from 'styled-components'` },
|
|
28
28
|
{ code: `import { css } from 'styled-components'` },
|
|
29
|
+
{ code: `import { HogeImg as FugaImg } from './hoge'` },
|
|
30
|
+
{ code: `import { HogeImage as FugaImage } from './hoge'` },
|
|
31
|
+
{ code: `import { HogeIcon as FugaIcon } from './hoge'` },
|
|
29
32
|
{ code: 'const HogeImg = styled.img``' },
|
|
30
33
|
{ code: 'const HogeImage = styled.img``' },
|
|
31
34
|
{ code: 'const HogeIcon = styled.img``' },
|
|
@@ -46,6 +49,9 @@ ruleTester.run('a11y-image-has-alt-attribute', rule, {
|
|
|
46
49
|
],
|
|
47
50
|
invalid: [
|
|
48
51
|
{ code: `import hoge from 'styled-components'`, errors: [ { message: `styled-components をimportする際は、名称が"styled" となるようにしてください。例: "import styled from 'styled-components'"` } ] },
|
|
52
|
+
{ code: `import { HogeImg as ImgFuga } from './hoge'`, errors: [ { message: `ImgFugaを正規表現 "/Img$/" がmatchする名称に変更してください` } ] },
|
|
53
|
+
{ code: `import { HogeImage as HogeImageFuga } from './hoge'`, errors: [ { message: `HogeImageFugaを正規表現 "/Image$/" がmatchする名称に変更してください` } ] },
|
|
54
|
+
{ code: `import { Icon as Hoge } from './hoge'`, errors: [ { message: `Hogeを正規表現 "/Icon$/" がmatchする名称に変更してください` } ] },
|
|
49
55
|
{ code: 'const Hoge = styled.img``', errors: [ { message: `Hogeを正規表現 "/(Img|Image|Icon)$/" がmatchする名称に変更してください` } ] },
|
|
50
56
|
{ code: 'const Hoge = styled.svg``', errors: [ { message: `Hogeを正規表現 "/(Img|Image|Icon)$/" がmatchする名称に変更してください` } ] },
|
|
51
57
|
{ code: 'const Hoge = styled(Icon)``', errors: [ { message: `Hogeを正規表現 "/Icon$/" がmatchする名称に変更してください` } ] },
|
|
@@ -23,6 +23,15 @@ ruleTester.run('a11y-input-has-name-attribute', rule, {
|
|
|
23
23
|
{ code: `import styled from 'styled-components'` },
|
|
24
24
|
{ code: `import styled, { css } from 'styled-components'` },
|
|
25
25
|
{ code: `import { css } from 'styled-components'` },
|
|
26
|
+
{ code: `import { Input as HogeInput } from './hoge'` },
|
|
27
|
+
{ code: `import { HogeTextarea as FugaTextarea } from './hoge'` },
|
|
28
|
+
{ code: `import { Select as HogeSelect } from './hoge'` },
|
|
29
|
+
{ code: `import { InputFile as HogeInputFile } from './hoge'` },
|
|
30
|
+
{ code: `import { HogeRadioButton as FugaRadioButton } from './hoge'` },
|
|
31
|
+
{ code: `import { CheckBox as FugaCheckBox } from './hoge'` },
|
|
32
|
+
{ code: `import { HogeComboBox as FugaComboBox } from './hoge'` },
|
|
33
|
+
{ code: `import { DatePicker as HogeDatePicker } from './hoge'` },
|
|
34
|
+
{ code: `import { HogeDropZone as HogeFugaDropZone } from './hoge'` },
|
|
26
35
|
{ code: 'const HogeInput = styled.input``' },
|
|
27
36
|
{ code: 'const HogeInput = styled(Input)``' },
|
|
28
37
|
{ code: 'const HogeRadioButton = styled(RadioButton)``' },
|
|
@@ -43,6 +52,15 @@ ruleTester.run('a11y-input-has-name-attribute', rule, {
|
|
|
43
52
|
],
|
|
44
53
|
invalid: [
|
|
45
54
|
{ code: `import hoge from 'styled-components'`, errors: [ { message: `styled-components をimportする際は、名称が"styled" となるようにしてください。例: "import styled from 'styled-components'"` } ] },
|
|
55
|
+
{ code: `import { Input as InputHoge } from './hoge'`, errors: [ { message: `InputHogeを正規表現 "/Input$/" がmatchする名称に変更してください` } ] },
|
|
56
|
+
{ code: `import { HogeTextarea as HogeTextareaFuga } from './hoge'`, errors: [ { message: `HogeTextareaFugaを正規表現 "/Textarea$/" がmatchする名称に変更してください` } ] },
|
|
57
|
+
{ code: `import { HogeSelect as SelectFuga } from './hoge'`, errors: [ { message: `SelectFugaを正規表現 "/Select$/" がmatchする名称に変更してください` } ] },
|
|
58
|
+
{ code: `import { InputFile as HogeInputFileFuga } from './hoge'`, errors: [ { message: `HogeInputFileFugaを正規表現 "/InputFile$/" がmatchする名称に変更してください` } ] },
|
|
59
|
+
{ code: `import { HogeRadioButton as FugaRadioButtonAbc } from './hoge'`, errors: [ { message: `FugaRadioButtonAbcを正規表現 "/RadioButton$/" がmatchする名称に変更してください` } ] },
|
|
60
|
+
{ code: `import { CheckBox as FugaCheckBoxHoge } from './hoge'`, errors: [ { message: `FugaCheckBoxHogeを正規表現 "/CheckBox$/" がmatchする名称に変更してください` } ] },
|
|
61
|
+
{ code: `import { HogeComboBox as ComboBoxFuga } from './hoge'`, errors: [ { message: `ComboBoxFugaを正規表現 "/ComboBox$/" がmatchする名称に変更してください` } ] },
|
|
62
|
+
{ code: `import { DatePicker as HogeDatePickerFuga } from './hoge'`, errors: [ { message: `HogeDatePickerFugaを正規表現 "/DatePicker$/" がmatchする名称に変更してください` } ] },
|
|
63
|
+
{ code: `import { HogeDropZone as HogeFugaDropZoneAbc } from './hoge'`, errors: [ { message: `HogeFugaDropZoneAbcを正規表現 "/DropZone$/" がmatchする名称に変更してください` } ] },
|
|
46
64
|
{ code: 'const Hoge = styled.input``', errors: [ { message: `Hogeを正規表現 "/Input$/" がmatchする名称に変更してください` } ] },
|
|
47
65
|
{ code: 'const Hoge = styled.Input``', errors: [ { message: `Hogeを正規表現 "/Input$/" がmatchする名称に変更してください` } ] },
|
|
48
66
|
{ code: 'const Hoge = styled(RadioButton)``', errors: [ { message: `Hogeを正規表現 "/RadioButton$/" がmatchする名称に変更してください` } ] },
|
|
@@ -17,6 +17,11 @@ ruleTester.run('a11y-prohibit-input-placeholder', rule, {
|
|
|
17
17
|
{ code: `import styled from 'styled-components'` },
|
|
18
18
|
{ code: `import styled, { css } from 'styled-components'` },
|
|
19
19
|
{ code: `import { css } from 'styled-components'` },
|
|
20
|
+
{ code: `import { Input as HogeInput } from './hoge'` },
|
|
21
|
+
{ code: `import { HogeSearchInput as FugaSearchInput } from './hoge'` },
|
|
22
|
+
{ code: `import { HogeTextarea as FugaHogeTextarea } from './hoge'` },
|
|
23
|
+
{ code: `import { ComboBox as FugaHogeComboBox } from './hoge'` },
|
|
24
|
+
{ code: `import { AbcDatePicker as StyledDatePicker } from './hoge'` },
|
|
20
25
|
{ code: 'const HogeInput = styled.input``' },
|
|
21
26
|
{ code: 'const HogeTextarea = styled.textarea``' },
|
|
22
27
|
{ code: 'const HogeInput = styled(Input)``' },
|
|
@@ -44,6 +49,11 @@ ruleTester.run('a11y-prohibit-input-placeholder', rule, {
|
|
|
44
49
|
],
|
|
45
50
|
invalid: [
|
|
46
51
|
{ code: `import hoge from 'styled-components'`, errors: [ { message: `styled-components をimportする際は、名称が"styled" となるようにしてください。例: "import styled from 'styled-components'"` } ] },
|
|
52
|
+
{ code: `import { Input as InputHoge } from './hoge'`, errors: [ { message: `InputHogeを正規表現 "/Input$/" がmatchする名称に変更してください` } ] },
|
|
53
|
+
{ code: `import { SearchInput as Hoge } from './hoge'`, errors: [ { message: `Hogeを正規表現 "/Input$/" がmatchする名称に変更してください` }, { message: `Hogeを正規表現 "/SearchInput$/" がmatchする名称に変更してください` } ] },
|
|
54
|
+
{ code: `import { HogeTextarea as HogeTextareaFuga } from './hoge'`, errors: [ { message: `HogeTextareaFugaを正規表現 "/Textarea$/" がmatchする名称に変更してください` } ] },
|
|
55
|
+
{ code: `import { HogeComboBox as ComboBoxFuga } from './hoge'`, errors: [ { message: `ComboBoxFugaを正規表現 "/ComboBox$/" がmatchする名称に変更してください` } ] },
|
|
56
|
+
{ code: `import { DatePicker as HogeDatePickerFuga } from './hoge'`, errors: [ { message: `HogeDatePickerFugaを正規表現 "/DatePicker$/" がmatchする名称に変更してください` } ] },
|
|
47
57
|
{ code: 'const Hoge = styled.input``', errors: [ { message: `Hogeを正規表現 "/Input$/" がmatchする名称に変更してください` } ] },
|
|
48
58
|
{ code: 'const Hoge = styled(StyledInput)``', errors: [ { message: `Hogeを正規表現 "/Input$/" がmatchする名称に変更してください` } ] },
|
|
49
59
|
{ code: 'const Hoge = styled.textarea``', errors: [ { message: `Hogeを正規表現 "/Textarea$/" がmatchする名称に変更してください` } ] },
|
|
@@ -17,6 +17,12 @@ ruleTester.run('a11y-trigger-has-button', rule, {
|
|
|
17
17
|
{ code: `import styled from 'styled-components'` },
|
|
18
18
|
{ code: `import styled, { css } from 'styled-components'` },
|
|
19
19
|
{ code: `import { css } from 'styled-components'` },
|
|
20
|
+
{ code: `import { DropdownTrigger as HogeDropdownTrigger } from './hoge'` },
|
|
21
|
+
{ code: `import { FugaDialogTrigger as HogeDialogTrigger } from './hoge'` },
|
|
22
|
+
{ code: `import { AbcButton as HogeAbcButton } from './hoge'` },
|
|
23
|
+
{ code: `import { AnchorButton as FugaAnchorButton } from './hoge'` },
|
|
24
|
+
{ code: `import { HogeAnchor as HogeFugaAnchor } from './hoge'` },
|
|
25
|
+
{ code: `import { FugaLink as HogeLink } from './hoge'` },
|
|
20
26
|
{ code: 'const HogeButton = styled.button``' },
|
|
21
27
|
{ code: 'const HogeAnchor = styled.a``' },
|
|
22
28
|
{ code: 'const HogeLink = styled.a``' },
|
|
@@ -33,6 +39,12 @@ ruleTester.run('a11y-trigger-has-button', rule, {
|
|
|
33
39
|
],
|
|
34
40
|
invalid: [
|
|
35
41
|
{ code: `import hoge from 'styled-components'`, errors: [ { message: `styled-components をimportする際は、名称が"styled" となるようにしてください。例: "import styled from 'styled-components'"` } ] },
|
|
42
|
+
{ code: `import { DropdownTrigger as Hoge } from './hoge'`, errors: [ { message: `Hogeを正規表現 "/DropdownTrigger$/" がmatchする名称に変更してください` } ] },
|
|
43
|
+
{ code: `import { DialogTrigger as Hoge } from './hoge'`, errors: [ { message: `Hogeを正規表現 "/DialogTrigger$/" がmatchする名称に変更してください` } ] },
|
|
44
|
+
{ code: `import { Button as Hoge } from './hoge'`, errors: [ { message: `Hogeを正規表現 "/Button$/" がmatchする名称に変更してください` } ] },
|
|
45
|
+
{ code: `import { AbcAnchorButton as Hoge } from './hoge'`, errors: [ { message: `Hogeを正規表現 "/Button$/" がmatchする名称に変更してください` }, { message: `Hogeを正規表現 "/AnchorButton$/" がmatchする名称に変更してください` } ] },
|
|
46
|
+
{ code: `import { Anchor as Hoge } from './hoge'`, errors: [ { message: `Hogeを正規表現 "/Anchor$/" がmatchする名称に変更してください` } ] },
|
|
47
|
+
{ code: `import { Link as Hoge } from './hoge'`, errors: [ { message: `Hogeを正規表現 "/Link$/" がmatchする名称に変更してください` } ] },
|
|
36
48
|
{ code: 'const Hoge = styled.button``', errors: [ { message: `Hogeを正規表現 "/Button$/" がmatchする名称に変更してください` } ] },
|
|
37
49
|
{ code: 'const Hoge = styled.a``', errors: [ { message: `Hogeを正規表現 "/(Anchor|Link)$/" がmatchする名称に変更してください` } ] },
|
|
38
50
|
{ code: 'const Hoge = styled(Button)``', errors: [ { message: `Hogeを正規表現 "/Button$/" がmatchする名称に変更してください` } ] },
|