diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f3b3a55c..1eb365cf9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -663,7 +663,7 @@ Error: Comment "comment" was not printed. Please report this error! ``` -#### Fix formatting for comments inside JSX attribute ([#14082](https://github.com/prettier/prettier/pull/14082) with by [@fisker](https://github.com/fisker)) +#### Fix formatting for comments inside JSX attribute ([#14082](https://github.com/prettier/prettier/pull/14082) by [@fisker](https://github.com/fisker)) ```jsx diff --git a/changelog_unreleased/javascript/14163.md b/changelog_unreleased/javascript/14163.md new file mode 100644 index 000000000..8214e8856 --- /dev/null +++ b/changelog_unreleased/javascript/14163.md @@ -0,0 +1,18 @@ +#### Fix cursor tracking inside JSX Text (#14163 by @fisker) + + +```js +// Prettier stable +formatWithCursor( + ["<>a", "
hi
", ""].join("\n"), + { cursorOffset: 3, parser: "babel" } +).cursorOffset; +// -> 2 + +// Prettier main +(await formatWithCursor( + ["<>a", "
hi
", ""].join("\n"), + { cursorOffset: 3, parser: "babel" } +)).cursorOffset; +// -> 6 +``` diff --git a/src/language-js/print/jsx.js b/src/language-js/print/jsx.js index b552300f3..cbdfd6ecc 100644 --- a/src/language-js/print/jsx.js +++ b/src/language-js/print/jsx.js @@ -13,6 +13,7 @@ import { ifBreak, lineSuffixBoundary, join, + cursor, } from "../../document/builders.js"; import { willBreak, replaceEndOfLine } from "../../document/utils.js"; import UnexpectedNodeError from "../../utils/unexpected-node-error.js"; @@ -50,6 +51,7 @@ const isEmptyStringOrAnyLine = (doc) => * @typedef {import("../../common/ast-path.js").default} AstPath * @typedef {import("../types/estree.js").Node} Node * @typedef {import("../types/estree.js").JSXElement} JSXElement + * @typedef {import("../../document/builders.js").Doc} Doc */ // JSX expands children from the inside-out, instead of the outside-in. @@ -236,10 +238,22 @@ function printJsxElementInternal(path, options, print) { // If there is text we use `fill` to fit as much onto each line as possible. // When there is no text (just tags and expressions) we use `group` // to output each on a separate line. - const content = containsText + /** @type {Doc} */ + let content = containsText ? fill(multilineChildren) : group(multilineChildren, { shouldBreak: true }); + /* + `printJsxChildren` won't call `print` on `JSXText` + When the cursorNode is inside `cursor` won't get print. + */ + if ( + options.cursorNode?.type === "JSXText" && + node.children.includes(options.cursorNode) + ) { + content = [cursor, content, cursor]; + } + if (isMdxBlock) { return content; } diff --git a/tests/format/jsx/cursor/__snapshots__/jsfmt.spec.js.snap b/tests/format/jsx/cursor/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000..496e57842 --- /dev/null +++ b/tests/format/jsx/cursor/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,20 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`in-jsx-text.js format 1`] = ` +====================================options===================================== +cursorOffset: 3 +parsers: ["babel", "typescript", "flow"] +printWidth: 80 + | printWidth +=====================================input====================================== +<>a<|> +
hi
+ + +=====================================output===================================== +<> + a<|>
hi
+; + +================================================================================ +`; diff --git a/tests/format/jsx/cursor/in-jsx-text.js b/tests/format/jsx/cursor/in-jsx-text.js new file mode 100644 index 000000000..aaa114af6 --- /dev/null +++ b/tests/format/jsx/cursor/in-jsx-text.js @@ -0,0 +1,3 @@ +<>a<|> +
hi
+ diff --git a/tests/format/jsx/cursor/jsfmt.spec.js b/tests/format/jsx/cursor/jsfmt.spec.js new file mode 100644 index 000000000..f7fd785f6 --- /dev/null +++ b/tests/format/jsx/cursor/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(import.meta, ["babel", "typescript", "flow"]);