diff --git a/CHANGELOG.md b/CHANGELOG.md index c0e9bf59e5..dde43a8d6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,8 +15,10 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange * configs: avoid legacy config system error ([#3461][] @ljharb) * [`sort-prop-types`]: restore autofixing ([#3452][] @ROSSROSALES) * [`no-unknown-property`]: do not check `fbs` elements ([#3494][] @brianogilvie) +* [`jsx-newline`]: No newline between comments and jsx elements ([#3493][] @justmejulian) [#3494]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3494 +[#3493]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3493 [#3461]: https://github.com/jsx-eslint/eslint-plugin-react/issues/3461 [#3452]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3452 [#3449]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3449 diff --git a/lib/rules/jsx-newline.js b/lib/rules/jsx-newline.js index cbc5e58283..d9c8262cc9 100644 --- a/lib/rules/jsx-newline.js +++ b/lib/rules/jsx-newline.js @@ -72,6 +72,15 @@ module.exports = { const jsxElementParents = new Set(); const sourceCode = context.getSourceCode(); + function isBlockCommentInCurlyBraces(element) { + const elementRawValue = sourceCode.getText(element); + return /^\s*{\/\*/.test(elementRawValue); + } + + function isNonBlockComment(element) { + return !isBlockCommentInCurlyBraces(element) && (element.type === 'JSXElement' || element.type === 'JSXExpressionContainer'); + } + return { 'Program:exit'() { jsxElementParents.forEach((parent) => { @@ -93,7 +102,15 @@ module.exports = { // Check adjacent sibling has the proper amount of newlines const isWithoutNewLine = !/\n\s*\n/.test(firstAdjacentSibling.value); - if (allowMultilines && (isMultilined(element) || isMultilined(secondAdjacentSibling))) { + if (isBlockCommentInCurlyBraces(element)) return; + + if ( + allowMultilines + && ( + isMultilined(element) + || isMultilined(elements.slice(index + 2).find(isNonBlockComment)) + ) + ) { if (!isWithoutNewLine) return; const regex = /(\n)(?!.*\1)/g; @@ -115,6 +132,7 @@ module.exports = { } if (isWithoutNewLine === prevent) return; + const messageId = prevent ? 'prevent' : 'require'; diff --git a/tests/lib/rules/jsx-newline.js b/tests/lib/rules/jsx-newline.js index 318d82eaab..d0daf68f86 100644 --- a/tests/lib/rules/jsx-newline.js +++ b/tests/lib/rules/jsx-newline.js @@ -105,6 +105,44 @@ new RuleTester({ parserOptions }).run('jsx-newline', rule, { `, }, + { + code: ` + + `, + }, + { + code: ` + + `, + }, + { + code: ` + + `, + }, + { + code: ` + <> + {/* does this */} + + + {/* also work with multiple components and inside a fragment? */} + + + `, + features: ['fragment'], + }, { code: ` <> @@ -122,6 +160,24 @@ new RuleTester({ parserOptions }).run('jsx-newline', rule, { features: ['fragment'], options: [{ prevent: true, allowMultilines: true }], }, + { + code: ` +
+ {/* this does not have a newline */} + + {/* neither does this */} + + + {/* but this one needs one */} + +
+ `, + options: [{ prevent: true, allowMultilines: true }], + }, { code: `
@@ -223,6 +279,100 @@ new RuleTester({ parserOptions }).run('jsx-newline', rule, { `, errors: [{ messageId: 'require' }], }, + { + code: ` +
+ {/* This should however still not work*/} + + + + {/* Comments between components still need a newLine */} + +
+ `, + output: ` +
+ {/* This should however still not work*/} + + + + + {/* Comments between components still need a newLine */} + +
+ `, + errors: [{ messageId: 'require' }], + }, + { + code: ` +
+ {/* this does not have a newline */} + + {/* neither does this */} + + {/* but this one needs one */} + +
+ `, + output: ` +
+ {/* this does not have a newline */} + + {/* neither does this */} + + + {/* but this one needs one */} + +
+ `, + options: [{ prevent: true, allowMultilines: true }], + errors: [{ messageId: 'allowMultilines' }], + }, + { + code: ` +
+ {/* this does not have a newline */} + + {/* neither does this */} + + {/* Multiline */} + {/* Block comments */} + {/* Stick to MultilineComponent */} + +
+ `, + output: ` +
+ {/* this does not have a newline */} + + {/* neither does this */} + + + {/* Multiline */} + {/* Block comments */} + {/* Stick to MultilineComponent */} + +
+ `, + options: [{ prevent: true, allowMultilines: true }], + errors: [{ messageId: 'allowMultilines' }], + }, { code: `