Skip to content

Commit

Permalink
feat: a11y系ruleのコンポーネント名チェックが漏れているパターンが存在したため調整 (#56)
Browse files Browse the repository at this point in the history
  • Loading branch information
AtsushiM authored Jan 19, 2023
1 parent abc8091 commit e628426
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 58 deletions.
107 changes: 55 additions & 52 deletions libs/format_styled_components.js
Original file line number Diff line number Diff line change
@@ -1,68 +1,71 @@
const getExtendedComponentName = (node) => {
if (!node.parent) {
return null
}
const STYLED_COMPONENTS_METHOD = 'styled'
const STYLED_COMPONENTS = `${STYLED_COMPONENTS_METHOD}-components`

return node.parent.id?.name || getExtendedComponentName(node.parent)
}
const getBaseComponentName = (node) => {
if (!node) {
return null
}
const findInvalidImportNameNode = (s) => s.type === 'ImportDefaultSpecifier' && s.local.name !== STYLED_COMPONENTS_METHOD

if (node.type === 'CallExpression') {
if (node.callee.name === 'styled') {
return node.arguments[0].name
}
if (node.callee.object?.name === 'styled') {
return node.callee.property.name
}
}
const generateTagFormatter = ({ context, EXPECTED_NAMES }) => {
const entriesesTagNames = Object.entries(EXPECTED_NAMES).map(([b, e]) => [ new RegExp(b), new RegExp(e) ])

if (node?.object?.name === 'styled') {
return node.property.name
}
return {
ImportDeclaration: (node) => {
if (node.source.value !== STYLED_COMPONENTS) {
return
}

return getBaseComponentName(node.parent)
}
const invalidNameNode = node.specifiers.find(findInvalidImportNameNode)

const generateTagFormatter = ({ context, EXPECTED_NAMES }) => ({
ImportDeclaration: (node) => {
if (node.source.value !== 'styled-components') {
return
}
if (invalidNameNode) {
context.report({
node: invalidNameNode,
message: `${STYLED_COMPONENTS} をimportする際は、名称が"${STYLED_COMPONENTS_METHOD}" となるようにしてください。例: "import ${STYLED_COMPONENTS_METHOD} from '${STYLED_COMPONENTS}'"`,
});
}
},
VariableDeclarator: (node) => {
if (!node.init) {
return
}

const invalidNameNode = node.specifiers.find((s) => s.type === 'ImportDefaultSpecifier' && s.local.name !== 'styled')
const tag = node.init.tag || node.init

if (invalidNameNode) {
context.report({
node: invalidNameNode,
message: "styled-components をimportする際は、名称が`styled` となるようにしてください。例: `import styled from 'styled-components'`",
});
}
},
TaggedTemplateExpression: (node) => {
const extended = getExtendedComponentName(node)
let base = null

if (extended) {
const base = getBaseComponentName(node.tag)
if (tag.object?.name === STYLED_COMPONENTS_METHOD) {
base = tag.property.name
} else if (tag.callee) {
const callee = tag.callee

switch (STYLED_COMPONENTS_METHOD) {
case callee.name: {
const arg = tag.arguments[0]
base = arg.name || arg.value
break
}
case callee.callee?.name: {
const arg = callee.arguments[0]
base = arg.name || arg.value
break
}
case callee.object?.name:
base = callee.property.name
break
}
}

if (base) {
Object.entries(EXPECTED_NAMES).forEach(([b, e]) => {
if (base.match(new RegExp(b))) {
const extendedregex = new RegExp(e)
const extended = node.id.name

if (!extended.match(extendedregex)) {
context.report({
node: node.parent,
message: `${extended}を正規表現 "${extendedregex.toString()}" がmatchする名称に変更してください`,
});
}
entriesesTagNames.forEach(([b, e]) => {
if (base.match(b) && !extended.match(e)) {
context.report({
node,
message: `${extended}を正規表現 "${e.toString()}" がmatchする名称に変更してください`,
});
}
})
}
}
},
})
},
}
}

module.exports = { generateTagFormatter }
9 changes: 8 additions & 1 deletion test/a11y-clickable-element-has-text.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ ruleTester.run('a11y-clickable-element-has-text', rule, {
{ code: 'const HogeButton = styled(Button)``' },
{ code: 'const FugaAnchor = styled(HogeAnchor)``' },
{ code: 'const FugaSmartHRLogo = styled(SmartHRLogo)``' },
{ code: 'const HogeAnchor = styled.a(() => ``)' },
{ code: 'const HogeAnchor = styled("a")(() => ``)' },
{ code: 'const HogeAnchor = styled(Anchor)(() => ``)' },
{
code: `<a>ほげ</a>`,
},
Expand Down Expand Up @@ -110,7 +113,7 @@ ruleTester.run('a11y-clickable-element-has-text', rule, {
},
],
invalid: [
{ code: `import hoge from 'styled-components'`, errors: [ { message: "styled-components をimportする際は、名称が`styled` となるようにしてください。例: `import styled from 'styled-components'`" } ] },
{ code: `import hoge from 'styled-components'`, errors: [ { message: `styled-components をimportする際は、名称が"styled" となるようにしてください。例: "import styled from 'styled-components'"` } ] },
{ code: 'const Hoge = styled.a``', errors: [ { message: `Hogeを正規表現 "/(Anchor|Link)$/" がmatchする名称に変更してください` } ] },
{ code: 'const Hoge = styled.button``', errors: [ { message: `Hogeを正規表現 "/Button$/" がmatchする名称に変更してください` } ] },
{ code: 'const Hoge = styled(Anchor)``', errors: [ { message: `Hogeを正規表現 "/Anchor$/" がmatchする名称に変更してください` } ] },
Expand All @@ -119,6 +122,10 @@ ruleTester.run('a11y-clickable-element-has-text', rule, {
{ code: 'const Fuga = styled(HogeAnchor)``', errors: [ { message: `Fugaを正規表現 "/Anchor$/" がmatchする名称に変更してください` } ] },
{ code: 'const Fuga = styled(HogeAnchor)``', errors: [ { message: `Fugaを正規表現 "/Anchor$/" がmatchする名称に変更してください` } ] },
{ code: 'const Fuga = styled(SmartHRLogo)``', errors: [ { message: `Fugaを正規表現 "/SmartHRLogo$/" がmatchする名称に変更してください` } ] },
{ code: 'const Piyo = styled.a(() => ``)', errors: [ { message: `Piyoを正規表現 "/(Anchor|Link)$/" がmatchする名称に変更してください` } ] },
{ code: 'const Piyo = styled("a")(() => ``)', errors: [ { message: `Piyoを正規表現 "/(Anchor|Link)$/" がmatchする名称に変更してください` } ] },
{ code: 'const Piyo = styled("a")``', errors: [ { message: `Piyoを正規表現 "/(Anchor|Link)$/" がmatchする名称に変更してください` } ] },
{ code: 'const Piyo = styled(Anchor)(() => ``)', errors: [ { message: `Piyoを正規表現 "/Anchor$/" がmatchする名称に変更してください` } ] },
{
code: `<a><img src="hoge.jpg" /></a>`,
errors: [{ message: defaultErrorMessage }]
Expand Down
2 changes: 1 addition & 1 deletion test/a11y-image-has-alt-attribute.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ ruleTester.run('a11y-image-has-alt-attribute', rule, {
{ code: '<svg><image /></svg>' },
],
invalid: [
{ code: `import hoge from 'styled-components'`, errors: [ { message: "styled-components をimportする際は、名称が`styled` となるようにしてください。例: `import styled from 'styled-components'`" } ] },
{ code: `import hoge from 'styled-components'`, errors: [ { message: `styled-components をimportする際は、名称が"styled" となるようにしてください。例: "import styled from 'styled-components'"` } ] },
{ code: 'const Hoge = styled.img``', errors: [ { message: `Hogeを正規表現 "/(Img|Image|Icon)$/" がmatchする名称に変更してください` } ] },
{ code: 'const Hoge = styled.svg``', errors: [ { message: `Hogeを正規表現 "/(Img|Image|Icon)$/" がmatchする名称に変更してください` } ] },
{ code: 'const Hoge = styled(Icon)``', errors: [ { message: `Hogeを正規表現 "/Icon$/" がmatchする名称に変更してください` } ] },
Expand Down
2 changes: 1 addition & 1 deletion test/a11y-input-has-name-attribute.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ ruleTester.run('a11y-input-has-name-attribute', rule, {
{ code: '<Select name="hoge[0][Fuga]" />' },
],
invalid: [
{ code: `import hoge from 'styled-components'`, errors: [ { message: "styled-components をimportする際は、名称が`styled` となるようにしてください。例: `import styled from 'styled-components'`" } ] },
{ code: `import hoge from 'styled-components'`, errors: [ { message: `styled-components をimportする際は、名称が"styled" となるようにしてください。例: "import styled from 'styled-components'"` } ] },
{ code: 'const Hoge = styled.input``', errors: [ { message: `Hogeを正規表現 "/Input$/" がmatchする名称に変更してください` } ] },
{ code: 'const Hoge = styled.Input``', errors: [ { message: `Hogeを正規表現 "/Input$/" がmatchする名称に変更してください` } ] },
{ code: 'const Hoge = styled(RadioButton)``', errors: [ { message: `Hogeを正規表現 "/RadioButton$/" がmatchする名称に変更してください` } ] },
Expand Down
4 changes: 2 additions & 2 deletions test/a11y-prohhibit-input-placeholder.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,14 @@ ruleTester.run('a11y-prohibit-input-placeholder', rule, {
{ code: `<ComboBox placeholder="hoge" dropdownHelpMessage="fuga" />` },
],
invalid: [
{ code: `import hoge from 'styled-components'`, errors: [ { message: "styled-components をimportする際は、名称が`styled` となるようにしてください。例: `import styled from 'styled-components'`" } ] },
{ code: `import hoge from 'styled-components'`, errors: [ { message: `styled-components をimportする際は、名称が"styled" となるようにしてください。例: "import styled from 'styled-components'"` } ] },
{ code: 'const Hoge = styled.input``', errors: [ { message: `Hogeを正規表現 "/Input$/" がmatchする名称に変更してください` } ] },
{ code: 'const Hoge = styled(StyledInput)``', errors: [ { message: `Hogeを正規表現 "/Input$/" がmatchする名称に変更してください` } ] },
{ code: 'const Hoge = styled.textarea``', errors: [ { message: `Hogeを正規表現 "/Textarea$/" がmatchする名称に変更してください` } ] },
{ code: 'const Hoge = styled(StyledTextarea)``', errors: [ { message: `Hogeを正規表現 "/Textarea$/" がmatchする名称に変更してください` } ] },
{ code: 'const Hoge = styled(FieldSet)``', errors: [ { message: `Hogeを正規表現 "/FieldSet$/" がmatchする名称に変更してください` } ] },
{ code: 'const Hoge = styled(ComboBox)``', errors: [ { message: `Hogeを正規表現 "/ComboBox$/" がmatchする名称に変更してください` } ] },
{
{
code: 'const Hoge = styled(SearchInput)``',
errors: [
{ message: `Hogeを正規表現 "/Input$/" がmatchする名称に変更してください` },
Expand Down
2 changes: 1 addition & 1 deletion test/a11y-trigger-has-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ ruleTester.run('a11y-trigger-has-button', rule, {
{ code: '<DropdownTrigger>{hoge}</DropdownTrigger>' },
],
invalid: [
{ code: `import hoge from 'styled-components'`, errors: [ { message: "styled-components をimportする際は、名称が`styled` となるようにしてください。例: `import styled from 'styled-components'`" } ] },
{ code: `import hoge from 'styled-components'`, errors: [ { message: `styled-components をimportする際は、名称が"styled" となるようにしてください。例: "import styled from 'styled-components'"` } ] },
{ code: 'const Hoge = styled.button``', errors: [ { message: `Hogeを正規表現 "/Button$/" がmatchする名称に変更してください` } ] },
{ code: 'const Hoge = styled.a``', errors: [ { message: `Hogeを正規表現 "/(Anchor|Link)$/" がmatchする名称に変更してください` } ] },
{ code: 'const Hoge = styled(Button)``', errors: [ { message: `Hogeを正規表現 "/Button$/" がmatchする名称に変更してください` } ] },
Expand Down

0 comments on commit e628426

Please sign in to comment.