Enforce Text suffix for Text-rendering components (#3407)
* Rm unused * Add Text suffix to Title/Description * Add Text suffix to text components * Add Text suffix to props * Validate Text components returns
This commit is contained in:
parent
c190fd58ec
commit
3915bb4316
43 changed files with 453 additions and 366 deletions
|
@ -246,6 +246,41 @@ describe('avoid-unwrapped-text', () => {
|
|||
</Foo>
|
||||
`,
|
||||
},
|
||||
|
||||
{
|
||||
code: `
|
||||
function Stuff() {
|
||||
return <Text>foo</Text>
|
||||
}
|
||||
`,
|
||||
},
|
||||
|
||||
{
|
||||
code: `
|
||||
function Stuff({ foo }) {
|
||||
return <View>{foo}</View>
|
||||
}
|
||||
`,
|
||||
},
|
||||
|
||||
{
|
||||
code: `
|
||||
function MyText() {
|
||||
return <Text>foo</Text>
|
||||
}
|
||||
`,
|
||||
},
|
||||
|
||||
{
|
||||
code: `
|
||||
function MyText({ foo }) {
|
||||
if (foo) {
|
||||
return <Text>foo</Text>
|
||||
}
|
||||
return <Text>foo</Text>
|
||||
}
|
||||
`,
|
||||
},
|
||||
],
|
||||
|
||||
invalid: [
|
||||
|
@ -390,6 +425,36 @@ describe('avoid-unwrapped-text', () => {
|
|||
`,
|
||||
errors: 1,
|
||||
},
|
||||
|
||||
{
|
||||
code: `
|
||||
function MyText() {
|
||||
return <Foo />
|
||||
}
|
||||
`,
|
||||
errors: 1,
|
||||
},
|
||||
|
||||
{
|
||||
code: `
|
||||
function MyText({ foo }) {
|
||||
return <Foo>{foo}</Foo>
|
||||
}
|
||||
`,
|
||||
errors: 1,
|
||||
},
|
||||
|
||||
{
|
||||
code: `
|
||||
function MyText({ foo }) {
|
||||
if (foo) {
|
||||
return <Foo>{foo}</Foo>
|
||||
}
|
||||
return <Text>foo</Text>
|
||||
}
|
||||
`,
|
||||
errors: 1,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,11 @@ exports.create = function create(context) {
|
|||
const impliedTextComponents = options.impliedTextComponents ?? []
|
||||
const textProps = [...impliedTextProps]
|
||||
const textComponents = ['Text', ...impliedTextComponents]
|
||||
|
||||
function isTextComponent(tagName) {
|
||||
return textComponents.includes(tagName) || tagName.endsWith('Text')
|
||||
}
|
||||
|
||||
return {
|
||||
JSXText(node) {
|
||||
if (typeof node.value !== 'string' || hasOnlyLineBreak(node.value)) {
|
||||
|
@ -44,7 +49,7 @@ exports.create = function create(context) {
|
|||
while (parent) {
|
||||
if (parent.type === 'JSXElement') {
|
||||
const tagName = getTagName(parent)
|
||||
if (textComponents.includes(tagName) || tagName.endsWith('Text')) {
|
||||
if (isTextComponent(tagName)) {
|
||||
// We're good.
|
||||
return
|
||||
}
|
||||
|
@ -107,5 +112,36 @@ exports.create = function create(context) {
|
|||
continue
|
||||
}
|
||||
},
|
||||
ReturnStatement(node) {
|
||||
let fnScope = context.getScope()
|
||||
while (fnScope && fnScope.type !== 'function') {
|
||||
fnScope = fnScope.upper
|
||||
}
|
||||
if (!fnScope) {
|
||||
return
|
||||
}
|
||||
const fn = fnScope.block
|
||||
if (!fn.id || fn.id.type !== 'Identifier' || !fn.id.name) {
|
||||
return
|
||||
}
|
||||
if (!/^[A-Z]\w*Text$/.test(fn.id.name)) {
|
||||
return
|
||||
}
|
||||
if (!node.argument || node.argument.type !== 'JSXElement') {
|
||||
return
|
||||
}
|
||||
const openingEl = node.argument.openingElement
|
||||
if (openingEl.name.type !== 'JSXIdentifier') {
|
||||
return
|
||||
}
|
||||
const returnedComponentName = openingEl.name.name
|
||||
if (!isTextComponent(returnedComponentName)) {
|
||||
context.report({
|
||||
node,
|
||||
message:
|
||||
'Components ending with *Text must return <Text> or <SomeText>.',
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue