eslint-plugin-smarthr 0.5.6 → 0.5.7

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 CHANGED
@@ -2,6 +2,14 @@
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.5.7](https://github.com/kufu/eslint-plugin-smarthr/compare/v0.5.6...v0.5.7) (2024-04-01)
6
+
7
+
8
+ ### Features
9
+
10
+ * a11y-delegate-element-has-role-presentationでas, forwardedAsにform, fieldsetが指定されている場合、インタファクティブな要素として扱うように修正 ([#132](https://github.com/kufu/eslint-plugin-smarthr/issues/132)) ([3d629fa](https://github.com/kufu/eslint-plugin-smarthr/commit/3d629fa73e7346c229831a0075478fcbfe582de1))
11
+ * a11y-replace-unreadable-symbol ([#128](https://github.com/kufu/eslint-plugin-smarthr/issues/128)) ([9410ff9](https://github.com/kufu/eslint-plugin-smarthr/commit/9410ff9ad9ed5a0d18945e3567a1fee8c056f822))
12
+
5
13
  ### [0.5.6](https://github.com/kufu/eslint-plugin-smarthr/compare/v0.5.5...v0.5.6) (2024-03-29)
6
14
 
7
15
 
package/README.md CHANGED
@@ -11,6 +11,7 @@
11
11
  - [a11y-numbered-text-within-ol](https://github.com/kufu/eslint-plugin-smarthr/tree/main/rules/a11y-numbered-text-within-ol)
12
12
  - [a11y-prohibit-input-placeholder](https://github.com/kufu/eslint-plugin-smarthr/tree/main/rules/a11y-prohibit-input-placeholder)
13
13
  - [a11y-prohibit-useless-sectioning-fragment](https://github.com/kufu/eslint-plugin-smarthr/tree/main/rules/a11y-prohibit-useless-sectioning-fragment)
14
+ - [a11y-replace-unreadable-symbol](https://github.com/kufu/eslint-plugin-smarthr/tree/main/rules/a11y-replace-unreadable-symbol)
14
15
  - [a11y-trigger-has-button](https://github.com/kufu/eslint-plugin-smarthr/tree/main/rules/a11y-trigger-has-button)
15
16
  - [best-practice-for-button-element](https://github.com/kufu/eslint-plugin-smarthr/tree/main/rules/best-practice-for-button-element)
16
17
  - [best-practice-for-date](https://github.com/kufu/eslint-plugin-smarthr/tree/main/rules/best-practice-for-date)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-smarthr",
3
- "version": "0.5.6",
3
+ "version": "0.5.7",
4
4
  "author": "SmartHR",
5
5
  "license": "MIT",
6
6
  "description": "A sharable ESLint plugin for SmartHR",
@@ -43,6 +43,8 @@ const INTERACTIVE_COMPONENT_NAMES = Object.keys(EXPECTED_NAMES).join('|')
43
43
  const INTERACTIVE_ON_REGEX = /^on(Change|Input|Focus|Blur|(Double)?Click|Key(Down|Up|Press)|Mouse(Enter|Over|Down|Up|Leave)|Select|Submit)$/
44
44
  const MEANED_ROLE_REGEX = /^(combobox|group|slider|toolbar)$/
45
45
  const INTERACTIVE_NODE_TYPE_REGEX = /^(JSXElement|JSXExpressionContainer|ConditionalExpression)$/
46
+ const AS_REGEX = /^(as|forwardedAs)$/
47
+ const AS_VALUE_REGEX = /^(form|fieldset)$/
46
48
 
47
49
  const messageNonInteractiveEventHandler = (nodeName, interactiveComponentRegex, onAttrs) => {
48
50
  const onAttrsText = onAttrs.join(', ')
@@ -122,12 +124,15 @@ module.exports = {
122
124
  let onAttrs = []
123
125
  let roleMean = undefined
124
126
  let isRolePresentation = false
127
+ let isAsInteractive = false
125
128
 
126
129
  node.attributes.forEach((a) => {
127
130
  const aName = a.name?.name || ''
128
131
 
129
132
  if (aName.match(INTERACTIVE_ON_REGEX)) {
130
133
  onAttrs.push(aName)
134
+ } else if (AS_REGEX.test(aName) && AS_VALUE_REGEX.test(a.value?.value || '')) {
135
+ isAsInteractive = true
131
136
  } else if (aName === 'role') {
132
137
  const v = a.value?.value || ''
133
138
 
@@ -140,7 +145,7 @@ module.exports = {
140
145
  }
141
146
  })
142
147
 
143
- if (nodeName.match(interactiveComponentRegex)) {
148
+ if (isAsInteractive || nodeName.match(interactiveComponentRegex)) {
144
149
  if (isRolePresentation) {
145
150
  context.report({
146
151
  node,
@@ -0,0 +1,38 @@
1
+ # smarthr/a11y-replace-unreadable-symbol
2
+
3
+ - 一部記号はスクリーンリーダーで読み上げられない、もしくは記号名そのままで読み上げられてしまい、意図が正しく伝えられない場合があります
4
+ - それらの記号を適切に読み上げられるコンポーネントに置き換えることを促すルールです
5
+
6
+ ## rules
7
+
8
+ ```js
9
+ {
10
+ rules: {
11
+ 'smarthr/a11y-replace-unreadable-symbol': 'error', // 'warn', 'off',
12
+ },
13
+ }
14
+ ```
15
+
16
+ ## ❌ Incorrect
17
+
18
+ ```jsx
19
+ <>XXXX年YY月ZZ日 〜 XXXX年YY月ZZ日</>
20
+ // スクリーンリーダーは "XXXX年YY月ZZ日XXXX年YY月ZZ日" と読み上げる場合があります
21
+
22
+ <p>選択できる数値の範囲は 0 ~ 9999 です</p>
23
+ // スクリーンリーダーは "選択できる数値の範囲は09999です" と読み上げる場合があります
24
+ ```
25
+
26
+ ## ✅ Correct
27
+
28
+ ```jsx
29
+ //
30
+ <>XXXX年YY月ZZ日 <RangeSeparator /> XXXX年YY月ZZ日</>
31
+ // スクリーンリーダーは "XXXX年YY月ZZ日からXXXX年YY月ZZ日" と読み上げます
32
+
33
+ <p>選択できる数値の範囲は 0 <RangeSeparator /> 9999 です</p>
34
+ // スクリーンリーダーは "選択できる数値の範囲は0から9999です" と読み上げます
35
+
36
+ <p>入力できる記号は <RangeSeparator decorators={{ text: '~', visuallyHiddenText: '半角チルダ' }} /> です</p>
37
+ // スクリーンリーダーは "入力できる記号は半角チルダです" と読み上げます
38
+ ```
@@ -0,0 +1,28 @@
1
+ const TILDE_REGEX = /([~〜])/
2
+
3
+ const SCHEMA = []
4
+
5
+ module.exports = {
6
+ meta: {
7
+ type: 'problem',
8
+ schema: SCHEMA,
9
+ },
10
+ create(context) {
11
+ return {
12
+ JSXText: (node) => {
13
+ const matcher = node.value.match(TILDE_REGEX)
14
+
15
+ if (matcher) {
16
+ context.report({
17
+ node,
18
+ message: `"${matcher[1]}"はスクリーンリーダーが正しく読み上げることができない場合があるため、smarthr-ui/RangeSeparatorに置き換えてください。
19
+ - エラー表示されている行に"${matcher[1]}"が存在しない場合、改行文字を含む関係で行番号がずれている場合があります。数行下の範囲を確認してください
20
+ - smarthr-ui/RangeSeparatorに置き換えることでスクリーンリーダーが "から" と読み上げることができます
21
+ - 前後の文脈などで "から" と読まれることが不適切な場合 \`<RangeSeparator decorators={{ visuallyHiddenText: () => "ANY" }} />\` のようにdecoratorsを指定してください`,
22
+ })
23
+ }
24
+ },
25
+ }
26
+ },
27
+ }
28
+ module.exports.schema = SCHEMA
@@ -56,6 +56,8 @@ ruleTester.run('smarthr/a11y-delegate-element-has-role-presentation', rule, {
56
56
  { code: '<Wrapper onClick={any} role="presentation">{any1 ? (any2 ? <HogeLink /> : null) : null}</Wrapper>' },
57
57
  { code: '<Wrapper onClick={any} role="presentation">{any ? null : (hoge ? <AnyLink /> : null)}</Wrapper>' },
58
58
  { code: '<Wrapper onClick={any} role="slider">Hoge</Wrapper>' },
59
+ { code: '<Wrapper onSubmit={any} as="form" />' },
60
+ { code: '<Wrapper onSubmit={any} forwardedAs="fieldset">any</Wrapper>' },
59
61
  ],
60
62
  invalid: [
61
63
  { code: '<Input role="presentation" />', errors: [ { message: messageInteractiveHasRolePresentation('Input') } ] },
@@ -0,0 +1,36 @@
1
+ const rule = require('../rules/a11y-replace-unreadable-symbol')
2
+ const RuleTester = require('eslint').RuleTester
3
+
4
+ const generateErrorText = (symbol, replaced, read) => `"${symbol}"はスクリーンリーダーが正しく読み上げることができない場合があるため、smarthr-ui/${replaced}に置き換えてください。
5
+ - エラー表示されている行に"${symbol}"が存在しない場合、改行文字を含む関係で行番号がずれている場合があります。数行下の範囲を確認してください
6
+ - smarthr-ui/${replaced}に置き換えることでスクリーンリーダーが "${read}" と読み上げることができます
7
+ - 前後の文脈などで "${read}" と読まれることが不適切な場合 \`<RangeSeparator decorators={{ visuallyHiddenText: () => "ANY" }} />\` のようにdecoratorsを指定してください`
8
+
9
+ const ruleTester = new RuleTester({
10
+ parserOptions: {
11
+ ecmaVersion: 2018,
12
+ ecmaFeatures: {
13
+ experimentalObjectRestSpread: true,
14
+ jsx: true,
15
+ },
16
+ sourceType: 'module',
17
+ },
18
+ })
19
+
20
+ ruleTester.run('a11y-replace-unreadable-symbol', rule, {
21
+ valid: [
22
+ { code: `<>ほげふが</>` },
23
+ { code: `<RangeSeparator />` },
24
+ { code: `<p>ほげ<RangeSeparator />ふが</p>` },
25
+ { code: `<p>
26
+ ほげ
27
+ <RangeSeparator />
28
+ ふが
29
+ </p>` },
30
+ ],
31
+ invalid: [
32
+ { code: `<>~</>`, errors: [ { message: generateErrorText('~', 'RangeSeparator', 'から') } ] },
33
+ { code: `<>ほげ~ふが</>`, errors: [ { message: generateErrorText('~', 'RangeSeparator', 'から') } ] },
34
+ { code: `<p>ほげ〜ふが</p>`, errors: [ { message: generateErrorText('〜', 'RangeSeparator', 'から') } ] },
35
+ ]
36
+ })