eslint-plugin-smarthr 0.3.23 → 0.3.25
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 +10 -0
- package/README.md +2 -1
- package/libs/format_styled_components.js +1 -2
- package/package.json +1 -1
- package/rules/a11y-heading-in-sectioning-content/README.md +6 -8
- package/rules/a11y-heading-in-sectioning-content/index.js +2 -1
- package/rules/a11y-input-has-name-attribute/index.js +1 -1
- package/rules/a11y-input-in-form-control/README.md +103 -0
- package/rules/a11y-input-in-form-control/index.js +441 -0
- package/rules/a11y-prohibit-useless-sectioning-fragment/README.md +60 -0
- package/rules/a11y-prohibit-useless-sectioning-fragment/index.js +74 -0
- package/test/a11y-anchor-has-href-attribute.js +7 -5
- package/test/a11y-clickable-element-has-text.js +26 -20
- package/test/a11y-heading-in-sectioning-content.js +37 -24
- package/test/a11y-image-has-alt-attribute.js +11 -8
- package/test/a11y-input-has-name-attribute.js +21 -12
- package/test/a11y-input-in-form-control.js +155 -0
- package/test/a11y-prohhibit-input-placeholder.js +19 -13
- package/test/a11y-prohibit-useless-sectioning-fragment.js +31 -0
- package/test/a11y-trigger-has-button.js +22 -15
- package/test/best-practice-for-remote-trigger-dialog.js +2 -2
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# smarthr/a11y-prohibit-useless-sectioning-fragment
|
|
2
|
+
|
|
3
|
+
- Headingレベルの自動計算用のコンポーネントであるSectioningFragmentが不必要に利用されている場合を検知し、修正を促します
|
|
4
|
+
- Sectioninigされるコンポーネントを直接SectioningFragmentで囲んでいる場合エラーになります
|
|
5
|
+
|
|
6
|
+
## rules
|
|
7
|
+
|
|
8
|
+
```js
|
|
9
|
+
{
|
|
10
|
+
rules: {
|
|
11
|
+
'smarthr/a11y-prohibit-useless-sectioning-fragment': 'error', // 'warn', 'off',
|
|
12
|
+
},
|
|
13
|
+
}
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## ❌ Incorrect
|
|
17
|
+
|
|
18
|
+
```jsx
|
|
19
|
+
<SectioninigFragment>
|
|
20
|
+
<Section>
|
|
21
|
+
any
|
|
22
|
+
</Section>
|
|
23
|
+
</SectioninigFragment>
|
|
24
|
+
|
|
25
|
+
<SectioninigFragment>
|
|
26
|
+
<Stack as="aside">
|
|
27
|
+
any
|
|
28
|
+
</Stack>
|
|
29
|
+
</SectioninigFragment>
|
|
30
|
+
|
|
31
|
+
<SectioninigFragment>
|
|
32
|
+
<HogeCenter forwardedas="nav">
|
|
33
|
+
any
|
|
34
|
+
</HogeCenter>
|
|
35
|
+
</SectioninigFragment>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## ✅ Correct
|
|
39
|
+
|
|
40
|
+
```jsx
|
|
41
|
+
<Section>
|
|
42
|
+
any
|
|
43
|
+
</Section>
|
|
44
|
+
|
|
45
|
+
<Stack as="aside">
|
|
46
|
+
any
|
|
47
|
+
</Stack>
|
|
48
|
+
|
|
49
|
+
<HogeCenter forwardedas="nav">
|
|
50
|
+
any
|
|
51
|
+
</HogeCenter>
|
|
52
|
+
|
|
53
|
+
<SectioningFragment>
|
|
54
|
+
<Any />
|
|
55
|
+
</SectioningFragment>
|
|
56
|
+
|
|
57
|
+
<Aside>
|
|
58
|
+
<SectioningFragment>{any}</SectioningFragment>>
|
|
59
|
+
</Aside>
|
|
60
|
+
```
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
const { generateTagFormatter } = require('../../libs/format_styled_components')
|
|
2
|
+
|
|
3
|
+
const EXPECTED_NAMES = {
|
|
4
|
+
'Article$': '(Article)$',
|
|
5
|
+
'Aside$': '(Aside)$',
|
|
6
|
+
'Nav$': '(Nav)$',
|
|
7
|
+
'Section$': '(Section)$',
|
|
8
|
+
'Center$': '(Center)$',
|
|
9
|
+
'Reel$': '(Reel)$',
|
|
10
|
+
'Sidebar$': '(Sidebar)$',
|
|
11
|
+
'Stack$': '(Stack)$',
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const UNEXPECTED_NAMES = EXPECTED_NAMES
|
|
15
|
+
|
|
16
|
+
const BARE_SECTIONING_TAG_REGEX = /^(article|aside|nav|section)$/
|
|
17
|
+
const SECTIONING_REGEX = /((A(rticle|side))|Nav|Section)$/
|
|
18
|
+
const SECTIONING_FRAGMENT_REGEX = /^SectioningFragment$/
|
|
19
|
+
const LAYOUT_REGEX = /((C(ent|lust)er)|Reel|Sidebar|Stack)$/
|
|
20
|
+
const AS_REGEX = /^(as|forwardedAs)$/
|
|
21
|
+
|
|
22
|
+
const includeSectioningAsAttr = (a) => a.name?.name.match(AS_REGEX) && a.value.value.match(BARE_SECTIONING_TAG_REGEX)
|
|
23
|
+
|
|
24
|
+
const searchSectioningFragment = (node) => {
|
|
25
|
+
switch (node.type) {
|
|
26
|
+
case 'JSXElement':
|
|
27
|
+
return node.openingElement.name?.name.match(SECTIONING_FRAGMENT_REGEX) ? node.openingElement : null
|
|
28
|
+
case 'Program':
|
|
29
|
+
return null
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return searchSectioningFragment(node.parent)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const SCHEMA = []
|
|
36
|
+
|
|
37
|
+
module.exports = {
|
|
38
|
+
meta: {
|
|
39
|
+
type: 'problem',
|
|
40
|
+
schema: SCHEMA,
|
|
41
|
+
},
|
|
42
|
+
create(context) {
|
|
43
|
+
return {
|
|
44
|
+
...generateTagFormatter({ context, EXPECTED_NAMES, UNEXPECTED_NAMES }),
|
|
45
|
+
JSXOpeningElement: (node) => {
|
|
46
|
+
const name = node.name?.name || ''
|
|
47
|
+
let hit = null
|
|
48
|
+
let asAttr = null
|
|
49
|
+
|
|
50
|
+
if (name.match(SECTIONING_REGEX)) {
|
|
51
|
+
hit = true
|
|
52
|
+
} else {
|
|
53
|
+
asAttr = name.match(LAYOUT_REGEX) && node.attributes.find(includeSectioningAsAttr)
|
|
54
|
+
|
|
55
|
+
if (asAttr) {
|
|
56
|
+
hit = true
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (hit) {
|
|
61
|
+
result = searchSectioningFragment(node.parent.parent)
|
|
62
|
+
|
|
63
|
+
if (result) {
|
|
64
|
+
context.report({
|
|
65
|
+
node: result,
|
|
66
|
+
message: `無意味なSectioningFragmentが記述されています。子要素である<${name}${asAttr ? ` ${asAttr.name.name}="${asAttr.value.value}"` : ''}>で問題なくセクションは設定されているため、このSectioningFragmentは削除してください`
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
}
|
|
74
|
+
module.exports.schema = SCHEMA
|
|
@@ -41,11 +41,13 @@ ruleTester.run('a11y-anchor-has-href-attribute', rule, {
|
|
|
41
41
|
],
|
|
42
42
|
invalid: [
|
|
43
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
|
-
|
|
46
|
-
{ code:
|
|
47
|
-
|
|
48
|
-
{ code: 'const Hoge = styled
|
|
44
|
+
{ code: `import { Anchor as AnchorHoge } from './hoge'`, errors: [ { message: `AnchorHogeを正規表現 "/Anchor$/" がmatchする名称に変更してください。
|
|
45
|
+
- Anchorが型の場合、'import type { Anchor as AnchorHoge }' もしくは 'import { type Anchor as AnchorHoge }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
46
|
+
{ code: `import { HogeLink as HogeLinkFuga } from './hoge'`, errors: [ { message: `HogeLinkFugaを正規表現 "/Link$/" がmatchする名称に変更してください。
|
|
47
|
+
- HogeLinkが型の場合、'import type { HogeLink as HogeLinkFuga }' もしくは 'import { type HogeLink as HogeLinkFuga }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
48
|
+
{ code: 'const Hoge = styled.a``', errors: [ { message: `Hogeを正規表現 "/(Anchor|Link)$/" がmatchする名称に変更してください。` } ] },
|
|
49
|
+
{ code: 'const Hoge = styled(Anchor)``', errors: [ { message: `Hogeを正規表現 "/Anchor$/" がmatchする名称に変更してください。` } ] },
|
|
50
|
+
{ code: 'const Hoge = styled(Link)``', errors: [ { message: `Hogeを正規表現 "/Link$/" がmatchする名称に変更してください。` } ] },
|
|
49
51
|
{ code: 'const FugaAnchor = styled.div``', errors: [ { message: `FugaAnchor は /(Anchor|^a)$/ にmatchする名前のコンポーネントを拡張することを期待している名称になっています
|
|
50
52
|
- FugaAnchor の名称の末尾が"Anchor" という文字列ではない状態にしつつ、"div"を継承していることをわかる名称に変更してください
|
|
51
53
|
- もしくは"div"を"FugaAnchor"の継承元であることがわかるような適切なタグや別コンポーネントに差し替えてください
|
|
@@ -134,26 +134,32 @@ ruleTester.run('a11y-clickable-element-has-text', rule, {
|
|
|
134
134
|
],
|
|
135
135
|
invalid: [
|
|
136
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
|
-
|
|
139
|
-
{ code: `import {
|
|
140
|
-
|
|
141
|
-
{ code: `import {
|
|
142
|
-
|
|
143
|
-
{ code:
|
|
144
|
-
|
|
145
|
-
{ code:
|
|
146
|
-
|
|
147
|
-
{ code:
|
|
148
|
-
|
|
149
|
-
{ code: 'const
|
|
150
|
-
{ code: 'const
|
|
151
|
-
{ code: 'const
|
|
152
|
-
{ code: 'const
|
|
153
|
-
{ code: 'const
|
|
154
|
-
{ code: 'const
|
|
155
|
-
{ code: 'const
|
|
156
|
-
{ code: 'const
|
|
137
|
+
{ code: `import { SmartHRLogo as SmartHRLogoHoge } from './hoge'`, errors: [ { message: `SmartHRLogoHogeを正規表現 "/SmartHRLogo$/" がmatchする名称に変更してください。
|
|
138
|
+
- SmartHRLogoが型の場合、'import type { SmartHRLogo as SmartHRLogoHoge }' もしくは 'import { type SmartHRLogo as SmartHRLogoHoge }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
139
|
+
{ code: `import { AbcButton as AbcButtonFuga } from './hoge'`, errors: [ { message: `AbcButtonFugaを正規表現 "/Button$/" がmatchする名称に変更してください。
|
|
140
|
+
- AbcButtonが型の場合、'import type { AbcButton as AbcButtonFuga }' もしくは 'import { type AbcButton as AbcButtonFuga }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
141
|
+
{ code: `import { Anchor as AnchorHoge } from './hoge'`, errors: [ { message: `AnchorHogeを正規表現 "/Anchor$/" がmatchする名称に変更してください。
|
|
142
|
+
- Anchorが型の場合、'import type { Anchor as AnchorHoge }' もしくは 'import { type Anchor as AnchorHoge }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
143
|
+
{ code: `import { HogeLink as HogeLinkFuga } from './hoge'`, errors: [ { message: `HogeLinkFugaを正規表現 "/Link$/" がmatchする名称に変更してください。
|
|
144
|
+
- HogeLinkが型の場合、'import type { HogeLink as HogeLinkFuga }' もしくは 'import { type HogeLink as HogeLinkFuga }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
145
|
+
{ code: `import { FugaText as FugaTextFuga } from './hoge'`, errors: [ { message: `FugaTextFugaを正規表現 "/Text$/" がmatchする名称に変更してください。
|
|
146
|
+
- FugaTextが型の場合、'import type { FugaText as FugaTextFuga }' もしくは 'import { type FugaText as FugaTextFuga }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
147
|
+
{ code: `import { FugaMessage as FugaMessageFuga } from './hoge'`, errors: [ { message: `FugaMessageFugaを正規表現 "/Message$/" がmatchする名称に変更してください。
|
|
148
|
+
- FugaMessageが型の場合、'import type { FugaMessage as FugaMessageFuga }' もしくは 'import { type FugaMessage as FugaMessageFuga }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
149
|
+
{ code: 'const Hoge = styled.a``', errors: [ { message: `Hogeを正規表現 "/(Anchor|Link)$/" がmatchする名称に変更してください。` } ] },
|
|
150
|
+
{ code: 'const Hoge = styled.button``', errors: [ { message: `Hogeを正規表現 "/Button$/" がmatchする名称に変更してください。` } ] },
|
|
151
|
+
{ code: 'const Hoge = styled(Anchor)``', errors: [ { message: `Hogeを正規表現 "/Anchor$/" がmatchする名称に変更してください。` } ] },
|
|
152
|
+
{ code: 'const Hoge = styled(Link)``', errors: [ { message: `Hogeを正規表現 "/Link$/" がmatchする名称に変更してください。` } ] },
|
|
153
|
+
{ code: 'const Hoge = styled(Button)``', errors: [ { message: `Hogeを正規表現 "/Button$/" がmatchする名称に変更してください。` } ] },
|
|
154
|
+
{ code: 'const Fuga = styled(HogeAnchor)``', errors: [ { message: `Fugaを正規表現 "/Anchor$/" がmatchする名称に変更してください。` } ] },
|
|
155
|
+
{ code: 'const Fuga = styled(HogeAnchor)``', errors: [ { message: `Fugaを正規表現 "/Anchor$/" がmatchする名称に変更してください。` } ] },
|
|
156
|
+
{ code: 'const Fuga = styled(SmartHRLogo)``', errors: [ { message: `Fugaを正規表現 "/SmartHRLogo$/" がmatchする名称に変更してください。` } ] },
|
|
157
|
+
{ code: 'const Piyo = styled.a(() => ``)', errors: [ { message: `Piyoを正規表現 "/(Anchor|Link)$/" がmatchする名称に変更してください。` } ] },
|
|
158
|
+
{ code: 'const Piyo = styled("a")(() => ``)', errors: [ { message: `Piyoを正規表現 "/(Anchor|Link)$/" がmatchする名称に変更してください。` } ] },
|
|
159
|
+
{ code: 'const Piyo = styled("a")``', errors: [ { message: `Piyoを正規表現 "/(Anchor|Link)$/" がmatchする名称に変更してください。` } ] },
|
|
160
|
+
{ code: 'const Piyo = styled(Anchor)(() => ``)', errors: [ { message: `Piyoを正規表現 "/Anchor$/" がmatchする名称に変更してください。` } ] },
|
|
161
|
+
{ code: 'const Hoge = styled(Text)``', errors: [ { message: `Hogeを正規表現 "/Text$/" がmatchする名称に変更してください。` } ] },
|
|
162
|
+
{ code: 'const Hoge = styled(HogeMessage)``', errors: [ { message: `Hogeを正規表現 "/Message$/" がmatchする名称に変更してください。` } ] },
|
|
157
163
|
{ code: 'const StyledButton = styled.div``', errors: [ { message: `StyledButton は /(B|^b)utton$/ にmatchする名前のコンポーネントを拡張することを期待している名称になっています
|
|
158
164
|
- StyledButton の名称の末尾が"Button" という文字列ではない状態にしつつ、"div"を継承していることをわかる名称に変更してください
|
|
159
165
|
- もしくは"div"を"StyledButton"の継承元であることがわかるような適切なタグや別コンポーネントに差し替えてください
|
|
@@ -60,33 +60,46 @@ ruleTester.run('a11y-heading-in-sectioning-content', rule, {
|
|
|
60
60
|
{ code: '<Reel as="aside"><div><Heading>hoge</Heading></div></Reel>' },
|
|
61
61
|
{ code: '<Sidebar as="nav"><div><Heading>hoge</Heading></div></Sidebar>' },
|
|
62
62
|
{ code: '<Stack as="section"><div><Heading>hoge</Heading></div></Stack>' },
|
|
63
|
+
{ code: '<HogeCenter forwardedAs="section"><div><Heading>hoge</Heading></div></HogeCenter>' },
|
|
64
|
+
{ code: '<HogeCluster forwardedAs="section"><div><Heading>hoge</Heading></div></HogeCluster>' },
|
|
65
|
+
{ code: '<HogeReel forwardedAs="aside"><div><Heading>hoge</Heading></div></HogeReel>' },
|
|
66
|
+
{ code: '<HogeSidebar forwardedAs="nav"><div><Heading>hoge</Heading></div></HogeSidebar>' },
|
|
67
|
+
{ code: '<HogeStack forwardedAs="section"><div><Heading>hoge</Heading></div></HogeStack>' },
|
|
63
68
|
],
|
|
64
69
|
invalid: [
|
|
65
70
|
{ code: `import hoge from 'styled-components'`, errors: [ { message: `styled-components をimportする際は、名称が"styled" となるようにしてください。例: "import styled from 'styled-components'"` } ] },
|
|
66
|
-
{ code: `import { HogePageHeading as PageHeadingAbc } from './hoge'`, errors: [ { message: `PageHeadingAbcを正規表現 "/PageHeading$/" がmatch
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
{ code: `import {
|
|
70
|
-
|
|
71
|
-
{ code: `import {
|
|
72
|
-
|
|
73
|
-
{ code:
|
|
74
|
-
|
|
75
|
-
{ code:
|
|
76
|
-
|
|
77
|
-
{ code:
|
|
78
|
-
|
|
79
|
-
{ code:
|
|
80
|
-
|
|
81
|
-
{ code: 'const
|
|
82
|
-
{ code: 'const
|
|
83
|
-
{ code: 'const
|
|
84
|
-
{ code: 'const
|
|
85
|
-
{ code: 'const
|
|
86
|
-
{ code: 'const
|
|
87
|
-
{ code: 'const Fuga = styled(
|
|
88
|
-
{ code: 'const Fuga = styled(
|
|
89
|
-
{ code: 'const Fuga = styled(
|
|
71
|
+
{ code: `import { HogePageHeading as PageHeadingAbc } from './hoge'`, errors: [ { message: `PageHeadingAbcを正規表現 "/PageHeading$/" がmatchする名称に変更してください。
|
|
72
|
+
- HogePageHeadingが型の場合、'import type { HogePageHeading as PageHeadingAbc }' もしくは 'import { type HogePageHeading as PageHeadingAbc }' のように明示的に型であることを宣言してください。名称変更が不要になります` }, { message: `PageHeadingAbcを正規表現 "/Heading$/" がmatchする名称に変更してください。
|
|
73
|
+
- HogePageHeadingが型の場合、'import type { HogePageHeading as PageHeadingAbc }' もしくは 'import { type HogePageHeading as PageHeadingAbc }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
74
|
+
{ code: `import { Heading as HeadingHoge } from './hoge'`, errors: [ { message: `HeadingHogeを正規表現 "/Heading$/" がmatchする名称に変更してください。
|
|
75
|
+
- Headingが型の場合、'import type { Heading as HeadingHoge }' もしくは 'import { type Heading as HeadingHoge }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
76
|
+
{ code: `import { HogeArticle as HogeArticleFuga } from './hoge'`, errors: [ { message: `HogeArticleFugaを正規表現 "/Article$/" がmatchする名称に変更してください。
|
|
77
|
+
- HogeArticleが型の場合、'import type { HogeArticle as HogeArticleFuga }' もしくは 'import { type HogeArticle as HogeArticleFuga }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
78
|
+
{ code: `import { HogeAside as HogeAsideFuga } from './hoge'`, errors: [ { message: `HogeAsideFugaを正規表現 "/Aside$/" がmatchする名称に変更してください。
|
|
79
|
+
- HogeAsideが型の場合、'import type { HogeAside as HogeAsideFuga }' もしくは 'import { type HogeAside as HogeAsideFuga }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
80
|
+
{ code: `import { HogeNav as HogeNavFuga } from './hoge'`, errors: [ { message: `HogeNavFugaを正規表現 "/Nav$/" がmatchする名称に変更してください。
|
|
81
|
+
- HogeNavが型の場合、'import type { HogeNav as HogeNavFuga }' もしくは 'import { type HogeNav as HogeNavFuga }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
82
|
+
{ code: `import { HogeSection as HogeSectionFuga } from './hoge'`, errors: [ { message: `HogeSectionFugaを正規表現 "/Section$/" がmatchする名称に変更してください。
|
|
83
|
+
- HogeSectionが型の場合、'import type { HogeSection as HogeSectionFuga }' もしくは 'import { type HogeSection as HogeSectionFuga }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
84
|
+
{ code: `import { HogeModelessDialog as HogeModelessDialogFuga } from './hoge'`, errors: [ { message: `HogeModelessDialogFugaを正規表現 "/ModelessDialog$/" がmatchする名称に変更してください。
|
|
85
|
+
- HogeModelessDialogが型の場合、'import type { HogeModelessDialog as HogeModelessDialogFuga }' もしくは 'import { type HogeModelessDialog as HogeModelessDialogFuga }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
86
|
+
{ code: 'const Hoge = styled.h1``', errors: [ { message: `Hogeを正規表現 "/PageHeading$/" がmatchする名称に変更してください。` } ] },
|
|
87
|
+
{ code: 'const Hoge = styled.h2``', errors: [ { message: `Hogeを正規表現 "/Heading$/" がmatchする名称に変更してください。` } ] },
|
|
88
|
+
{ code: 'const Hoge = styled.h3``', errors: [ { message: `Hogeを正規表現 "/Heading$/" がmatchする名称に変更してください。` } ] },
|
|
89
|
+
{ code: 'const Hoge = styled.h4``', errors: [ { message: `Hogeを正規表現 "/Heading$/" がmatchする名称に変更してください。` } ] },
|
|
90
|
+
{ code: 'const Hoge = styled.h5``', errors: [ { message: `Hogeを正規表現 "/Heading$/" がmatchする名称に変更してください。` } ] },
|
|
91
|
+
{ code: 'const Hoge = styled.h6``', errors: [ { message: `Hogeを正規表現 "/Heading$/" がmatchする名称に変更してください。` } ] },
|
|
92
|
+
{ code: 'const Fuga = styled(Heading)``', errors: [ { message: `Fugaを正規表現 "/Heading$/" がmatchする名称に変更してください。` } ] },
|
|
93
|
+
{ code: 'const Fuga = styled(HogeHeading)``', errors: [ { message: `Fugaを正規表現 "/Heading$/" がmatchする名称に変更してください。` } ] },
|
|
94
|
+
{ code: 'const Fuga = styled(HogeHeading).attrs(() => ({ type: "blockTitle" }))``', errors: [ { message: `Fugaを正規表現 "/Heading$/" がmatchする名称に変更してください。` } ] },
|
|
95
|
+
{ code: 'const Fuga = styled(HogeArticle)``', errors: [ { message: `Fugaを正規表現 "/Article$/" がmatchする名称に変更してください。` } ] },
|
|
96
|
+
{ code: 'const Fuga = styled(HogeAside)``', errors: [ { message: `Fugaを正規表現 "/Aside$/" がmatchする名称に変更してください。` } ] },
|
|
97
|
+
{ code: 'const Fuga = styled(HogeNav)``', errors: [ { message: `Fugaを正規表現 "/Nav$/" がmatchする名称に変更してください。` } ] },
|
|
98
|
+
{ code: 'const Fuga = styled(HogeSection)``', errors: [ { message: `Fugaを正規表現 "/Section$/" がmatchする名称に変更してください。` } ] },
|
|
99
|
+
{ code: 'const Fuga = styled(HogeCenter)``', errors: [ { message: `Fugaを正規表現 "/Center$/" がmatchする名称に変更してください。` } ] },
|
|
100
|
+
{ code: 'const Fuga = styled(HogeReel)``', errors: [ { message: `Fugaを正規表現 "/Reel$/" がmatchする名称に変更してください。` } ] },
|
|
101
|
+
{ code: 'const Fuga = styled(HogeSidebar)``', errors: [ { message: `Fugaを正規表現 "/Sidebar$/" がmatchする名称に変更してください。` } ] },
|
|
102
|
+
{ code: 'const Fuga = styled(HogeStack)``', errors: [ { message: `Fugaを正規表現 "/Stack$/" がmatchする名称に変更してください。` } ] },
|
|
90
103
|
{ code: 'const StyledArticle = styled.article``', errors: [ { message: `"article"を利用せず、smarthr-ui/Articleを拡張してください。Headingのレベルが自動計算されるようになります。(例: "styled.article" -> "styled(Article)")` } ] },
|
|
91
104
|
{ code: 'const StyledAside = styled.aside``', errors: [ { message: `"aside"を利用せず、smarthr-ui/Asideを拡張してください。Headingのレベルが自動計算されるようになります。(例: "styled.aside" -> "styled(Aside)")` } ] },
|
|
92
105
|
{ code: 'const StyledNav = styled.nav``', errors: [ { message: `"nav"を利用せず、smarthr-ui/Navを拡張してください。Headingのレベルが自動計算されるようになります。(例: "styled.nav" -> "styled(Nav)")` } ] },
|
|
@@ -49,14 +49,17 @@ ruleTester.run('a11y-image-has-alt-attribute', rule, {
|
|
|
49
49
|
],
|
|
50
50
|
invalid: [
|
|
51
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
|
-
|
|
54
|
-
{ code: `import {
|
|
55
|
-
|
|
56
|
-
{ code:
|
|
57
|
-
|
|
58
|
-
{ code: 'const Hoge = styled
|
|
59
|
-
{ code: 'const Hoge = styled
|
|
52
|
+
{ code: `import { HogeImg as ImgFuga } from './hoge'`, errors: [ { message: `ImgFugaを正規表現 "/Img$/" がmatchする名称に変更してください。
|
|
53
|
+
- HogeImgが型の場合、'import type { HogeImg as ImgFuga }' もしくは 'import { type HogeImg as ImgFuga }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
54
|
+
{ code: `import { HogeImage as HogeImageFuga } from './hoge'`, errors: [ { message: `HogeImageFugaを正規表現 "/Image$/" がmatchする名称に変更してください。
|
|
55
|
+
- HogeImageが型の場合、'import type { HogeImage as HogeImageFuga }' もしくは 'import { type HogeImage as HogeImageFuga }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
56
|
+
{ code: `import { Icon as Hoge } from './hoge'`, errors: [ { message: `Hogeを正規表現 "/Icon$/" がmatchする名称に変更してください。
|
|
57
|
+
- Iconが型の場合、'import type { Icon as Hoge }' もしくは 'import { type Icon as Hoge }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
58
|
+
{ code: 'const Hoge = styled.img``', errors: [ { message: `Hogeを正規表現 "/(Img|Image|Icon)$/" がmatchする名称に変更してください。` } ] },
|
|
59
|
+
{ code: 'const Hoge = styled.svg``', errors: [ { message: `Hogeを正規表現 "/(Img|Image|Icon)$/" がmatchする名称に変更してください。` } ] },
|
|
60
|
+
{ code: 'const Hoge = styled(Icon)``', errors: [ { message: `Hogeを正規表現 "/Icon$/" がmatchする名称に変更してください。` } ] },
|
|
61
|
+
{ code: 'const Hoge = styled(Img)``', errors: [ { message: `Hogeを正規表現 "/Img$/" がmatchする名称に変更してください。` } ] },
|
|
62
|
+
{ code: 'const Hoge = styled(Image)``', errors: [ { message: `Hogeを正規表現 "/Image$/" がmatchする名称に変更してください。` } ] },
|
|
60
63
|
{ code: 'const StyledImage = styled.span``', errors: [ { message: `StyledImage は /(Image|^(img|svg))$/ にmatchする名前のコンポーネントを拡張することを期待している名称になっています
|
|
61
64
|
- StyledImage の名称の末尾が"Image" という文字列ではない状態にしつつ、"span"を継承していることをわかる名称に変更してください
|
|
62
65
|
- もしくは"span"を"StyledImage"の継承元であることがわかるような適切なタグや別コンポーネントに差し替えてください
|
|
@@ -52,18 +52,27 @@ ruleTester.run('a11y-input-has-name-attribute', rule, {
|
|
|
52
52
|
],
|
|
53
53
|
invalid: [
|
|
54
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
|
-
|
|
57
|
-
{ code: `import {
|
|
58
|
-
|
|
59
|
-
{ code: `import {
|
|
60
|
-
|
|
61
|
-
{ code: `import {
|
|
62
|
-
|
|
63
|
-
{ code: `import {
|
|
64
|
-
|
|
65
|
-
{ code:
|
|
66
|
-
|
|
55
|
+
{ code: `import { Input as InputHoge } from './hoge'`, errors: [ { message: `InputHogeを正規表現 "/Input$/" がmatchする名称に変更してください。
|
|
56
|
+
- Inputが型の場合、'import type { Input as InputHoge }' もしくは 'import { type Input as InputHoge }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
57
|
+
{ code: `import { HogeTextarea as HogeTextareaFuga } from './hoge'`, errors: [ { message: `HogeTextareaFugaを正規表現 "/Textarea$/" がmatchする名称に変更してください。
|
|
58
|
+
- HogeTextareaが型の場合、'import type { HogeTextarea as HogeTextareaFuga }' もしくは 'import { type HogeTextarea as HogeTextareaFuga }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
59
|
+
{ code: `import { HogeSelect as SelectFuga } from './hoge'`, errors: [ { message: `SelectFugaを正規表現 "/Select$/" がmatchする名称に変更してください。
|
|
60
|
+
- HogeSelectが型の場合、'import type { HogeSelect as SelectFuga }' もしくは 'import { type HogeSelect as SelectFuga }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
61
|
+
{ code: `import { InputFile as HogeInputFileFuga } from './hoge'`, errors: [ { message: `HogeInputFileFugaを正規表現 "/InputFile$/" がmatchする名称に変更してください。
|
|
62
|
+
- InputFileが型の場合、'import type { InputFile as HogeInputFileFuga }' もしくは 'import { type InputFile as HogeInputFileFuga }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
63
|
+
{ code: `import { HogeRadioButton as FugaRadioButtonAbc } from './hoge'`, errors: [ { message: `FugaRadioButtonAbcを正規表現 "/RadioButton$/" がmatchする名称に変更してください。
|
|
64
|
+
- HogeRadioButtonが型の場合、'import type { HogeRadioButton as FugaRadioButtonAbc }' もしくは 'import { type HogeRadioButton as FugaRadioButtonAbc }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
65
|
+
{ code: `import { CheckBox as FugaCheckBoxHoge } from './hoge'`, errors: [ { message: `FugaCheckBoxHogeを正規表現 "/CheckBox$/" がmatchする名称に変更してください。
|
|
66
|
+
- CheckBoxが型の場合、'import type { CheckBox as FugaCheckBoxHoge }' もしくは 'import { type CheckBox as FugaCheckBoxHoge }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
67
|
+
{ code: `import { HogeComboBox as ComboBoxFuga } from './hoge'`, errors: [ { message: `ComboBoxFugaを正規表現 "/ComboBox$/" がmatchする名称に変更してください。
|
|
68
|
+
- HogeComboBoxが型の場合、'import type { HogeComboBox as ComboBoxFuga }' もしくは 'import { type HogeComboBox as ComboBoxFuga }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
69
|
+
{ code: `import { DatePicker as HogeDatePickerFuga } from './hoge'`, errors: [ { message: `HogeDatePickerFugaを正規表現 "/DatePicker$/" がmatchする名称に変更してください。
|
|
70
|
+
- DatePickerが型の場合、'import type { DatePicker as HogeDatePickerFuga }' もしくは 'import { type DatePicker as HogeDatePickerFuga }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
71
|
+
{ code: `import { HogeDropZone as HogeFugaDropZoneAbc } from './hoge'`, errors: [ { message: `HogeFugaDropZoneAbcを正規表現 "/DropZone$/" がmatchする名称に変更してください。
|
|
72
|
+
- HogeDropZoneが型の場合、'import type { HogeDropZone as HogeFugaDropZoneAbc }' もしくは 'import { type HogeDropZone as HogeFugaDropZoneAbc }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
73
|
+
{ code: 'const Hoge = styled.input``', errors: [ { message: `Hogeを正規表現 "/Input$/" がmatchする名称に変更してください。` } ] },
|
|
74
|
+
{ code: 'const Hoge = styled.Input``', errors: [ { message: `Hogeを正規表現 "/Input$/" がmatchする名称に変更してください。` } ] },
|
|
75
|
+
{ code: 'const Hoge = styled(RadioButton)``', errors: [ { message: `Hogeを正規表現 "/RadioButton$/" がmatchする名称に変更してください。` } ] },
|
|
67
76
|
{ code: '<input />', errors: [ { message: `input にname属性を指定してください${MESSAGE_SUFFIX}` } ] },
|
|
68
77
|
{ code: '<input type="date" />', errors: [ { message: `input にname属性を指定してください${MESSAGE_SUFFIX}` } ] },
|
|
69
78
|
{ code: '<Input type="checkbox" />', errors: [ { message: `Input にname属性を指定してください${MESSAGE_SUFFIX}` } ] },
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
const rule = require('../rules/a11y-input-in-form-control')
|
|
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
|
+
const noLabeledInput = (name) => `${name} を、smarthr-ui/FormControl もしくはそれを拡張したコンポーネントが囲むようマークアップを変更してください。
|
|
16
|
+
- FormControlで入力要素を囲むことでラベルと入力要素が適切に紐づき、操作性が高まります
|
|
17
|
+
- ${name}が入力要素とラベル・タイトル・説明など含む概念を表示するコンポーネントの場合、コンポーネント名を/((FormGroup)$|(FormControl)$|((F|^f)ieldset)$)/とマッチするように修正してください
|
|
18
|
+
- ${name}が入力要素自体を表現するコンポーネントの一部である場合、ルートとなるコンポーネントの名称を/((I|^i)nput$|SearchInput$|(T|^t)extarea$|(S|^s)elect$|InputFile$|Combo(b|B)ox$|DatePicker$|RadioButton$|RadioButtonPanel$|Check(B|b)ox$)/とマッチするように修正してください
|
|
19
|
+
- 上記のいずれの方法も適切では場合、${name}のtitle属性に "どんな値を入力すれば良いのか" の説明を設定してください
|
|
20
|
+
- 例: <${name} title="姓を全角カタカナのみで入力してください" />`
|
|
21
|
+
const noLabeledSelect = (name) => `${name} を、smarthr-ui/FormControl もしくはそれを拡張したコンポーネントが囲むようマークアップを変更してください。
|
|
22
|
+
- FormControlで入力要素を囲むことでラベルと入力要素が適切に紐づき、操作性が高まります
|
|
23
|
+
- ${name}が入力要素とラベル・タイトル・説明など含む概念を表示するコンポーネントの場合、コンポーネント名を/((FormGroup)$|(FormControl)$|((F|^f)ieldset)$)/とマッチするように修正してください
|
|
24
|
+
- ${name}が入力要素自体を表現するコンポーネントの一部である場合、ルートとなるコンポーネントの名称を/((I|^i)nput$|SearchInput$|(T|^t)extarea$|(S|^s)elect$|InputFile$|Combo(b|B)ox$|DatePicker$|RadioButton$|RadioButtonPanel$|Check(B|b)ox$)/とマッチするように修正してください
|
|
25
|
+
- 上記のいずれの方法も適切では場合、${name}のtitle属性に "どんな値を選択すれば良いのか" の説明を設定してください
|
|
26
|
+
- 例: <${name} title="検索対象を選択してください" />`
|
|
27
|
+
const invalidPureCheckboxInFormControl = (name) => `HogeFormControl が ${name} を含んでいます。smarthr-ui/FormControl を smarthr-ui/Fieldset に変更し、正しくグルーピングされるように修正してください。
|
|
28
|
+
- 可能なら${name}はsmarthr-ui/Checkboxへの変更を検討してください。難しい場合は ${name} と結びつくlabel要素が必ず存在するよう、マークアップする必要があることに注意してください。`
|
|
29
|
+
const invalidCheckboxInFormControl = (name) => `HogeFormControl が ${name} を含んでいます。smarthr-ui/FormControl を smarthr-ui/Fieldset に変更し、正しくグルーピングされるように修正してください。`
|
|
30
|
+
const invalidPureRadioInFormControl = (name) => `HogeFormControl が ${name} を含んでいます。smarthr-ui/FormControl を smarthr-ui/Fieldset に変更し、正しくグルーピングされるように修正してください。
|
|
31
|
+
- Fieldsetで同じname属性のラジオボタン全てを囲むことで正しくグループ化され、適切なタイトル・説明を追加出来ます
|
|
32
|
+
- 可能なら${name}はsmarthr-ui/RadioButton、smarthr-ui/RadioButtonPanelへの変更を検討してください。難しい場合は ${name} と結びつくlabel要素が必ず存在するよう、マークアップする必要があることに注意してください。`
|
|
33
|
+
const invalidRadioInFormControl = (name) => `HogeFormControl が ${name} を含んでいます。smarthr-ui/FormControl を smarthr-ui/Fieldset に変更し、正しくグルーピングされるように修正してください。
|
|
34
|
+
- Fieldsetで同じname属性のラジオボタン全てを囲むことで正しくグループ化され、適切なタイトル・説明を追加出来ます`
|
|
35
|
+
const invalidMultiInputsInFormControl = () => `HogeFormControl が複数の入力要素を含んでいます。ラベルと入力要素の紐づけが正しく行われない可能性があるため、以下の方法のいずれかで修正してください。
|
|
36
|
+
- 方法1: 入力要素ごとにラベルを設定できる場合、HogeFormControlをsmarthr-ui/Fieldset、もしくはそれを拡張したコンポーネントに変更した上で、入力要素を一つずつsmarthr-ui/FormControlで囲むようにマークアップを変更してください
|
|
37
|
+
- 方法2: 郵便番号や電話番号など、本来一つの概念の入力要素を分割して複数の入力要素にしている場合、一つの入力要素にまとめることを検討してください
|
|
38
|
+
- コピーアンドペーストがしやすくなる、ブラウザの自動補完などがより適切に反映されるなど多大なメリットがあります
|
|
39
|
+
- 方法3: HogeFormControl が smarthr-ui/FormControl、もしくはそれを拡張しているコンポーネントではない場合、名称を /((FormGroup)$|(FormControl)$|((F|^f)ieldset)$)/ にマッチしないものに変更してください
|
|
40
|
+
- 方法4: 上記方法のいずれも対応出来ない場合、HogeFormControl に 'role="group"' 属性を設定してください`
|
|
41
|
+
const noLabeledInputInFieldset = (name) => `HogeFieldset が ラベルを持たない入力要素(${name})を含んでいます。入力要素が何であるかを正しく伝えるため、以下の方法のいずれかで修正してください。
|
|
42
|
+
- 方法1: HogeFieldset を smarthr-ui/FormControl、もしくはそれを拡張したコンポーネントに変更してください
|
|
43
|
+
- 方法2: ${name} がlabel要素を含むコンポーネントである場合、名称を/(Form(Control|Group))$/にマッチするものに変更してください
|
|
44
|
+
- smarthr-ui/FormControl、smarthr-ui/FormGroup はlabel要素を内包しています
|
|
45
|
+
- 方法3: ${name} がRadioButton、もしくはCheckboxを表すコンポーネントの場合、名称を/(RadioButton$|RadioButtonPanel$|Check(B|b)ox$)/にマッチするものに変更してください
|
|
46
|
+
- smarthr-ui/RadioButton、smarthr-ui/RadioButtonPanel、smarthr-ui/Checkbox はlabel要素を内包しています
|
|
47
|
+
- 方法4: HogeFieldset が smarthr-ui/Fieldset、もしくはそれを拡張しているコンポーネントではない場合、名称を /Fieldset$/ にマッチしないものに変更してください`
|
|
48
|
+
const useFormControlInsteadOfSection = (name, section) => `${name}は${section}より先に、smarthr-ui/FormControlが入力要素を囲むようマークアップを以下のいずれかの方法で変更してください。
|
|
49
|
+
- 方法1: ${section} をFormControl、もしくはそれを拡張したコンポーネントに変更してください
|
|
50
|
+
- ${section} 内のHeading要素はFormControlのtitle属性に変更してください
|
|
51
|
+
- 方法2: ${section} と ${name} の間に FormControl が存在するようにマークアップを変更してください
|
|
52
|
+
- 方法3: 上記のいずれの方法も適切では場合、${name}のtitle属性に "どんな値を入力すれば良いのか" の説明を設定してください
|
|
53
|
+
- 例: <${name} title="姓を全角カタカナのみで入力してください" />`
|
|
54
|
+
const useFormControlInsteadOfSectionInRadio = (name, section) => `${name}は${section}より先に、smarthr-ui/Fieldsetが入力要素を囲むようマークアップを以下のいずれかの方法で変更してください。
|
|
55
|
+
- 方法1: ${section} をFieldset、もしくはそれを拡張したコンポーネントに変更してください
|
|
56
|
+
- ${section} 内のHeading要素はFieldsetのtitle属性に変更してください
|
|
57
|
+
- 方法2: ${section} と ${name} の間に Fieldset が存在するようにマークアップを変更してください`
|
|
58
|
+
const invalidFieldsetHasRoleGroup = (fieldset, base) => `${fieldset}に 'role="group" が設定されています。${base} をつかってマークアップする場合、'role="group"' は不要です
|
|
59
|
+
- ${fieldset} が ${base}、もしくはそれを拡張しているコンポーネントではない場合、名称を /((FormGroup)$|(FormControl)$|((F|^f)ieldset)$)/ にマッチしないものに変更してください`
|
|
60
|
+
const invalidChildreninFormControl = (children) => `FormControl が、${children} を子要素として持っており、マークアップとして正しくない状態になっています。以下のいずれかの方法で修正を試みてください。
|
|
61
|
+
- 方法1: 親要素であるFormControlをsmarthr-ui/FormControl、もしくはそれを拡張していないコンポーネントでマークアップしてください
|
|
62
|
+
- FormControlではなく、smarthr-ui/Fieldset、もしくはsmarthr-ui/Section + smarthr-ui/Heading などでのマークアップを検討してください
|
|
63
|
+
- 方法2: 親要素であるFormControlがsmarthr-ui/FormControlを拡張したコンポーネントではない場合、コンポーネント名を/(Form(Control|Group))$/と一致しない名称に変更してください`
|
|
64
|
+
const requireMultiInputInFormControlWithRoleGroup = () => `HogeFormControl内に入力要素が2個以上存在しないため、'role=\"group\"'を削除してください。'role=\"group\"'は複数の入力要素を一つのグループとして扱うための属性です。
|
|
65
|
+
- HogeFormControl内に2つ以上の入力要素が存在する場合、入力要素を含むコンポーネント名全てを/((I|^i)nput$|SearchInput$|(T|^t)extarea$|(S|^s)elect$|InputFile$|Combo(b|B)ox$|DatePicker$|RadioButton$|RadioButtonPanel$|Check(B|b)ox$)/、もしくは/((FormGroup)$|(FormControl)$|((F|^f)ieldset)$)/にマッチする名称に変更してください`
|
|
66
|
+
|
|
67
|
+
ruleTester.run('a11y-input-in-form-control', rule, {
|
|
68
|
+
valid: [
|
|
69
|
+
{ code: `import styled from 'styled-components'` },
|
|
70
|
+
{ code: `import styled, { css } from 'styled-components'` },
|
|
71
|
+
{ code: `import { css } from 'styled-components'` },
|
|
72
|
+
{ code: `import { HogeAInput as FugaInput } from './hoge'` },
|
|
73
|
+
{ code: `import { Textarea as HogeTextarea } from './hoge'` },
|
|
74
|
+
{ code: 'const HogeInput = styled.input``' },
|
|
75
|
+
{ code: 'const HogeTextarea = styled.textarea``' },
|
|
76
|
+
{ code: 'const HogeSelect = styled(Select)``' },
|
|
77
|
+
{ code: 'const HogeRadioButton = styled(FugaRadioButton)``' },
|
|
78
|
+
{ code: 'const HogeRadioButtonPanel = styled(FugaRadioButtonPanel)``' },
|
|
79
|
+
{ code: 'const HogeCheckBox = styled(FugaCheckbox)``' },
|
|
80
|
+
{ code: 'const DatePicker = styled(AnyDatePicker)``' },
|
|
81
|
+
{ code: '<input title="any"/>' },
|
|
82
|
+
{ code: '<HogeInput title="any"/>' },
|
|
83
|
+
{ code: '<textarea title="any"/>' },
|
|
84
|
+
{ code: '<HogeTextarea title="any"/>' },
|
|
85
|
+
{ code: '<select title="any"/>' },
|
|
86
|
+
{ code: '<HogeSelect title="any"/>' },
|
|
87
|
+
{ code: '<HogeInputFile title="any"/>' },
|
|
88
|
+
{ code: '<HogeComboBox title="any"/>' },
|
|
89
|
+
{ code: '<HogeDatePicker title="any"/>' },
|
|
90
|
+
{ code: '<HogeFormGroup />' },
|
|
91
|
+
{ code: '<HogeFormControl />' },
|
|
92
|
+
{ code: '<HogeFieldset />' },
|
|
93
|
+
{ code: '<HogeFormGroup><input /></HogeFormGroup>' },
|
|
94
|
+
{ code: '<HogeFormGroup><input title="any" /></HogeFormGroup>' },
|
|
95
|
+
{ code: '<HogeFormGroup><Input type="checkbox" /></HogeFormGroup>' },
|
|
96
|
+
{ code: '<HogeFormGroup><CheckBox /></HogeFormGroup>' },
|
|
97
|
+
{ code: '<HogeFormControl><HogeSelect /></HogeFormControl>' },
|
|
98
|
+
{ code: '<HogeFormControl><HogeComboBox title="any" /></HogeFormControl>' },
|
|
99
|
+
{ code: '<HogeFieldset><Input type="checkbox" /><Input type="checkbox" /></HogeFieldset>' },
|
|
100
|
+
{ code: '<HogeFieldset><HogeCheckBox /><HogeCheckBox /></HogeFieldset>' },
|
|
101
|
+
{ code: '<HogeFieldset><input type="radio" /></HogeFieldset>' },
|
|
102
|
+
{ code: '<HogeFieldset><RadioButton /></HogeFieldset>' },
|
|
103
|
+
{ code: '<HogeFieldset><HogeRadioButtonPanel /></HogeFieldset>' },
|
|
104
|
+
{ code: '<HogeFormControl role="group"><HogeInput /><HogeSelect /></HogeFormControl>' },
|
|
105
|
+
{ code: '<FugaSection><HogeFormControl><HogeInput /></HogeFormControl></FugaSection>' },
|
|
106
|
+
{ code: '<Stack as="section"><HogeFormControl><HogeInput /></HogeFormControl></Stack>' },
|
|
107
|
+
{ code: `const AnyComboBox = () => <input />` },
|
|
108
|
+
{ code: `<Fieldset><HogeFieldset /><HogeFormControl /></Fieldset>` },
|
|
109
|
+
{ code: '<HogeFieldset><HogeCheckBox /><HogeInput id="any" /></HogeFieldset>' },
|
|
110
|
+
{ code: '<FugaSection><HogeInput id="any" /></FugaSection>' },
|
|
111
|
+
{ code: '<HogeTextarea id="any" />' },
|
|
112
|
+
{ code: '<HogeFieldset><HogeCheckBox /><HogeInput title="any" /></HogeFieldset>' },
|
|
113
|
+
{ code: '<FugaSection><HogeInput title="any" /></FugaSection>' },
|
|
114
|
+
{ code: '<HogeTextarea title="any" />' },
|
|
115
|
+
],
|
|
116
|
+
invalid: [
|
|
117
|
+
{ code: `import hoge from 'styled-components'`, errors: [ { message: `styled-components をimportする際は、名称が"styled" となるようにしてください。例: "import styled from 'styled-components'"` } ] },
|
|
118
|
+
{ code: `import { ComboBox as ComboBoxHoge } from './hoge'`, errors: [ { message: `ComboBoxHogeを正規表現 "/(ComboBox)$/" がmatchする名称に変更してください。
|
|
119
|
+
- ComboBoxが型の場合、'import type { ComboBox as ComboBoxHoge }' もしくは 'import { type ComboBox as ComboBoxHoge }' のように明示的に型であることを宣言してください。名称変更が不要になります` } ] },
|
|
120
|
+
{ code: 'const RadioButton = styled(FugaRadioButtonPanel)``', errors: [
|
|
121
|
+
{ message: `RadioButtonを正規表現 "/(RadioButtonPanel)$/" がmatchする名称に変更してください。` },
|
|
122
|
+
{ message: `RadioButton は /RadioButton$/ にmatchする名前のコンポーネントを拡張することを期待している名称になっています
|
|
123
|
+
- RadioButton の名称の末尾が"RadioButton" という文字列ではない状態にしつつ、"FugaRadioButtonPanel"を継承していることをわかる名称に変更してください
|
|
124
|
+
- もしくは"FugaRadioButtonPanel"を"RadioButton"の継承元であることがわかるような名称に変更するか、適切な別コンポーネントに差し替えてください
|
|
125
|
+
- 修正例1: const Xxxx = styled(FugaRadioButtonPanel)
|
|
126
|
+
- 修正例2: const RadioButtonXxxx = styled(FugaRadioButtonPanel)
|
|
127
|
+
- 修正例3: const RadioButton = styled(XxxxRadioButton)` } ] },
|
|
128
|
+
{ code: `<input />`, errors: [ { message: noLabeledInput('input') } ] },
|
|
129
|
+
{ code: `<HogeInput />`, errors: [ { message: noLabeledInput('HogeInput') } ] },
|
|
130
|
+
{ code: '<textarea />', errors: [ { message: noLabeledInput('textarea') } ] },
|
|
131
|
+
{ code: '<HogeTextarea />', errors: [ { message: noLabeledInput('HogeTextarea') } ] },
|
|
132
|
+
{ code: '<select />', errors: [ { message: noLabeledSelect('select') } ] },
|
|
133
|
+
{ code: '<HogeSelect />', errors: [ { message: noLabeledSelect('HogeSelect') } ] },
|
|
134
|
+
{ code: '<HogeInputFile />', errors: [ { message: noLabeledInput('HogeInputFile') } ] },
|
|
135
|
+
{ code: '<HogeComboBox />', errors: [ { message: noLabeledInput('HogeComboBox') } ] },
|
|
136
|
+
{ code: '<HogeDatePicker />', errors: [ { message: noLabeledInput('HogeDatePicker') } ] },
|
|
137
|
+
{ code: '<HogeFormControl><Input type="checkbox" /><Input type="checkbox" /></HogeFormControl>', errors: [ { message: invalidPureCheckboxInFormControl('Input') } ] },
|
|
138
|
+
{ code: '<HogeFormControl><HogeCheckBox /><Input /></HogeFormControl>', errors: [ { message: invalidMultiInputsInFormControl() } ] },
|
|
139
|
+
{ code: '<HogeFormControl><HogeCheckBox /><HogeCheckBox /></HogeFormControl>', errors: [ { message: invalidCheckboxInFormControl('HogeCheckBox') } ] },
|
|
140
|
+
{ code: '<HogeFormControl><input type="radio" /></HogeFormControl>', errors: [ { message: invalidPureRadioInFormControl('input') } ] },
|
|
141
|
+
{ code: '<HogeFormControl><RadioButton /></HogeFormControl>', errors: [ { message: invalidRadioInFormControl('RadioButton') } ] },
|
|
142
|
+
{ code: '<HogeFormControl><HogeRadioButtonPanel /></HogeFormControl>', errors: [ { message: invalidRadioInFormControl('HogeRadioButtonPanel') } ] },
|
|
143
|
+
{ code: '<HogeFieldset><HogeCheckBox /><HogeInput /></HogeFieldset>', errors: [ { message: noLabeledInputInFieldset('HogeInput') } ] },
|
|
144
|
+
{ code: '<FugaSection><HogeInput /></FugaSection>', errors: [ { message: useFormControlInsteadOfSection('HogeInput', 'FugaSection') } ] },
|
|
145
|
+
{ code: '<Stack as="section"><HogeInput /></Stack>', errors: [ { message: useFormControlInsteadOfSection('HogeInput', '<Stack as="section">') } ] },
|
|
146
|
+
{ code: '<Center forwardedAs="aside"><HogeInput /></Center>', errors: [ { message: useFormControlInsteadOfSection('HogeInput', '<Center forwardedAs="aside">') } ] },
|
|
147
|
+
{ code: '<FugaSection><HogeRadioButton /></FugaSection>', errors: [ { message: useFormControlInsteadOfSectionInRadio('HogeRadioButton', 'FugaSection') } ] },
|
|
148
|
+
{ code: `const AnyHoge = () => <input />`, errors: [ { message: noLabeledInput('input') } ] },
|
|
149
|
+
{ code: '<HogeFieldset role="group"><HogeFormControl /><HogeRadioButton /></HogeFieldset>', errors: [ { message: invalidFieldsetHasRoleGroup('HogeFieldset', 'smarthr-ui/Fieldset') } ] },
|
|
150
|
+
{ code: '<fieldset role="group"><HogeFormControl /><HogeRadioButton /></fieldset>', errors: [ { message: invalidFieldsetHasRoleGroup('fieldset', 'fieldset') } ] },
|
|
151
|
+
{ code: '<FormControl><HogeFieldset /></FormControl>', errors: [ { message: invalidChildreninFormControl('HogeFieldset') } ] },
|
|
152
|
+
{ code: '<FormControl><HogeFormControl /></FormControl>', errors: [ { message: invalidChildreninFormControl('HogeFormControl') } ] },
|
|
153
|
+
{ code: '<HogeFormControl role="group"><HogeInput /></HogeFormControl>', errors: [ { message: requireMultiInputInFormControlWithRoleGroup() } ] },
|
|
154
|
+
]
|
|
155
|
+
})
|