eslint-plugin-smarthr 0.2.3 → 0.2.4
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 +7 -0
- package/libs/common.js +1 -1
- package/package.json +1 -1
- package/rules/a11y-clickable-element-has-text/index.js +12 -17
- package/rules/a11y-trigger-has-button/index.js +16 -2
- package/rules/redundant-name/index.js +13 -13
- package/rules/require-barrel-import/index.js +1 -1
- package/test/a11y-clickable-element-has-text.js +13 -0
- package/test/a11y-trigger-has-button.js +15 -13
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
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.2.4](https://github.com/kufu/eslint-plugin-smarthr/compare/v0.2.3...v0.2.4) (2022-08-30)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* ruleを更新する ([#27](https://github.com/kufu/eslint-plugin-smarthr/issues/27)) ([1ec7783](https://github.com/kufu/eslint-plugin-smarthr/commit/1ec7783395c9dafa547c453724f3671df489997b))
|
|
11
|
+
|
|
5
12
|
### [0.2.3](https://github.com/kufu/eslint-plugin-smarthr/compare/v0.2.2...v0.2.3) (2022-08-26)
|
|
6
13
|
|
|
7
14
|
|
package/libs/common.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const { generateTagFormatter } = require('../../libs/format_styled_components')
|
|
2
2
|
|
|
3
3
|
const EXPECTED_NAMES = {
|
|
4
|
+
'SmartHRLogo$': 'SmartHRLogo$',
|
|
4
5
|
'(b|B)utton$': 'Button$',
|
|
5
6
|
'Anchor$': 'Anchor$',
|
|
6
7
|
'Link$': 'Link$',
|
|
@@ -35,23 +36,17 @@ module.exports = {
|
|
|
35
36
|
return
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
const recursiveSearch = (c) =>
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
return true
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return false
|
|
54
|
-
}
|
|
39
|
+
const recursiveSearch = (c) => (
|
|
40
|
+
['JSXText', 'JSXExpressionContainer'].includes(c.type) ||
|
|
41
|
+
(
|
|
42
|
+
c.type === 'JSXElement' && (
|
|
43
|
+
// HINT: SmartHRLogo コンポーネントは内部でaltを持っているため対象外にする
|
|
44
|
+
c.openingElement.name.name.match(/SmartHRLogo$/) ||
|
|
45
|
+
c.openingElement.attributes.some((a) => (['visuallyHiddenText', 'alt'].includes(a.name.name) && !!a.value.value)) ||
|
|
46
|
+
(c.children && filterFalsyJSXText(c.children).some(recursiveSearch))
|
|
47
|
+
)
|
|
48
|
+
)
|
|
49
|
+
)
|
|
55
50
|
|
|
56
51
|
const child = filterFalsyJSXText(parentNode.children).find(recursiveSearch)
|
|
57
52
|
|
|
@@ -47,7 +47,21 @@ module.exports = {
|
|
|
47
47
|
return
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
filterFalsyJSXText(parentNode.children)
|
|
50
|
+
const children = filterFalsyJSXText(parentNode.children)
|
|
51
|
+
|
|
52
|
+
if (children.length > 1) {
|
|
53
|
+
context.report({
|
|
54
|
+
node,
|
|
55
|
+
messageId: 'a11y-trigger-has-button',
|
|
56
|
+
data: {
|
|
57
|
+
message: `${match[1]}Trigger の直下には複数のコンポーネントを設置することは出来ません。buttonコンポーネントが一つだけ設置されている状態にしてください`,
|
|
58
|
+
},
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
children.forEach((c) => {
|
|
51
65
|
// `<DialogTrigger>{button}</DialogTrigger>` のような場合は許可する
|
|
52
66
|
if (c.type === 'JSXExpressionContainer') {
|
|
53
67
|
return false
|
|
@@ -56,7 +70,7 @@ module.exports = {
|
|
|
56
70
|
if (
|
|
57
71
|
c.type !== 'JSXElement' ||
|
|
58
72
|
!c.openingElement.name.name.match(/(b|B)utton$/) ||
|
|
59
|
-
c.openingElement.name.name.match(/AnchorButton
|
|
73
|
+
c.openingElement.name.name.match(/AnchorButton$/)
|
|
60
74
|
) {
|
|
61
75
|
context.report({
|
|
62
76
|
node: c,
|
|
@@ -16,7 +16,6 @@ const DEFAULT_CONFIG = {
|
|
|
16
16
|
],
|
|
17
17
|
SUFFIX: ['Props', 'Type'],
|
|
18
18
|
},
|
|
19
|
-
typeProperty: COMMON_DEFAULT_CONFIG,
|
|
20
19
|
file: COMMON_DEFAULT_CONFIG,
|
|
21
20
|
property: COMMON_DEFAULT_CONFIG,
|
|
22
21
|
function: COMMON_DEFAULT_CONFIG,
|
|
@@ -62,7 +61,6 @@ const SCHEMA = [
|
|
|
62
61
|
...DEFAULT_SCHEMA_PROPERTY,
|
|
63
62
|
suffix: { type: 'array', items: { type: 'string' } },
|
|
64
63
|
},
|
|
65
|
-
typeProperty: DEFAULT_SCHEMA_PROPERTY,
|
|
66
64
|
file: DEFAULT_SCHEMA_PROPERTY,
|
|
67
65
|
property: DEFAULT_SCHEMA_PROPERTY,
|
|
68
66
|
function: DEFAULT_SCHEMA_PROPERTY,
|
|
@@ -89,7 +87,6 @@ const generateRedundantKeywords = ({ args, key, terminalImportName }) => {
|
|
|
89
87
|
const option = args.option[key] || {}
|
|
90
88
|
const ignoreKeywords = option.ignoreKeywords || DEFAULT_CONFIG[key].IGNORE_KEYWORDS
|
|
91
89
|
const terminalImportKeyword = terminalImportName ? terminalImportName.toLowerCase() : ''
|
|
92
|
-
|
|
93
90
|
return args.keywords.reduce((prev, keyword) => {
|
|
94
91
|
if (keyword === terminalImportKeyword || ignoreKeywords.includes(keyword)) {
|
|
95
92
|
return prev
|
|
@@ -262,8 +259,7 @@ const generateTypeRedundant = (args) => {
|
|
|
262
259
|
}
|
|
263
260
|
|
|
264
261
|
const generateTypePropertyRedundant = (args) => {
|
|
265
|
-
const key = '
|
|
266
|
-
|
|
262
|
+
const key = 'property'
|
|
267
263
|
return handleReportBetterName({
|
|
268
264
|
...args,
|
|
269
265
|
key,
|
|
@@ -274,7 +270,7 @@ const generateTypePropertyRedundant = (args) => {
|
|
|
274
270
|
})
|
|
275
271
|
}
|
|
276
272
|
const generateTypePropertyFunctionParamsRedundant = (args) => {
|
|
277
|
-
const key = '
|
|
273
|
+
const key = 'property'
|
|
278
274
|
const redundant = handleReportBetterName({
|
|
279
275
|
...args,
|
|
280
276
|
key,
|
|
@@ -298,7 +294,15 @@ const generatePropertyRedundant = (args) => {
|
|
|
298
294
|
option: args.option[key],
|
|
299
295
|
redundantKeywords: generateRedundantKeywords({ args, key }),
|
|
300
296
|
defaultBetterName: 'item',
|
|
301
|
-
fetchName: (node) =>
|
|
297
|
+
fetchName: (node) => {
|
|
298
|
+
// argumentsとしてわたされたobjectの展開などの場合は許可する
|
|
299
|
+
// このファイル内で修正すべき場合などは冗長な名前を修正するべき場合はtype propertyなどで判断出来る
|
|
300
|
+
if (node.parent.type === 'ObjectPattern') {
|
|
301
|
+
return null
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return node.key.name
|
|
305
|
+
},
|
|
302
306
|
})
|
|
303
307
|
}
|
|
304
308
|
|
|
@@ -391,7 +395,6 @@ module.exports = {
|
|
|
391
395
|
'file-name': ' {{ message }}',
|
|
392
396
|
'type-name': '{{ message }}',
|
|
393
397
|
'type-name/invalid-suffix': '{{ message }}',
|
|
394
|
-
'typeProperty-name': '{{ message }}',
|
|
395
398
|
'property-name': ' {{ message }}',
|
|
396
399
|
'function-name': ' {{ message }}',
|
|
397
400
|
'functionParams-name': ' {{ message }}',
|
|
@@ -449,9 +452,10 @@ module.exports = {
|
|
|
449
452
|
addRule('TSTypeAliasDeclaration', generateTypeRedundant(args))
|
|
450
453
|
// addRule('TSInterfaceDeclaration', generateTypeRedundant(args)) // 必要になったら実装する
|
|
451
454
|
}
|
|
452
|
-
if (option.
|
|
455
|
+
if (option.property) {
|
|
453
456
|
const typePropRedundant = generateTypePropertyRedundant(args)
|
|
454
457
|
const typeFuncParamRedundant = generateTypePropertyFunctionParamsRedundant(args)
|
|
458
|
+
const redundant = generatePropertyRedundant(args)
|
|
455
459
|
|
|
456
460
|
addRule('TSPropertySignature', (node) => {
|
|
457
461
|
typePropRedundant(node)
|
|
@@ -460,10 +464,6 @@ module.exports = {
|
|
|
460
464
|
typeFuncParamRedundant(node.typeAnnotation.typeAnnotation)
|
|
461
465
|
}
|
|
462
466
|
})
|
|
463
|
-
}
|
|
464
|
-
if (option.property) {
|
|
465
|
-
const redundant = generatePropertyRedundant(args)
|
|
466
|
-
|
|
467
467
|
addRule('Property', redundant)
|
|
468
468
|
addRule('PropertyDefinition', redundant)
|
|
469
469
|
}
|
|
@@ -26,6 +26,7 @@ ruleTester.run('a11y-clickable-element-has-text', rule, {
|
|
|
26
26
|
{ code: 'const HogeLink = styled(Link)``' },
|
|
27
27
|
{ code: 'const HogeButton = styled(Button)``' },
|
|
28
28
|
{ code: 'const FugaAnchor = styled(HogeAnchor)``' },
|
|
29
|
+
{ code: 'const FugaSmartHRLogo = styled(SmartHRLogo)``' },
|
|
29
30
|
{
|
|
30
31
|
code: `<a>ほげ</a>`,
|
|
31
32
|
},
|
|
@@ -89,6 +90,12 @@ ruleTester.run('a11y-clickable-element-has-text', rule, {
|
|
|
89
90
|
{
|
|
90
91
|
code: `<a><span>{any}</span></a>`,
|
|
91
92
|
},
|
|
93
|
+
{
|
|
94
|
+
code: `<a><SmartHRLogo /></a>`,
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
code: `<a><PrefixSmartHRLogo /></a>`,
|
|
98
|
+
},
|
|
92
99
|
],
|
|
93
100
|
invalid: [
|
|
94
101
|
{ code: `import hoge from 'styled-components'`, errors: [ { message: "styled-components をimportする際は、名称が`styled` となるようにしてください。例: `import styled from 'styled-components'`" } ] },
|
|
@@ -98,6 +105,8 @@ ruleTester.run('a11y-clickable-element-has-text', rule, {
|
|
|
98
105
|
{ code: 'const Hoge = styled(Link)``', errors: [ { message: `Hogeを正規表現 "/Link$/" がmatchする名称に変更してください` } ] },
|
|
99
106
|
{ code: 'const Hoge = styled(Button)``', errors: [ { message: `Hogeを正規表現 "/Button$/" がmatchする名称に変更してください` } ] },
|
|
100
107
|
{ code: 'const Fuga = styled(HogeAnchor)``', errors: [ { message: `Fugaを正規表現 "/Anchor$/" がmatchする名称に変更してください` } ] },
|
|
108
|
+
{ code: 'const Fuga = styled(HogeAnchor)``', errors: [ { message: `Fugaを正規表現 "/Anchor$/" がmatchする名称に変更してください` } ] },
|
|
109
|
+
{ code: 'const Fuga = styled(SmartHRLogo)``', errors: [ { message: `Fugaを正規表現 "/SmartHRLogo$/" がmatchする名称に変更してください` } ] },
|
|
101
110
|
{
|
|
102
111
|
code: `<a><img src="hoge.jpg" /></a>`,
|
|
103
112
|
errors: [{ message: defaultErrorMessage }]
|
|
@@ -138,5 +147,9 @@ ruleTester.run('a11y-clickable-element-has-text', rule, {
|
|
|
138
147
|
code: `<button><AnyComponent><Icon visuallyHiddenText="" /></AnyComponent></button>`,
|
|
139
148
|
errors: [{ message: defaultErrorMessage }]
|
|
140
149
|
},
|
|
150
|
+
{
|
|
151
|
+
code: `<button><SmartHRLogoSuffix /></button>`,
|
|
152
|
+
errors: [{ message: defaultErrorMessage }]
|
|
153
|
+
},
|
|
141
154
|
]
|
|
142
155
|
})
|
|
@@ -33,18 +33,20 @@ ruleTester.run('a11y-trigger-has-button', rule, {
|
|
|
33
33
|
],
|
|
34
34
|
invalid: [
|
|
35
35
|
{ code: `import hoge from 'styled-components'`, errors: [ { message: "styled-components をimportする際は、名称が`styled` となるようにしてください。例: `import styled from 'styled-components'`" } ] },
|
|
36
|
-
{ code: 'const Hoge = styled.button``', errors: [ { message: `Hogeを正規表現 "/Button$/" がmatchする名称に変更してください` } ]
|
|
37
|
-
{ code: 'const Hoge = styled.a``', errors: [ { message: `Hogeを正規表現 "/(Anchor|Link)$/" がmatchする名称に変更してください` } ]
|
|
38
|
-
{ code: 'const Hoge = styled(Button)``', errors: [ { message: `Hogeを正規表現 "/Button$/" がmatchする名称に変更してください` } ]
|
|
39
|
-
{ code: 'const Hoge = styled(AnchorButton)``', errors: [ { message: `Hogeを正規表現 "/Button$/" がmatchする名称に変更してください` },{ message: `Hogeを正規表現 "/AnchorButton$/" がmatchする名称に変更してください` } ]
|
|
40
|
-
{ code: 'const Hoge = styled(ButtonAnchor)``', errors: [ { message: `Hogeを正規表現 "/ButtonAnchor$/" がmatchする名称に変更してください` }, { message: `Hogeを正規表現 "/Anchor$/" がmatchする名称に変更してください` } ]
|
|
41
|
-
{ code: 'const Hoge = styled(Anchor)``', errors: [ { message: `Hogeを正規表現 "/Anchor$/" がmatchする名称に変更してください` } ]
|
|
42
|
-
{ code: 'const Hoge = styled(Link)``', errors: [ { message: `Hogeを正規表現 "/Link$/" がmatchする名称に変更してください` } ]
|
|
43
|
-
{ code: 'const Hoge = styled(DropdownTrigger)``', errors: [ { message: `Hogeを正規表現 "/DropdownTrigger$/" がmatchする名称に変更してください` } ]
|
|
44
|
-
{ code: 'const Hoge = styled(DialogTrigger)``', errors: [ { message: `Hogeを正規表現 "/DialogTrigger$/" がmatchする名称に変更してください` } ]
|
|
45
|
-
{ code: '<DropdownTrigger>ほげ</DropdownTrigger>', errors: [ { message: 'DropdownTrigger の直下にはbuttonコンポーネントのみ設置してください' } ]
|
|
46
|
-
{ code: '<DialogTrigger><span><Button>ほげ</Button></span></DialogTrigger>', errors: [ { message: 'DialogTrigger の直下にはbuttonコンポーネントのみ設置してください' } ]
|
|
47
|
-
{ code: '<DropdownTrigger><AnchorButton>ほげ</AnchorButton></DropdownTrigger>', errors: [ { message: 'DropdownTrigger の直下にはbuttonコンポーネントのみ設置してください' } ]
|
|
48
|
-
{ code: '<DropdownTrigger><ButtonAnchor>ほげ</ButtonAnchor></DropdownTrigger>', errors: [ { message: 'DropdownTrigger の直下にはbuttonコンポーネントのみ設置してください' } ]
|
|
36
|
+
{ code: 'const Hoge = styled.button``', errors: [ { message: `Hogeを正規表現 "/Button$/" がmatchする名称に変更してください` } ] },
|
|
37
|
+
{ code: 'const Hoge = styled.a``', errors: [ { message: `Hogeを正規表現 "/(Anchor|Link)$/" がmatchする名称に変更してください` } ] },
|
|
38
|
+
{ code: 'const Hoge = styled(Button)``', errors: [ { message: `Hogeを正規表現 "/Button$/" がmatchする名称に変更してください` } ] },
|
|
39
|
+
{ code: 'const Hoge = styled(AnchorButton)``', errors: [ { message: `Hogeを正規表現 "/Button$/" がmatchする名称に変更してください` },{ message: `Hogeを正規表現 "/AnchorButton$/" がmatchする名称に変更してください` } ] },
|
|
40
|
+
{ code: 'const Hoge = styled(ButtonAnchor)``', errors: [ { message: `Hogeを正規表現 "/ButtonAnchor$/" がmatchする名称に変更してください` }, { message: `Hogeを正規表現 "/Anchor$/" がmatchする名称に変更してください` } ] },
|
|
41
|
+
{ code: 'const Hoge = styled(Anchor)``', errors: [ { message: `Hogeを正規表現 "/Anchor$/" がmatchする名称に変更してください` } ] },
|
|
42
|
+
{ code: 'const Hoge = styled(Link)``', errors: [ { message: `Hogeを正規表現 "/Link$/" がmatchする名称に変更してください` } ] },
|
|
43
|
+
{ code: 'const Hoge = styled(DropdownTrigger)``', errors: [ { message: `Hogeを正規表現 "/DropdownTrigger$/" がmatchする名称に変更してください` } ] },
|
|
44
|
+
{ code: 'const Hoge = styled(DialogTrigger)``', errors: [ { message: `Hogeを正規表現 "/DialogTrigger$/" がmatchする名称に変更してください` } ] },
|
|
45
|
+
{ code: '<DropdownTrigger>ほげ</DropdownTrigger>', errors: [ { message: 'DropdownTrigger の直下にはbuttonコンポーネントのみ設置してください' } ] },
|
|
46
|
+
{ code: '<DialogTrigger><span><Button>ほげ</Button></span></DialogTrigger>', errors: [ { message: 'DialogTrigger の直下にはbuttonコンポーネントのみ設置してください' } ] },
|
|
47
|
+
{ code: '<DropdownTrigger><AnchorButton>ほげ</AnchorButton></DropdownTrigger>', errors: [ { message: 'DropdownTrigger の直下にはbuttonコンポーネントのみ設置してください' } ] },
|
|
48
|
+
{ code: '<DropdownTrigger><ButtonAnchor>ほげ</ButtonAnchor></DropdownTrigger>', errors: [ { message: 'DropdownTrigger の直下にはbuttonコンポーネントのみ設置してください' } ] },
|
|
49
|
+
{ code: '<DialogTrigger><button>{hoge}</button>{hoge}</DialogTrigger>', errors: [ { message: 'DialogTrigger の直下には複数のコンポーネントを設置することは出来ません。buttonコンポーネントが一つだけ設置されている状態にしてください' } ] },
|
|
50
|
+
{ code: '<DropdownTrigger>{hoge}<span>text</span></DropdownTrigger>', errors: [ { message: 'DropdownTrigger の直下には複数のコンポーネントを設置することは出来ません。buttonコンポーネントが一つだけ設置されている状態にしてください' } ] },
|
|
49
51
|
]
|
|
50
52
|
})
|