diff --git a/changelog_unreleased/blog-post-intro.md b/changelog_unreleased/blog-post-intro.md new file mode 100644 index 000000000..594a19ced --- /dev/null +++ b/changelog_unreleased/blog-post-intro.md @@ -0,0 +1,9 @@ +--- +author: "Sosuke Suzuki (@sosukesuzuki)" +authorURL: "https://github.com/sosukesuzuki" +title: "Prettier 3.4: A lot of bug fixes" +--- + +This release includes numerous bug fixes and other improvements. + +If you appreciate Prettier and would like to support our work, please consider sponsoring us directly via [our OpenCollective](https://opencollective.com/prettier) or by sponsoring the projects we depend on, such as [typescript-eslint](https://opencollective.com/typescript-eslint), [remark](https://opencollective.com/unified), and [Babel](https://opencollective.com/babel). Thank you for your continued support! diff --git a/website/blog/2024-11-26-3.4.0.md b/website/blog/2024-11-26-3.4.0.md new file mode 100644 index 000000000..ae9778bdc --- /dev/null +++ b/website/blog/2024-11-26-3.4.0.md @@ -0,0 +1,854 @@ +--- +author: "Sosuke Suzuki (@sosukesuzuki)" +authorURL: "https://github.com/sosukesuzuki" +title: "Prettier 3.4: A lot of bug fixes" +--- + +This release includes numerous bug fixes and other improvements. + +If you appreciate Prettier and would like to support our work, please consider sponsoring us directly via [our OpenCollective](https://opencollective.com/prettier) or by sponsoring the projects we depend on, such as [typescript-eslint](https://opencollective.com/typescript-eslint), [remark](https://opencollective.com/unified), and [Babel](https://opencollective.com/babel). Thank you for your continued support! + + + +## Other Changes + +### JavaScript + +#### Fix template literal print with array ([#13315](https://github.com/prettier/prettier/pull/13315) by [@fisker](https://github.com/fisker), [@syi0808](https://github.com/syi0808)) + + +```jsx +// Input +const string = `${[[1, 2], [3, 4]]}` + +// Prettier 3.3 +const string = `${[ + [2], + [4], +]}`; + +// Prettier 3.4 +const string = `${[ + [1, 2], + [3, 4], +]}`; +``` + +#### Add missing parentheses in tagged template literals ([#16500](https://github.com/prettier/prettier/pull/16500) by [@syi0808](https://github.com/syi0808)) + + +```jsx +// Input +(String?.raw)``; +(getTag?.())``; + +// Prettier 3.3 +String?.raw``; +getTag?.()``; + +// Prettier 3.4 +(String?.raw)``; +(getTag?.())``; +``` + +#### Don't remove useless `\` in string literals ([#16563](https://github.com/prettier/prettier/pull/16563) by [@sosukesuzuki](https://github.com/sosukesuzuki), [#16763](https://github.com/prettier/prettier/pull/16763) by [@fisker](https://github.com/fisker)) + +Previously, Prettier would remove useless escape characters (`\`) from string literals. However, this behavior was inconsistent as it did not apply to template literals, which was reported in [issue #16542](https://github.com/prettier/prettier/issues/16542). + +This issue is a feature request to extend this behavior to template literals as well. + +After discussing this internally, the Prettier team concluded that removing useless escape characters, whether in string literals or template literals, is the responsibility of a linter, not a formatter. + +This change disables the removal of useless escape characters in string literals across all languages supported by Prettier. To keep the previous behavior, we recommend using ESLint rules like [`no-useless-escape`](https://eslint.org/docs/latest/rules/no-useless-escape). + +Escaped quotes (e.g. `"\"\'"`) may get unescaped when changing between different quotes. This is explained on the [Rationale](https://prettier.io/docs/en/rationale.html#strings) page of the official documentation. + + +```jsx +// Input +const str = "\a"; + +// Prettier 3.3 +const str = "a"; + +// Prettier 3.4 +const str = "\a"; +``` + +#### Improve comment formatting for logical expression in unary expression ([#16593](https://github.com/prettier/prettier/pull/16593) by [@sosukesuzuki](https://github.com/sosukesuzuki)) + + +```jsx +// Input +!( + cond1 || // foo + cond2 || // bar + cond3 // baz +); + +// Prettier 3.3 +!( + ( + cond1 || // foo + cond2 || // bar + cond3 + ) // baz +); + +// Prettier 3.4 +!( + cond1 || // foo + cond2 || // bar + cond3 // baz +); +``` + +#### Removed support for experimental syntax ([#16643](https://github.com/prettier/prettier/pull/16643), [#16705](https://github.com/prettier/prettier/pull/16705) by [@fisker](https://github.com/fisker)) + +- `DecimalLiteral` - The [Decimal proposal](https://github.com/tc39/proposal-decimal) decided not introduce new syntax. The `decimal` plugin will be removed from Babel 8. +- `importReflection` - The "Import Reflection" proposal has renamed as ["Source Phase Imports"](https://github.com/tc39/proposal-source-phase-imports) + +- [Disclaimer about non-standard syntax](https://prettier.io/docs/en/rationale.html#disclaimer-about-non-standard-syntax) + +### TypeScript + +#### Add missing parentheses in tagged template literals ([#16500](https://github.com/prettier/prettier/pull/16500) by [@syi0808](https://github.com/syi0808)) + + +```jsx +// Input +(String?.raw!)``; +(String?.raw)!``; + +// Prettier 3.3 +String?.raw!``; +String?.raw!``; + +// Prettier 3.4 +(String?.raw)!``; +(String?.raw)!``; +``` + +#### Preserve a comment on between decorator and modified parameter property ([#16574](https://github.com/prettier/prettier/pull/16574) by [@sosukesuzuki](https://github.com/sosukesuzuki)) + +The current version of Prettier unexpectedly moves a line comment between a parameter property modified by `readonly`, `private`, `public`, etc and a decorator. This output results in invalid TypeScript code. + +This change ensures that the original format is preserved. + + +```ts +// Input +class Foo { + constructor( + @decorator + // comment + readonly foo, + ) {} +} + +// Output (stable) +class Foo { + constructor( + @decorator + readonly // comment + foo, + ) {} +} + +// Output (main) +class Foo { + constructor( + @decorator + // comment + readonly foo, + ) {} +} +``` + +#### Preserve a comment between modifier and the decorated property name ([#16578](https://github.com/prettier/prettier/pull/16578) by [@sosukesuzuki](https://github.com/sosukesuzuki)) + +There was a bug where block comments between the modifier and the name of a decorated property were being treated as trailing comments of the decorator. This behavior was not only unexpected but also lacked idempotency. + +With this change, the position of the block comment between the modifier and the property name is preserved. + + +```tsx +// Input +class Foo { + @decorator + readonly /* comment */ propertyName; +} + +// Prettier 3.3 +class Foo { + @decorator /* comment */ + readonly propertyName; +} + +// Prettier 3.3 (second output) +class Foo { + @decorator /* comment */ readonly propertyName; +} + +// Prettier 3.4 +class Foo { + @decorator + readonly /* comment */ propertyName; +} +``` + +#### Don't print an extra line break for arrow function with type parameter in assignment ([#16586](https://github.com/prettier/prettier/pull/16586) by [@sosukesuzuki](https://github.com/sosukesuzuki)) + +There was a bug where an extra line was inserted when assigning a chained arrow function with type parameters to a variable if there was a line comment above it. + +This change ensures that the extra line is no longer inserted. + + +```tsx +// Input +const foo1 = + // comment + () => () => 1; + +// Prettier 3.3 +const foo1 = + // comment + + () => + () => + 1; + +// Prettier 3.4 +const foo1 = + // comment + () => + () => + 1; +``` + +#### Support "Top-level await statements" ([#16729](https://github.com/prettier/prettier/pull/16729) by [@fisker](https://github.com/fisker)) + + +```tsx +// Input +(await (await fetch()).json()).foo + +// Prettier 3.3 +await(await fetch()).json().foo; + +// Prettier 3.4 +(await (await fetch()).json()).foo; +``` + +#### Fix class heritage breaks even though it remains inside the line width ([#16730](https://github.com/prettier/prettier/pull/16730) by [@fisker](https://github.com/fisker)) + + +```tsx +// Input +export class JiraCreatePixFraudDetectionGateway + implements Pick +{ + constructor(private readonly logger: Logger) { + this.logger = logger.child({ + context: JiraCreatePixFraudDetectionGateway.name, + }); + } +} + +// Prettier 3.3 +export class JiraCreatePixFraudDetectionGateway + implements + Pick +{ + constructor(private readonly logger: Logger) { + this.logger = logger.child({ + context: JiraCreatePixFraudDetectionGateway.name, + }); + } +} + +// Prettier 3.4 +export class JiraCreatePixFraudDetectionGateway + implements Pick +{ + constructor(private readonly logger: Logger) { + this.logger = logger.child({ + context: JiraCreatePixFraudDetectionGateway.name, + }); + } +} +``` + +#### Print `declare` before accessibility in class properties ([#16731](https://github.com/prettier/prettier/pull/16731) by [@fisker](https://github.com/fisker)) + + +```tsx +// Input +class A { + declare private readonly name: string; +} + +// Prettier 3.3 +class A { + private declare readonly name: string; +} + +// Prettier 3.4 +class A { + declare private readonly name: string; +} +``` + +### CSS + +#### Resolve some types of overrun in CSS ([#16570](https://github.com/prettier/prettier/pull/16570) by [@seiyab](https://github.com/seiyab)) + + +```css +/* Input */ +@media (prefers-reduced-data: no-preference) { + @font-face { + unicode-range: U+0000-00FF, U+0131, +U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; + } +} + +/* Prettier 3.3 */ +@media (prefers-reduced-data: no-preference) { + @font-face { + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, + U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, + U+2215, U+FEFF, U+FFFD; + } +} + +/* Prettier 3.4 */ +@media (prefers-reduced-data: no-preference) { + @font-face { + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, + U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, + U+2212, U+2215, U+FEFF, U+FFFD; + } +} +``` + +#### Remove extra indentation in pseudo-class function ([#16572](https://github.com/prettier/prettier/pull/16572) by [@sosukesuzuki](https://github.com/sosukesuzuki)) + +This change fixes a bug where extra indentation was added when line breaks were included in the argument list of pseudo-class functions like [`:where()`](https://developer.mozilla.org/en-US/docs/Web/CSS/:where), [`:is()`](https://developer.mozilla.org/en-US/docs/Web/CSS/:is), and [`:not`](https://developer.mozilla.org/en-US/docs/Web/CSS/:not). + + +```css +/* Input */ +:where(input:not([type="button"], [type="reset"], [type="submit"]), textarea, select) { + /* CSS here */ +} + +/* Prettier 3.3 */ +:where( + input:not([type="button"], [type="reset"], [type="submit"]), + textarea, + select + ) { + /* CSS here */ +} + +/* Prettier 3.4 */ +:where( + input:not([type="button"], [type="reset"], [type="submit"]), + textarea, + select +) { + /* CSS here */ +} + +``` + +#### Fix formatting of incomplete CSS value comments ([#16583](https://github.com/prettier/prettier/pull/16583) by [@sosukesuzuki](https://github.com/sosukesuzuki), [@fisker](https://github.com/fisker)) + +When formatting CSS value comments, the trailing `/` may be lost, resulting in an invalid comment. + +This change ensures that value comments are not truncated. + + +```css +/* Input */ +h1 { + --OFF: /* OFF */; +} + +/* Prettier 3.3 */ +h1 { + --OFF: /* OFF *; +} + +/* Prettier 3.4 */ +h1 { + --OFF: /* OFF */; +} +``` + +### SCSS + +#### Fix error thrown when formatting SCSS file ([#16607](https://github.com/prettier/prettier/pull/16607) by [@fisker](https://github.com/fisker)) + + +```scss +// Input +@if true { + $newKey: ($key: ( $theme-name: $value )) +} + +// Prettier 3.3 +Error + +// Prettier 3.4 +@if true { + $newKey: ( + $key: + ( + $theme-name: $value, + ), + ); +} +``` + +#### Fix wrong trailing comma position after comment in SCSS ([#16617](https://github.com/prettier/prettier/pull/16617) by [@Ma-hawaj](https://github.com/Ma-hawaj), [@fisker](https://github.com/fisker)) + + +```css +/* Input */ +$z-indexes: ( + header: 1035, + overlay: 1202 // TODO: change to 1050 after bootstrap modals will be removed +); + +/* Prettier 3.3 */ +$z-indexes: ( + header: 1035, + overlay: 1202 // TODO: change to 1050 after bootstrap modals will be removed, +); + +/* Prettier 3.4 */ +$z-indexes: ( + header: 1035, + overlay: 1202, // TODO: change to 1050 after bootstrap modals will be removed +); +``` + +### HTML + +#### Keep doctype in non-html files unchanged ([#16765](https://github.com/prettier/prettier/pull/16765) by [@fisker](https://github.com/fisker)) + +In Prettier v3, [we print HTML5 doctype in lowercase](https://prettier.io/blog/2023/07/05/3.0.0#print-html5-doctype-in-lowercase-7391httpsgithubcomprettierprettierpull7391-by-fiskerhttpsgithubcomfisker), it's safe for HTML files, however users may use the `html` parser to format other files eg: XHTML files, lowercase the `doctype` will break XHTML documents. + +Since Prettier 3.4, we'll only lowercase [HTML5 doctype (``)](https://developer.mozilla.org/en-US/docs/MDN/Writing_guidelines/Writing_style_guide/Code_style_guide/HTML#doctype) when the file extension is `.html` or `.htm`, otherwise they will be untouched. + + +```html + + + + + + + + + +``` + +### Vue + +#### Fix extra semicolon inserted in Vue event binding with non-ascii characters ([#16733](https://github.com/prettier/prettier/pull/16733) by [@fisker](https://github.com/fisker)) + + +```vue + + + + + + + + +``` + +### Angular + +#### Support Angular 19 ([#16862](https://github.com/prettier/prettier/pull/16862) by [@fisker](https://github.com/fisker)) + +Angular 19 added [support for `typeof` keyword in template expressions](https://github.com/angular/angular/pull/58183). + + +```html + +
{{ typeof + x === + 'object' ? 'Y' : 'N'}}
+ + +
+ {{ typeof + x === + 'object' ? 'Y' : 'N'}} +
+ +// Prettier 3.4 +
{{ typeof x === "object" ? "Y" : "N" }}
+``` + +### Markdown + +#### Remove excessive spaces after line prefixes for unordered lists in Markdown ([#15526](https://github.com/prettier/prettier/pull/15526) by [@TomasLudvik](https://github.com/TomasLudvik)) + + +```md + +- first line + - second line indented +- third line + - fourth line + - fifth line + + +- first line + - second line indented +- third line + - fourth line + - fifth line + + +- first line + - second line indented +- third line + - fourth line + - fifth line +``` + +#### Fix incorrect wrap in sentence with linkReference ([#16546](https://github.com/prettier/prettier/pull/16546) by [@seiyab](https://github.com/seiyab)) + + +```md + +This folder has [VHS] tape files to create gifs for the [Widget Showcase]. To run them, install VHS from main (the theme and screenshot commands are not yet released). + + +This folder has [VHS] tape files to create gifs for the [Widget Showcase]. To run +them, install VHS from main (the theme and screenshot commands are not yet released). + + +This folder has [VHS] tape files to create gifs for the [Widget Showcase]. To +run them, install VHS from main (the theme and screenshot commands are not yet +released). +``` + +#### Preserve non-ASCII whitespaces at the end of the line and beginning of the next line ([#16619](https://github.com/prettier/prettier/pull/16619) by [@tats-u](https://github.com/tats-u)) + +Prettier removes non-ASCII spaces at the end of the line and beginning of the next line. However, this behavior is not consistent with the CommonMark spec. + +https://spec.commonmark.org/0.31.2/#soft-line-breaks + +> Spaces at the end of the line and beginning of the next line are removed: + +https://spec.commonmark.org/0.31.2/#unicode-whitespace-character + +> A Unicode whitespace character is a character in the Unicode Zs general category, or a tab (U+0009), line feed (U+000A), form feed (U+000C), or carriage return (U+000D). + +> Unicode whitespace is a sequence of one or more Unicode whitespace characters. + +> A space is U+0020. + +The CommonMark spec doesn't mention non-ASCII spaces here, so removing them changes the content of the Markdown document. + + +```md + + EM Space (U+2003) EM Space  + + 全角スペース (U+3000) 全形空白  + + +EM Space (U+2003) EM Space + +全角スペース (U+3000) 全形空白 + + + EM Space (U+2003) EM Space  + + 全角スペース (U+3000) 全形空白  +``` + +#### Don't break a line a between Chinese or Japanese and others ([#16691](https://github.com/prettier/prettier/pull/16691) by [@tats-u](https://github.com/tats-u)) + +Markdown documents are mainly converted to HTML or components of JavaScript-based frameworks. This means that paragraphs in Markdown are eventually processed by the browser according to [CSS rules](https://drafts.csswg.org/css-text-4/). This is because many Markdown converter preserve line breaks in paragraphs in input Markdown and HTML itself does not specify how browsers should handle line breaks in text in HTML. + +According to [CSS rules (CSS Text Module Level 3 or later)](https://drafts.csswg.org/css-text-4/#line-break-transform), browsers should remove line breaks between Chinese/Japanese characters instead of replacing them with spaces. However, this rule has been ignored by WebKit-based or Webkit-derived browsers (Chrome, Safari, and so on) for long time. + +For example, the following HTML paragraph: + + +```html +

+日本語 +汉语 +漢語 +

+``` + +generated from the following Markdown: + +```md +日本語 +汉语 +漢語 +``` + +should be rendered as follows according to CSS rules and actually is rendered such by Firefox: + +```md +日本語汉语漢語 +``` + +However, Chrome and Safari render it as follows: + +```md +日本語 汉语 漢語 +``` + +This is why we should stop Prettier from line breaking between Chinese/Japanese characters. We decided to stop Prettier from forcing users to use a plugin for a Markdown converter that concatenates lines that start or end with Chinese/Japanese characters ([remark-join-cjk-lines](https://www.npmjs.com/package/remark-join-cjk-lines), for example). + +Also, [a line break between Chinese/Japanese and others are equivalent to a space](https://github.com/w3c/csswg-drafts/blob/076914a198bf3ac642001619e08acefdf607d61d/css-text/Overview.bs#L712) according to before [the commit suspending a concrete rule in CSS Text Module Level 3 by commenting it out](https://github.com/w3c/csswg-drafts/commit/b3bb0ed18b3168981c54c437bcfb5881ef49975b) fixing [an issue on the CSS Working Group Editor Drafts](https://github.com/w3c/csswg-drafts/issues/5086). Firefox follows this rule. Therefore, all browsers render the following paragraph: + +````html + +```html +

日本語 English 汉语 한국어 漢語

+ +

+```` + +as follows: + +```md +日本語 English 汉语 한국어 漢語 +``` + +However, Prettier has broken a line between Chinese/Japanese characters in Markdown for a long time, and between Chinese/Japanese and latin characters in some cases since 3.0.0. For example, the following Markdown paragraph: + +```md +日本語English汉语 +English +漢語 +``` + +is formatted as follows if `--prose-wrap` is set to the other value than `preserve` in Prettier 3.x: + +```md +日本語English汉语English漢語 +``` + +However, the following HTML, which is generated by a Markdown-to-HTML converter based on the above Markdown: + + +```html +

+日本語English汉语 +English +漢語 +

+``` + +is rendered as follows by all browsers: + +```md +日本語English汉语 English 漢語 +``` + +This is why we should stop Prettier from line breaking al so around Chinese/Japanese characters in Markdown. We are going to conform Prettier's behavior to this rule in a future version. After that, line breaks between Chinese/Japanese and others will be allowed again under certain rules. + +One of the few exceptions is spaces and line breaks between Chinese/Japanese and Korean letters. The following Markdown paragraphs are equivalent even in the current Prettier version: + +```md +현재 韓國의 大統領은 尹錫悅이다. +``` + +```md +현재 +韓國의 +大統領은 +尹錫悅이다. +``` + +You get the former if you format the latter with `--prose-wrap=always` and a sufficiently long `--print-width` value or with `--prose-wrap=never`, and you get the latter if you format the former with `--prose-wrap=always` with a extremely short `--print-width` value. Therefore, we do not have to touch such spaces and line breaks. + +Another exception is those between a Chinese/Japanese character and a meaningful symbol in Markdown like `*`, `` ` ``, `[`, and `]`. For example, the following Markdown paragraph is equivalent even in the current Prettier version: + +```md +**Yarn** のCLI経由でフォーマットするには `yarn prettier -w ` を実行してください。 +``` + +```md +**Yarn** +のCLI経由でフォーマットするには +`yarn prettier -w .` +を実行してください。 +``` + + +```md + +日本語 汉语 漢語 English 한국어 日本語 汉语 漢語 English 한국어 日本語 汉语 漢語 English 한국어 日本語 汉语 漢語 English 한국어 + +日本語汉语漢語English한국어日本語汉语漢語English한국어日本語汉语漢語English한국어日本語汉语漢語English한국어 + + +日本語 汉语 漢語 +English 한국어 日本 +語 汉语 漢語 English +한국어 日本語 汉语 +漢語 English 한국어 +日本語 汉语 漢語 +English 한국어 + +日本語汉语漢語 +English한국어日本語 +汉语漢語 +English한국어日本語 +汉语漢語 +English한국어日本語 +汉语漢語 +English한국어 + + +日本語 汉语 漢語 English +한국어 +日本語 汉语 漢語 English +한국어 +日本語 汉语 漢語 English +한국어 +日本語 汉语 漢語 English +한국어 + +日本語汉语漢語English한국어日本語汉语漢語English한국어日本語汉语漢語English한국어日本語汉语漢語English한국어 +``` + +#### Tell regexp-util to generate regex compatible with u flag ([#16816](https://github.com/prettier/prettier/pull/16816) by [@tats-u](https://github.com/tats-u)) + +CJK characters outside of BMP and Ideographic Variation Sequences (IVS; variation selectors dedicated for han/kanji), which consume 2 characters in JavaScript string, have not been treated as CJK. This is due to the fact that Prettier has not passed the appropriate flag `"u"` to the `regexp-util` package. + +In the following example, “𠮷” (U+20BB7) is out of BMP, and “葛󠄀” is a combination of a han “葛” (U+845B) in BMP and an IVS U+E0100. The latter requires a font with the support of Adobe Japan-1 (e.g. Yu Gothic UI and Source Han Sans) to be rendered as a form different from that of the character without IVS (葛). + + +```md + +a 字 a 字 a 字 +𠮷 +𠮷 +葛󠄀 +葛󠄀 +終 + + +a 字 a 字 a 字 𠮷 𠮷 葛󠄀 葛󠄀 終 + + +a 字 a 字 a 字𠮷𠮷葛󠄀葛󠄀終 + +``` + +### YAML + +#### Fix yaml comment in non-singleline items missing space before `#` ([#16489](https://github.com/prettier/prettier/pull/16489) by [@fyc09](https://github.com/fyc09)) + + +```yaml +# Input +123: # hello + # comment + +# Prettier 3.3 +123:# hello + # comment + +# Prettier 3.4 +123: # hello + # comment +``` + +### API + +#### Stop doc mutation in `prettier.doc.printDocToString` ([#13315](https://github.com/prettier/prettier/pull/13315) by [@fisker](https://github.com/fisker)) + +For performance reason, `prettier.doc.printDocToString` used to mutate `.parts` of the [`fill`](https://github.com/prettier/prettier/blob/main/commands.md#fill) command during print. It was converted to a [pure function](https://en.wikipedia.org/wiki/Pure_function) to ensure output correctness. + +#### Make `getPreferredQuote` public ([#16567](https://github.com/prettier/prettier/pull/16567) by [@sosukesuzuki](https://github.com/sosukesuzuki)) + +This change makes the internal `getPreferredQuote` function a part of the public API. + +In languages like JavaScript, both single quotes and double quotes can be used for string literals. Prettier determines the quote to enclose a string literal based on the number of quotes within the string and the value of the [`singleQuote`](https://prettier.io/docs/en/options#quotes) option. For more details, please refer to the [Rationale](https://prettier.io/docs/en/rationale.html#strings) page. + +The `getPreferredQuote` function determines the appropriate quote to enclose a string literal and has the following interface: + +```ts +type Quote = '"' | "'"; +function getPreferredQuote( + text: string, + preferredQuoteOrPreferSingleQuote: Quote | boolean, +): Quote; +``` + +Here are some examples of how to use it: + + +```jsx +import * as prettier from "prettier"; + +const SINGLE_QUOTE = `'`; +const DOUBLE_QUOTE = `"`; + +console.log(prettier.util.getPreferredQuote(`Hello World Test`, SINGLE_QUOTE)); // ' +console.log(prettier.util.getPreferredQuote(`Hello World Test`, DOUBLE_QUOTE)); // " +console.log(prettier.util.getPreferredQuote(`'Hello' "World" 'Test'`, SINGLE_QUOTE)); // " +console.log(prettier.util.getPreferredQuote(`"Hello" 'World' "Test"`, DOUBLE_QUOTE)); // ' +console.log(prettier.util.getPreferredQuote(`"Hello" "World" "Test"`, SINGLE_QUOTE)); // ' +console.log(prettier.util.getPreferredQuote(`'Hello' 'World' 'Test'`, DOUBLE_QUOTE)); // " +``` + +Making this function public will benefit plugin developers. Since the function is relatively short, you can find more details in the [implementation](https://github.com/prettier/prettier/blob/509a0cc10f12cbfa5304737965f99284449aca88/src/utils/get-preferred-quote.js). + +#### Fix loading ESM-style shared config file in Node.js 23 ([#16857](https://github.com/prettier/prettier/pull/16857) by [@sosukesuzuki](https://github.com/sosukesuzuki)) + +In Prettier 3.3, attempting to load an ESM-style [shared config file](https://prettier.io/docs/en/sharing-configurations) in Node.js 23 resulted in the following warnings, preventing the options from being loaded: + +``` +[warn] Ignored unknown option { __esModule: true }. +[warn] Ignored unknown option { default: { trailingComma: "es5", tabWidth: 4, singleQuote: true } }. +``` + +This issue was caused by a new module feature in Node.js 23, known as [`require(ESM)`](https://nodejs.org/api/modules.html#loading-ecmascript-modules-using-require). Prettier 3.4 resolves this problem, allowing the options to load correctly. + +For more details, please see https://github.com/prettier/prettier/issues/16812. + +### CLI + +#### Ignore files in the Jujutsu directory ([#16684](https://github.com/prettier/prettier/pull/16684) by [@marcusirgens](https://github.com/marcusirgens)) + +The Jujutsu VCS uses the `.jj` directory, similarly to how Git uses `.git`. + +This change adds `.jj` to the list of directories which are silently ignored by prettier. + +### Miscellaneous + +#### Fix `cursorOffset` feature sometimes being catastrophically slow ([#15709](https://github.com/prettier/prettier/pull/15709) by [@ExplodingCabbage](https://github.com/ExplodingCabbage)) + +Previously, Prettier's `cursorOffset` feature would be spectacularly slow in certain unfortunate circumstances (namely when the user's cursor was not contained within a leaf node of the AST, and the non-leaf node containing it was very large and being significantly reformatted by Prettier). As a consequence, if you used Prettier via an editor integration that used `cursorOffset` under the hood, your editor would sometimes inexplicably hang when you tried to format a file. + +All examples of this phenomenon that we are aware of should now be fixed, but bug reports of any further pathological examples would be welcome.