Skip to content

Commit

Permalink
[New] jsx-one-expression-per-line: add non-jsx option to allow no…
Browse files Browse the repository at this point in the history
…n-JSX children in one line
  • Loading branch information
burtek authored and ljharb committed Jan 11, 2024
1 parent 1014f8c commit 9f4b2b9
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -17,6 +17,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
* [`jsx-boolean-value`]: add `assumeUndefinedIsFalse` option ([#3675][] @developer-bandi)
* `linkAttribute` setting, [`jsx-no-target-blank`]: support multiple properties ([#3673][] @burtek)
* [`jsx-no-script-url`]: add `includeFromSettings` option to support `linkAttributes` setting ([#3673][] @burtek)
* [`jsx-one-expression-per-line`]: add `non-jsx` option to allow non-JSX children in one line ([#3677][] @burtek)

### Fixed
* [`jsx-no-leaked-render`]: preserve RHS parens for multiline jsx elements while fixing ([#3623][] @akulsr0)
Expand All @@ -32,6 +33,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
* [Docs] [`jsx-key`]: fix correct example ([#3656][] @developer-bandi)
* [Tests] `jsx-wrap-multilines`: passing tests ([#3545][] @burtek)

[#3677]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3677
[#3675]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3675
[#3674]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3674
[#3673]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3673
Expand Down
8 changes: 8 additions & 0 deletions docs/rules/jsx-one-expression-per-line.md
Expand Up @@ -133,3 +133,11 @@ Examples of **correct** code for this rule, when configured as `"single-child"`:

<App><Hello /></App>
```

Examples of **correct** code for this rule, when configured as `"non-jsx"`:

```jsx
<App>Hello {someVariable}</App>

<App>Hello {<Hello />} there!</App>
```
9 changes: 8 additions & 1 deletion lib/rules/jsx-one-expression-per-line.js
Expand Up @@ -38,7 +38,7 @@ module.exports = {
type: 'object',
properties: {
allow: {
enum: ['none', 'literal', 'single-child'],
enum: ['none', 'literal', 'single-child', 'non-jsx'],
},
},
default: optionDefaults,
Expand All @@ -65,6 +65,13 @@ module.exports = {
return;
}

if (
options.allow === 'non-jsx'
&& !children.find((child) => (child.type === 'JSXFragment' || child.type === 'JSXElement'))
) {
return;
}

const openingElement = node.openingElement || node.openingFragment;
const closingElement = node.closingElement || node.closingFragment;
const openingElementStartLine = openingElement.loc.start.line;
Expand Down
87 changes: 87 additions & 0 deletions tests/lib/rules/jsx-one-expression-per-line.js
Expand Up @@ -155,6 +155,22 @@ ruleTester.run('jsx-one-expression-per-line', rule, {
code: '<App>{"foo"}</App>',
options: [{ allow: 'single-child' }],
},
{
code: '<App>123</App>',
options: [{ allow: 'non-jsx' }],
},
{
code: '<App>foo</App>',
options: [{ allow: 'non-jsx' }],
},
{
code: '<App>{"foo"}</App>',
options: [{ allow: 'non-jsx' }],
},
{
code: '<App>{<Bar />}</App>',
options: [{ allow: 'non-jsx' }],
},
{
code: '<App>{foo && <Bar />}</App>',
options: [{ allow: 'single-child' }],
Expand Down Expand Up @@ -184,6 +200,38 @@ ruleTester.run('jsx-one-expression-per-line', rule, {
`,
features: ['fragment', 'no-ts-old'], // TODO: FIXME: remove no-ts-old and fix
},
{
code: '<App>Hello {name}</App>',
options: [{ allow: 'non-jsx' }],
},
{
code: `
<App>
Hello {name} there!
</App>`,
options: [{ allow: 'non-jsx' }],
},
{
code: `
<App>
Hello {<Bar />} there!
</App>`,
options: [{ allow: 'non-jsx' }],
},
{
code: `
<App>
Hello {(<Bar />)} there!
</App>`,
options: [{ allow: 'non-jsx' }],
},
{
code: `
<App>
Hello {(() => <Bar />)()} there!
</App>`,
options: [{ allow: 'non-jsx' }],
},
]),

invalid: parsers.all([
Expand Down Expand Up @@ -493,6 +541,28 @@ foo
],
parserOptions,
},
{
code: `
<Text style={styles.foo}>
<Bar /> <Baz />
</Text>
`,
output: `
<Text style={styles.foo}>
<Bar />${' '/* intentional trailing space */}
{' '}
<Baz />
</Text>
`,
errors: [
{
messageId: 'moveToNewLine',
data: { descriptor: 'Baz' },
},
],
options: [{ allow: 'non-jsx' }],
parserOptions,
},
{
code: `
<Text style={styles.foo}>
Expand Down Expand Up @@ -1257,6 +1327,23 @@ foo
},
],
},
{
code: `
<App><Foo /></App>
`,
output: `
<App>
<Foo />
</App>
`,
options: [{ allow: 'non-jsx' }],
errors: [
{
messageId: 'moveToNewLine',
data: { descriptor: 'Foo' },
},
],
},
{
code: `
<App
Expand Down

0 comments on commit 9f4b2b9

Please sign in to comment.