Repository: rollup/rollup
File: src/ast/nodes/JSXText.ts (TypeScript)

Code before:
import type MagicString from 'magic-string';
import type { NormalizedJsxOptions } from '../../rollup/types';
import type * as NodeType from './NodeType';
import { NodeBase, onlyIncludeSelf } from './shared/Node';

const RE_WHITESPACE_TRIM = /^[ \t]*\r?\n[ \t]*|[ \t]*\r?\n[ \t]*$/g;
const RE_WHITESPACE_MERGE = /[ \t]*\r?\n[ \t]*/g;

export default class JSXText extends NodeBase {
	type!: NodeType.tJSXText;
	value!: string;
	raw!: string;

	private renderedText: string | undefined;

	shouldRender() {
		return !!this.getRenderedText();
	}

	render(code: MagicString) {
		const { mode } = this.scope.context.options.jsx as NormalizedJsxOptions;
		if (mode !== 'preserve') {
			code.overwrite(this.start, this.end, JSON.stringify(this.getRenderedText()), {
				contentOnly: true
			});
		}
	}

	private getRenderedText() {
		if (this.renderedText === undefined)
			this.renderedText = this.value

Review comment (suggestion):
This looks like it will only remove until the first line-break, but checking against the Babel REPL, multiple line-breaks are removed as well. Compare this:

Babel: https://babeljs.io/repl#?config_lz=N4IgZglgNgpgdgQwLYxALhAJxgBygOgCsBnADxABoQdtiYAXY9AbWZHgDdLR6FMBzBkwwATGGAQBXKIwoACOAHt6ciDDkBGDfKUq1AfSSKARpo2UQRkdJjCJUOlWOT-kUrfT1MkmAF8AuhRs2AgAxvTcWJJw9BAo6CBS9IpICLGhIAFBIMS8ggC0AEyRYqGKmGnlxABqMJjEEIpwCYUADIUAzPlaFjgQODBQEHAwAAqYijiKxAhQCQAWYQDWmf6BOYqSmKEwACoAngMJVjaZQA&code_lz=KYDwDg9gTgLgBAMwK4DsDGMCWEWIBQCUcA3gFBwVxTAxJS57mXMA8AfE8851xT7yH5cWAE0wA3APQdeFFtJ4EA3KQC-pIA&lineWrap=true&version=7.28.3

Rollup: https://rollup-90iirwpg8-rollup-js.vercel.app/repl/?pr=6051&shareable=JTdCJTIyZXhhbXBsZSUyMiUzQSUyMiUyMiUyQyUyMm1vZHVsZXMlMjIlM0ElNUIlN0IlMjJjb2RlJTIyJTNBJTIyZXhwb3J0JTIwZnVuY3Rpb24lMjBmKCklMjAlN0IlNUNuJTIwJTIwJTIwJTIwcmV0dXJuJTIwKCU1Q24lMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlM0UlNUNuJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTVDbiUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCU1Q24lMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjB4JTVDbiUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUzQ2RpdiUyRiUzRSU1Q24lMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlM0MlMkYlM0UlNUNuJTIwJTIwJTIwJTIwKSUzQiU1Q24lN0QlNUNuJTIyJTJDJTIyaXNFbnRyeSUyMiUzQXRydWUlMkMlMjJuYW1lJTIyJTNBJTIybWFpbi5qcyUyMiU3RCU1RCUyQyUyMm9wdGlvbnMlMjIlM0ElN0IlMjJqc3glMjIlM0ElMjJyZWFjdC1qc3glMjIlMkMlMjJvdXRwdXQlMjIlM0ElN0IlMjJmb3JtYXQlMjIlM0ElMjJlcyUyMiU3RCU3RCU3RA==

Note the ominous double empty space `"  x"` it creates, which is from the second replacement function.

Code after:
import type MagicString from 'magic-string';
import type { NormalizedJsxOptions } from '../../rollup/types';
import type * as NodeType from './NodeType';
import { NodeBase, onlyIncludeSelf } from './shared/Node';

const RE_WHITESPACE_TRIM = /^[ \t]*\r?\n[ \t\r\n]*|[ \t]*\r?\n[ \t\r\n]*$/g;
const RE_WHITESPACE_MERGE = /[ \t]*\r?\n[ \t\r\n]*/g;

export default class JSXText extends NodeBase {
	type!: NodeType.tJSXText;
	value!: string;
	raw!: string;

	private renderedText: string | undefined;

	shouldRender() {
		return !!this.getRenderedText();
	}

	render(code: MagicString) {
		const { mode } = this.scope.context.options.jsx as NormalizedJsxOptions;
		if (mode !== 'preserve') {
			code.overwrite(this.start, this.end, JSON.stringify(this.getRenderedText()), {
				contentOnly: true
			});
		}
	}

	private getRenderedText() {
		if (this.renderedText === undefined)
			this.renderedText = this.value