diff options
author | dan <dan.abramov@gmail.com> | 2024-04-04 21:34:55 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-04 21:34:55 +0100 |
commit | 3915bb43169ae501d81571c5e1efa12cf0e24dbb (patch) | |
tree | be2f7bed7c842be71922f2793b4b4a20cd6fbc24 /eslint | |
parent | c190fd58ec82b36ea8124902cad34acc4a5b5ac0 (diff) | |
download | voidsky-3915bb43169ae501d81571c5e1efa12cf0e24dbb.tar.zst |
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
Diffstat (limited to 'eslint')
-rw-r--r-- | eslint/__tests__/avoid-unwrapped-text.test.js | 65 | ||||
-rw-r--r-- | eslint/avoid-unwrapped-text.js | 38 |
2 files changed, 102 insertions, 1 deletions
diff --git a/eslint/__tests__/avoid-unwrapped-text.test.js b/eslint/__tests__/avoid-unwrapped-text.test.js index 0fbc01123..7c667b4a8 100644 --- a/eslint/__tests__/avoid-unwrapped-text.test.js +++ b/eslint/__tests__/avoid-unwrapped-text.test.js @@ -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, + }, ], } diff --git a/eslint/avoid-unwrapped-text.js b/eslint/avoid-unwrapped-text.js index c9e72386e..79d099f00 100644 --- a/eslint/avoid-unwrapped-text.js +++ b/eslint/avoid-unwrapped-text.js @@ -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>.', + }) + } + }, } } |