diff --git a/changelog_unreleased/blog-post-intro.md b/changelog_unreleased/blog-post-intro.md new file mode 100644 index 000000000..a9a39ed08 --- /dev/null +++ b/changelog_unreleased/blog-post-intro.md @@ -0,0 +1,14 @@ +--- +authors: "sosukesuzuki" +title: "Prettier 3.6: Experimental fast CLI and new OXC and Hermes plugins!" +--- + +This release includes several important feature additions that we're excited to share with you. + +First, we're shipping a new experimental high-performance CLI behind a feature flag (`--experimental-cli`). This CLI was previously only available in `prettier@next`, but now you can enable it simply by using a flag. We encourage you to try it out and share your feedback! If you are interested in the internal implementation, please read [Prettier's CLI: Performance Deep Dive by Fabio](https://prettier.io/blog/2023/11/30/cli-deep-dive). + +Additionally, we're releasing two new official plugins: [`@prettier/plugin-oxc`](https://github.com/prettier/prettier/tree/main/packages/plugin-oxc) and [`@prettier/plugin-hermes`](https://github.com/prettier/prettier/tree/main/packages/plugin-hermes). These plugins are provided separately from Prettier's core. + +We want to extend our heartfelt gratitude to everyone who made this amazing release possible: [@fabiospampinato](https://github.com/fabiospampinato), [@43081j](https://github.com/43081j), and [@pralkarz](https://github.com/pralkarz) along with the new CLI contributors, [@boshen](https://github.com/boshen) and [@overlookmotel](https://github.com/overlookmotel) along with other OXC contributors, the [Flow](https://flow.org/) and [Hermes](https://github.com/facebook/hermes/blob/main/README.md) teams at Meta. Thank you all for your incredible contributions! + +We're excited to see how these new features enhance your development experience. Happy formatting! diff --git a/changelog_unreleased/javascript/17472.md b/changelog_unreleased/javascript/17472.md index 3ed660964..94a228b7c 100644 --- a/changelog_unreleased/javascript/17472.md +++ b/changelog_unreleased/javascript/17472.md @@ -21,6 +21,4 @@ Due to package size limitations, this plugin is not included in the `prettier` p For more information, check [the package homepage](https://github.com/prettier/prettier/tree/main/packages/plugin-oxc). - - -Many thanks to the OXC team(@boshen, @overlookmotel, and other contributors). +Many thanks to the OXC team([@boshen](https://github.com/boshen), [@overlookmotel](https://github.com/overlookmotel), and other contributors). diff --git a/website/blog/2025-06-23-3.6.0.md b/website/blog/2025-06-23-3.6.0.md new file mode 100644 index 000000000..62bfe4ded --- /dev/null +++ b/website/blog/2025-06-23-3.6.0.md @@ -0,0 +1,1118 @@ +--- +authors: "sosukesuzuki" +title: "Prettier 3.6: Experimental fast CLI and new OXC and Hermes plugins!" +--- + +This release includes several important feature additions that we're excited to share with you. + +First, we're shipping a new experimental high-performance CLI behind a feature flag (`--experimental-cli`). This CLI was previously only available in `prettier@next`, but now you can enable it simply by using a flag. We encourage you to try it out and share your feedback! If you are interested in the internal implementation, please read [Prettier's CLI: Performance Deep Dive by Fabio](https://prettier.io/blog/2023/11/30/cli-deep-dive). + +Additionally, we're releasing two new official plugins: [`@prettier/plugin-oxc`](https://github.com/prettier/prettier/tree/main/packages/plugin-oxc) and [`@prettier/plugin-hermes`](https://github.com/prettier/prettier/tree/main/packages/plugin-hermes). These plugins are provided separately from Prettier's core. + +We want to extend our heartfelt gratitude to everyone who made this amazing release possible: [@fabiospampinato](https://github.com/fabiospampinato), [@43081j](https://github.com/43081j), and [@pralkarz](https://github.com/pralkarz) along with the new CLI contributors, [@boshen](https://github.com/boshen) and [@overlookmotel](https://github.com/overlookmotel) along with other OXC contributors, the [Flow](https://flow.org/) and [Hermes](https://github.com/facebook/hermes/blob/main/README.md) teams at Meta. Thank you all for your incredible contributions! + +We're excited to see how these new features enhance your development experience. Happy formatting! + + + +## Highlights + +### JavaScript + +#### Added a new official plugin `@prettier/plugin-oxc` ([#17472](https://github.com/prettier/prettier/pull/17472), [#17483](https://github.com/prettier/prettier/pull/17483) by [@fisker](https://github.com/fisker)) {#change-17472} + +`@prettier/plugin-oxc` is based on [OXC](https://oxc.rs/)(A **fast** JavaScript and TypeScript parser in Rust). + +This plugin includes two new parsers `oxc` (JavaScript syntax) and `oxc-ts` (TypeScript syntax), to use this plugin: + +1. Install the plugin + + ```sh + yarn add --dev prettier @prettier/plugin-oxc + ``` + +2. Add the following to your `.prettierrc` file + + ```yaml + plugins: + - "@prettier/plugin-oxc" + ``` + +Due to package size limitations, this plugin is not included in the `prettier` package, it needs to be installed separately. + +For more information, check [the package homepage](https://github.com/prettier/prettier/tree/main/packages/plugin-oxc). + +Many thanks to the OXC team([@boshen](https://github.com/boshen), [@overlookmotel](https://github.com/overlookmotel), and other contributors). + +### Flow + +#### Added a new official plugin `@prettier/plugin-hermes` ([#17520](https://github.com/prettier/prettier/pull/17520) by [@fisker](https://github.com/fisker)) {#change-17520} + +`@prettier/plugin-hermes` is based on [Hermes JS Engine](https://github.com/facebook/hermes/blob/main/README.md). + +This plugin includes a new parser `hermes` (Flow syntax), to use this plugin: + +1. Install the plugin + + ```sh + yarn add --dev prettier @prettier/plugin-hermes + ``` + +2. Add the following to your `.prettierrc` file + + ```yaml + plugins: + - "@prettier/plugin-hermes" + ``` + +Due to package size limitations, this plugin is not included in the `prettier` package, it needs to be installed separately. + +**We plan to make this as the default parser for Flow syntax support in v4, we'll also remove `babel-flow` parser in v4, please give it a try.** + +For more information, check [the package homepage](https://github.com/prettier/prettier/tree/main/packages/plugin-hermes). + +Many thanks to the Hermes team. + +### CLI + +#### Support experimental CLI ([#17151](https://github.com/prettier/prettier/pull/17151), [#17396](https://github.com/prettier/prettier/pull/17396) by [@fisker](https://github.com/fisker)) {#change-17151} + +You may have already heard of or used our new [performance improved CLI](https://prettier.io/blog/2023/11/30/cli-deep-dive). From Prettier 3.6, you can now use it without installing unstable v4 version. + +```sh +# Run CLI with `--experimental-cli` +prettier . --check --experimental-cli + +# Or use environment variable `PRETTIER_EXPERIMENTAL_CLI=1` +PRETTIER_EXPERIMENTAL_CLI=1 prettier . --check +``` + +## Other Changes + +### JavaScript + +#### Add parentheses to `SequenceExpression` in `ReturnStatement` and `ExpressionStatement` ([#17085](https://github.com/prettier/prettier/pull/17085) by [@TYKevin](https://github.com/TYKevin)) {#change-17085} + + +```jsx +// Input +function a() { + return ( a, b) +} + +(a(), b()); + +// Prettier 3.5 +function a() { + return a, b; +} + +a(), b(); + +// Prettier 3.6 +function a() { + return (a, b); +} + +(a(), b()); +``` + +#### Add parentheses to `AssignmentExpression` in class property keys ([#17145](https://github.com/prettier/prettier/pull/17145) by [@fisker](https://github.com/fisker)) {#change-17145} + +Previously we only add parentheses to `AssignmentExpression` in object keys, but not in class property keys. Thanks to [Biome](https://biomejs.dev/formatter/differences-with-prettier/#prettier-has-an-inconsistent-behavior-for-assignment-in-computed-keys) for bringing our attention to this inconsistency. + + +```jsx +// Input +a = { + [(x = "key")]: 1, +} + +class A { + [(x = "property")] = 1; + [(x = "method")]() {} +} + +// Prettier 3.5 +a = { + [(x = "key")]: 1, +}; + +class A { + [x = "property"] = 1; + [(x = "method")]() {} +} + +// Prettier 3.6 +a = { + [(x = "key")]: 1, +}; + +class A { + [(x = "property")] = 1; + [(x = "method")]() {} +} +``` + +#### Add parentheses to numbers in optional member expression ([#17190](https://github.com/prettier/prettier/pull/17190) by [@fisker](https://github.com/fisker)) {#change-17190} + +There is an inconsistency when formatting member expression where the object is a number before Prettier 3.6. + +When using `babel` parser(and other Babel based parsers), we print the number as unparenthesized, when using `typescript` parser(and other ESTree parsers), we print it as parenthesized. + +Technically parentheses are not needed, but if we print it as `1?.toString()` and later users realize it's unnecessary to use `?.`, users can't simply remove the question mark because `1.toString()` will raise a `SyntaxError`, for this reason, we decide to always put parentheses around it. + + +```jsx +// Input +(1)?.toString(); +(1.5)?.toString(); + +// Prettier 3.5 (--parser=babel) +1?.toString(); +1.5?.toString(); + +// Prettier 3.5 (--parser=typescript) +(1)?.toString(); +(1.5)?.toString(); + +// Prettier 3.6 +(1)?.toString(); +(1.5)?.toString(); +``` + +#### Removed support for experimental `Records & Tuples` ([#17363](https://github.com/prettier/prettier/pull/17363) by [@fisker](https://github.com/fisker)) {#change-17363} + +The ES proposal [JavaScript Records & Tuples Proposal](https://github.com/tc39/proposal-record-tuple) has been withdrawn. + +- [Disclaimer about non-standard syntax](https://prettier.io/docs/en/rationale.html#disclaimer-about-non-standard-syntax) + +#### Preserve spaces between CSS words and embedded expression ([#17398](https://github.com/prettier/prettier/pull/17398) by [@sosukesuzuki](https://github.com/sosukesuzuki)) {#change-17398} + + +```jsx +// Input +const Heading = styled.h1` + font-size: var(--font-size-h${level}); +`; + +// Prettier 3.5 +const Heading = styled.h1` + font-size: var(--font-size-h ${level}); +`; + +// Prettier 3.6 +const Heading = styled.h1` + font-size: var(--font-size-h${level}); +`; +``` + +#### Fix inconsistent assignment format ([#17469](https://github.com/prettier/prettier/pull/17469) by [@fisker](https://github.com/fisker)) {#change-17469} + + +```jsx +// Input +didScheduleRenderPhaseUpdateDuringThisPassFoo = didScheduleRenderPhaseUpdate = true + +// Prettier 3.5 (--parser=babel) +didScheduleRenderPhaseUpdateDuringThisPassFoo = + didScheduleRenderPhaseUpdate = true; + +// Prettier 3.5 (--parser=typescript) +didScheduleRenderPhaseUpdateDuringThisPassFoo = didScheduleRenderPhaseUpdate = + true; + +// Prettier 3.6 +didScheduleRenderPhaseUpdateDuringThisPassFoo = + didScheduleRenderPhaseUpdate = true; +``` + +#### Fix inconsistent member chain format ([#17470](https://github.com/prettier/prettier/pull/17470) by [@fisker](https://github.com/fisker)) {#change-17470} + + +```jsx +// Input +s.get(u)?.trigger({ triggerKind: y.SignatureHelpTriggerKind.InvokeFooBarBaz123 }); + +// Prettier 3.5 (--parser=babel) +s.get(u)?.trigger({ + triggerKind: y.SignatureHelpTriggerKind.InvokeFooBarBaz123, +}); + +// Prettier 3.5 (--parser=typescript) +s + .get(u) + ?.trigger({ triggerKind: y.SignatureHelpTriggerKind.InvokeFooBarBaz123 }); + +// Prettier 3.6 +s.get(u)?.trigger({ + triggerKind: y.SignatureHelpTriggerKind.InvokeFooBarBaz123, +}); +``` + +#### Fix optional chaining as computed key ([#17486](https://github.com/prettier/prettier/pull/17486) by [@fisker](https://github.com/fisker)) {#change-17486} + + +```jsx +// Input +const a = { [y?.z]() {} }; +class A { [y?.z]() {} }; + +// Prettier 3.5 +const a = { [y?.z]?() {} }; +class A { + [y?.z]?() {} +} + +// Prettier 3.6 +const a = { [y?.z]() {} }; +class A { + [y?.z]() {} +} +``` + +#### Support type cast comments for `acorn` and `meriyah` parser ([#17491](https://github.com/prettier/prettier/pull/17491), [#17566](https://github.com/prettier/prettier/pull/17566) by [@ArnaudBarre](https://github.com/ArnaudBarre), [#17600](https://github.com/prettier/prettier/pull/17600) by #fisker) {#change-17491} + +This was previously only supported by the Babel parser. + + +```js +// Input +/** @type {MyType} */ (x).foo; + +// Prettier 3.5 (--parser=acorn|meriyah) +/** @type {MyType} */ x.foo; + +// Prettier 3.6 +/** @type {MyType} */ (x).foo; +``` + +#### Fix unstable comment format in tagged template literal ([#17510](https://github.com/prettier/prettier/pull/17510) by [@fisker](https://github.com/fisker)) {#change-17510} + + +```js +// Input +foo + // Comment + `x` + +// Prettier 3.5 (First format) +foo// Comment +`x`; + +// Prettier 3.5 (Second format) +foo // Comment +`x`; + +// Prettier 3.6 +foo // Comment +`x`; +``` + +#### Improve consistency for JSX in optional method call ([#17616](https://github.com/prettier/prettier/pull/17616) by [@seiyab](https://github.com/seiyab)) {#change-17616} + + +```jsx +// Input + +
+ {Array(20) + .fill() + ?.map((_, i) => ( +

{i + 1}

+ ))} +
+
; + +// Prettier 3.5 (ESTree based parsers like espree and typescript) + +
+ {Array(20) + .fill() + ?.map((_, i) =>

{i + 1}

)} +
+
; + +// Prettier 3.5 (babel and babel-ts parser) + +
+ {Array(20) + .fill() + ?.map((_, i) => ( +

{i + 1}

+ ))} +
+
; + +// Prettier 3.6 (parsers of both types) + +
+ {Array(20) + .fill() + ?.map((_, i) => ( +

{i + 1}

+ ))} +
+
; +``` + +### TypeScript + +#### Support import type attribute in `TSImportType` ([#16881](https://github.com/prettier/prettier/pull/16881) by [@fisker](https://github.com/fisker)) {#change-16881} + + +```jsx +// Input +type A = import("foo", {with: {type: "json"}}) + +// Prettier 3.5 +type A = import("foo") + +// Prettier 3.6 +type A = import("foo", { with: { type: "json" } }); +``` + +#### Fix comments in logical expression and intersection type ([#17193](https://github.com/prettier/prettier/pull/17193) by [@fisker](https://github.com/fisker)) {#change-17193} + + +```jsx +// Input +export type ErrorLike = + SerializedProps & + // cause is a new addition to Error that is not yet available in all runtimes. We have added + // it to try and pinpoint additional reasoning for failures such as Node's fetch. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause + { cause?: unknown }; + +// Prettier 3.5 +export type ErrorLike = + SerializedProps & // cause is a new addition to Error that is not yet available in all runtimes. We have added + // it to try and pinpoint additional reasoning for failures such as Node's fetch. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause + { cause?: unknown }; + +// Prettier 3.5 (second format) +export type ErrorLike = + SerializedProps & // it to try and pinpoint additional reasoning for failures such as Node's fetch. // cause is a new addition to Error that is not yet available in all runtimes. We have added + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause + { cause?: unknown }; + +// Prettier 3.6 +export type ErrorLike = SerializedProps & + // cause is a new addition to Error that is not yet available in all runtimes. We have added + // it to try and pinpoint additional reasoning for failures such as Node's fetch. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause + { cause?: unknown }; +``` + +#### Improve new line detect in mapped type ([#17498](https://github.com/prettier/prettier/pull/17498) by [@fisker](https://github.com/fisker)) {#change-17498} + + +```jsx +// Input +type A = { readonly + [A in B]: T} + +// Prettier 3.5 +type A = { + readonly [A in B]: T; +}; + +// Prettier 3.6 +type A = { readonly [A in B]: T }; +``` + +#### Don't print extra semicolon after `prettier-ignore`d index-signature ([#17538](https://github.com/prettier/prettier/pull/17538) by [@sosukesuzuki](https://github.com/sosukesuzuki)) {#change-17538} + + +```tsx +// Input +type foo = { + // prettier-ignore + [key: string]: bar; +}; + +// Prettier 3.5 +type foo = { + // prettier-ignore + [key: string]: bar;; +}; + +// Prettier 3.6 +type foo = { + // prettier-ignore + [key: string]: bar; +}; +``` + +### Flow + +#### Fix missing parentheses in `ConditionalTypeAnnotation` ([#17196](https://github.com/prettier/prettier/pull/17196) by [@fisker](https://github.com/fisker)) {#change-17196} + + +```jsx +// Input +type T = 'a' | ('b' extends U ? 'c' : empty); +type T = 'a' & ('b' extends U ? 'c' : empty); + +// Prettier 3.5 +type T = "a" | "b" extends U ? "c" : empty; +type T = "a" & "b" extends U ? "c" : empty; + +// Prettier 3.6 +type T = "a" | ("b" extends U ? "c" : empty); +type T = "a" & ("b" extends U ? "c" : empty); +``` + +### JSON + +#### Allow format comment-only JSONC files ([#17269](https://github.com/prettier/prettier/pull/17269) by [@fisker](https://github.com/fisker)) {#change-17269} + + +```jsonc +// Input +// Comment + +// Prettier 3.5 +SyntaxError: Unexpected token (1:11) +> 1 | // Comment + | ^ + +// Prettier 3.6 +// Comment +``` + +#### Forbid parenthesized expressions ([#17598](https://github.com/prettier/prettier/pull/17598) by [@fisker](https://github.com/fisker)) {#change-17598} + + +```json +// Input +[1, (2)] + +// Prettier 3.5 +[1, 2] + +// Prettier 3.6 +SyntaxError: 'ParenthesizedExpression' is not allowed in JSON. (1:5) +> 1 | [1, (2)] + | ^^^ +``` + +### CSS + +#### Support `@utility` directive for Tailwind ([#17362](https://github.com/prettier/prettier/pull/17362) by [@sosukesuzuki](https://github.com/sosukesuzuki)) {#change-17362} + +This change supports `@utility` directive for Tailwind CSS V4. + + +```css +/* Input */ +@utility tab-* { + tab-size: --value(--tab-size-*); +} + +/* Prettier 3.5 */ +@utility tab-* { + tab-size: --value(--tab-size- *); +} + +/* Prettier 3.6 */ +@utility tab-* { + tab-size: --value(--tab-size-*); +} +``` + +#### Remove extra indentation for `:has` pseudo call ([#17541](https://github.com/prettier/prettier/pull/17541) by [@sosukesuzuki](https://github.com/sosukesuzuki)) {#change-17541} + + +```css +/* Input */ +li:has( + path[d="M544,272H480V150.627L523.314,107.314A16,16,0,0,0,500.686,84.687L457.373,128H415a127.00381,127.00381,0,1,0-254,0H118.627L75.314,84.687A16,16,0,1,0,52.686,107.314L96,150.627V272H32a16,16,0,0,0,0,32H96v24a174.98856,174.98856,0,0,0,30.484,98.889L68.687,484.686a15.99972,15.99972,0,1,0,22.627,22.627l55.616-55.616A175.45165,175.45165,0,0,0,272,504h32a175.45165,175.45165,0,0,0,125.07-52.303l55.616,55.616a15.99972,15.99972,0,0,0,22.627-22.627l-57.797-57.797A174.98856,174.98856,0,0,0,480,328V304h64a16,16,0,0,0,0-32ZM288,32.01263A95.99568,95.99568,0,0,1,383,128H193A95.99568,95.99568,0,0,1,288,32.01263ZM448,328c0,79.401-64.598,144-144,144V236a12.00052,12.00052,0,0,0-12-12h-8a12.00052,12.00052,0,0,0-12,12V472c-79.402,0-144-64.599-144-144V160H448Z"] +) { + display: none; +} + +/* Prettier 3.5 */ +li:has( + path[d="M544,272H480V150.627L523.314,107.314A16,16,0,0,0,500.686,84.687L457.373,128H415a127.00381,127.00381,0,1,0-254,0H118.627L75.314,84.687A16,16,0,1,0,52.686,107.314L96,150.627V272H32a16,16,0,0,0,0,32H96v24a174.98856,174.98856,0,0,0,30.484,98.889L68.687,484.686a15.99972,15.99972,0,1,0,22.627,22.627l55.616-55.616A175.45165,175.45165,0,0,0,272,504h32a175.45165,175.45165,0,0,0,125.07-52.303l55.616,55.616a15.99972,15.99972,0,0,0,22.627-22.627l-57.797-57.797A174.98856,174.98856,0,0,0,480,328V304h64a16,16,0,0,0,0-32ZM288,32.01263A95.99568,95.99568,0,0,1,383,128H193A95.99568,95.99568,0,0,1,288,32.01263ZM448,328c0,79.401-64.598,144-144,144V236a12.00052,12.00052,0,0,0-12-12h-8a12.00052,12.00052,0,0,0-12,12V472c-79.402,0-144-64.599-144-144V160H448Z"] + ) { + display: none; +} + +/* Prettier 3.6 */ +li:has( + path[d="M544,272H480V150.627L523.314,107.314A16,16,0,0,0,500.686,84.687L457.373,128H415a127.00381,127.00381,0,1,0-254,0H118.627L75.314,84.687A16,16,0,1,0,52.686,107.314L96,150.627V272H32a16,16,0,0,0,0,32H96v24a174.98856,174.98856,0,0,0,30.484,98.889L68.687,484.686a15.99972,15.99972,0,1,0,22.627,22.627l55.616-55.616A175.45165,175.45165,0,0,0,272,504h32a175.45165,175.45165,0,0,0,125.07-52.303l55.616,55.616a15.99972,15.99972,0,0,0,22.627-22.627l-57.797-57.797A174.98856,174.98856,0,0,0,480,328V304h64a16,16,0,0,0,0-32ZM288,32.01263A95.99568,95.99568,0,0,1,383,128H193A95.99568,95.99568,0,0,1,288,32.01263ZM448,328c0,79.401-64.598,144-144,144V236a12.00052,12.00052,0,0,0-12-12h-8a12.00052,12.00052,0,0,0-12,12V472c-79.402,0-144-64.599-144-144V160H448Z"] +) { + display: none; +} +``` + +### Less + +#### Fix function argument incorrectly lowercased ([#17502](https://github.com/prettier/prettier/pull/17502) by [@fisker](https://github.com/fisker)) {#change-17502} + + +```less +// Input +.what { + .make-modifier(1A, "1a.png"); + .make-modifier(AA, "1a.png"); +} + +// Prettier 3.5 +.what { + .make-modifier(1a, "1a.png"); + .make-modifier(AA, "1a.png"); +} + +// Prettier 3.6 +.what { + .make-modifier(1A, "1a.png"); + .make-modifier(AA, "1a.png"); +} +``` + +### HTML + +#### Fix formatting when tag name is an object prototype property ([#17501](https://github.com/prettier/prettier/pull/17501) by [@fisker](https://github.com/fisker)) {#change-17501} + + +```html + + + text + + + +TypeError: Vn(...).startsWith is not a function + + + text +``` + +### Angular + +#### Support `TemplateLiteral` introduced in Angular 19.2 ([#17238](https://github.com/prettier/prettier/pull/17238) by [@fisker](https://github.com/fisker)) {#change-17238} + +Angular 29.2 added [support for `TemplateLiteral`](https://blog.angular.dev/angular-19-2-is-now-available-673ec70aea12#ed7b). + + +```html + +
{{ `Hello, ${ +getName('world')}` }}
+ + +
+ {{ `Hello, ${ +getName('world')}` }} +
+ + +
{{ `Hello, ${getName("world")}` }}
+``` + +#### Remove extra colon after `track` in angular `@for` control-flow ([#17280](https://github.com/prettier/prettier/pull/17280) by [@claudio-herger](https://github.com/claudio-herger)) {#change-17280} + + +```angular +// Input +@for (item of items; let i = $index; let count = $count; track block) {} + +// Prettier 3.5 +@for (item of items; let i = $index; let count = $count; track: block) {} + +// Prettier 3.6 +@for (item of items; let i = $index; let count = $count; track block) {} +``` + +#### Support Angular 20 ([#17534](https://github.com/prettier/prettier/pull/17534) by [@fisker](https://github.com/fisker)) {#change-17534} + + +```angular +// Input +{{ + ( (a in (b))) +}} +{{ + ( (tag ` a ${ b } \u0063 `)) +}} +{{ + ( (` a ${ b } \u0063 `)) +}} +{{ void(1 + 2) }} + +// Prettier 3.5 +The new syntax is not correctly recognized. + +// Prettier 3.6 +{{ a in b }} +{{ tag` a ${b} \u0063 ` }} +{{ ` a ${b} \u0063 ` }} +{{ void (1 + 2) }} +``` + +### MJML + +#### Enabling CSS formatting within `` tag ([#17338](https://github.com/prettier/prettier/pull/17338) by [@iryusa](https://github.com/iryusa)) {#change-17338} + + +```mjml + + +.hello { + color: blue; + border: 1px solid blue; +font-size:12px; +} p { font-size: 14px; } + + + + + .hello { color: blue; border: 1px solid blue; font-size:12px; } p { font-size: + 14px; } + + + + + .hello { + color: blue; + border: 1px solid blue; + font-size: 12px; + } + p { + font-size: 14px; + } + +``` + +#### Correctly parse `` and `` ([#17400](https://github.com/prettier/prettier/pull/17400) by [@fisker](https://github.com/fisker)) {#change-17400} + + +```html + + + a::before { + content: "

"; + } +
+ + +SyntaxError: Unexpected closing tag "p". + + +Correctly parsed as CSS. +``` + +### Markdown + +#### Fix adjacent markdown syntax in blockquote ([#16596](https://github.com/prettier/prettier/pull/16596) by [@fiji-flo](https://github.com/fiji-flo)) {#change-16596} + + +```md + +> `x` +> `y` + +> _x_ +> _y_ + +> [foo](http://foo) +> [bar](http://bar) + +> `this` behaves +> `correctly` + + +> `x` > `y` + +> _x_ > _y_ + +> [foo](http://foo) > [bar](http://bar) + +> `this` behaves `correctly` + + +> `x` `y` + +> _x_ _y_ + +> [foo](http://foo) [bar](http://bar) + +> `this` behaves `correctly` +``` + +#### Fix markdown inserts unexpected newline in lists ([#16637](https://github.com/prettier/prettier/pull/16637) by [@byplayer](https://github.com/byplayer)) {#change-16637} + + +```md + +- Level 1 + - Level 1-1 + +- Level 2 + + +- Level 1 + + - Level 1-1 + +- Level 2 + + + +- Level 1 + - Level 1-1 + +- Level 2 + +``` + +#### Fix strong emphasis ([#17143](https://github.com/prettier/prettier/pull/17143) by [@fiji-flo](https://github.com/fiji-flo)) {#change-17143} + +Most markdown implementations don't support `1**_2_**3` so prefer `1***2**3`. + + +```md + +1***2***3 +1**_2_**3 + + +1**_2_**3 +1**_2_**3 + + +1***2***3 +1***2***3 +``` + +### YAML + +#### Do not add line break before empty map or sequence ([#16074](https://github.com/prettier/prettier/pull/16074) by [@BapRx](https://github.com/BapRx)) {#change-16074} + + +```yaml +# Input +--- +myDict: {} + # comment +myList: [] + # comment + +# Prettier 3.5 +--- +myDict: + {} + # comment +myList: + [] + # comment + +# Prettier 3.6 +--- +myDict: {} + # comment +myList: [] + # comment +``` + +### API + +#### Accept `URL` in `plugins` option ([#17166](https://github.com/prettier/prettier/pull/17166) by [@fisker](https://github.com/fisker)) {#change-17166} + +`plugins` option now accepts [URL](https://developer.mozilla.org/en-US/docs/Web/API/URL) with `file:` protocol or a url string that starts with `file:` in all public APIs. + +```js +// `URL` +await prettier.check("foo", { + parser: "my-cool-parser", + plugins: [new URL("./path/to/plugin.js", import.meta.url)], +}); +await prettier.format("foo", { + parser: "my-cool-parser", + plugins: [new URL("./path/to/plugin.js", import.meta.url)], +}); +await prettier.formatWithCursor("foo", { + parser: "my-cool-parser", + cursorOffset: 2, + plugins: [new URL("./path/to/plugin.js", import.meta.url)], +}); +await prettier.getFileInfo("/path/to/file", { + plugins: [new URL("./path/to/plugin.js", import.meta.url)], +}); +await prettier.getSupportInfo({ + plugins: [new URL("./path/to/plugin.js", import.meta.url)], +}); + +// URL string +await prettier.check("foo", { + parser: "my-cool-parser", + plugins: ["file:///path/to/plugin.js"], +}); +await prettier.format("foo", { + parser: "my-cool-parser", + plugins: ["file:///path/to/plugin.js"], +}); +await prettier.formatWithCursor("foo", { + parser: "my-cool-parser", + cursorOffset: 2, + plugins: ["file:///path/to/plugin.js"], +}); +await prettier.getFileInfo("/path/to/file", { + plugins: ["file:///path/to/plugin.js"], +}); +await prettier.getSupportInfo({ + plugins: ["file:///path/to/plugin.js"], +}); +``` + +#### Accept `URL` as custom config file in `resolveConfig` ([#17167](https://github.com/prettier/prettier/pull/17167) by [@fisker](https://github.com/fisker)) {#change-17167} + +[`prettier.resolveConfig()`](https://prettier.io/docs/api#prettierresolveconfigfileurlorpath--options) now accepts an [URL](https://developer.mozilla.org/en-US/docs/Web/API/URL) with `file:` protocol or a url string that starts with `file:` as custom config file location. + +```js +// `URL` +await prettier.resolveConfig("path/to/file", { + config: new URL("/path/to/prettier-config-file", import.meta.url), +}); + +// URL string +await prettier.resolveConfig("path/to/file", { + config: "file:///path/to/prettier-config-file", +}); +``` + +#### Stop interpret `*.frag` files as JavaScript files ([#17178](https://github.com/prettier/prettier/pull/17178) by [@fisker](https://github.com/fisker)) {#change-17178} + +`*.frag` was interpreted as JavaScript files, but `.frag` is also used in GLSL([OpenGL Shading Language](https://en.wikipedia.org/wiki/OpenGL_Shading_Language)). It causes error when Prettier try to format them as JavaScript files. + +Since Prettier 3.6, `*.frag` files except `*.start.frag`, `*.end.frag`, `start.frag`, and `end.frag` are no longer treated as JavaScript files. + +If you have JavaScript files with `.frag` that do not match the patterns mentioned above, you can config with `overrides`. + +```js +export default { + overrides: { + files: "**/*.frag", + options: { + parser: "babel", + }, + }, +}; +``` + +#### Add `isSupported` function support for `languages` API ([#17331](https://github.com/prettier/prettier/pull/17331) by [@JounQin](https://github.com/JounQin), [#17490](https://github.com/prettier/prettier/pull/17490) by [@fisker](https://github.com/fisker)) {#change-17331} + +Previously, `languages` API for custom plugins only supported inferring parser based on the file basename or extension. + +Prettier 3.6 added `isSupported: (options: { filepath: string }) => boolean` function to allow plugin check if file is supported based on the full path (eg: files in a specific directory). + +:::note + +Prettier can not ensure that `filepath` exists on disk.\ +When using from APIs(eg: `prettier.format()`), Prettier can not ensure it's a valid path either. + +::: + +If no `isSupported` provided, it just behaves the same way as before. + +```js +export const languages = [ + { + name: "foo", + parsers: ["foo"], + isSupported: ({ filepath }) => filepath.includes(".foo"), + }, +]; +``` + +#### Add `mjml` parser ([#17339](https://github.com/prettier/prettier/pull/17339) by [@fisker](https://github.com/fisker)) {#change-17339} + +We already support [MJML](https://mjml.io/) in previous version with `html` parser, in order to distinguish MJML-specific a new `mjml` parser added. + +#### Ignore files with `--check-ignore-pragma` ([#17344](https://github.com/prettier/prettier/pull/17344) by [@wnayes](https://github.com/wnayes)) {#change-17344} + +Individual files can now opt out of formatting via `@noformat` or `@noprettier` "pragma" comments at the top of the file. + +To enable this feature, use the new option [`--check-ignore-pragma`](https://prettier.io/docs/options#check-ignore-pragma) (`checkIgnorePragma` via configuration or API). + +Language plugins can [implement support](https://prettier.io/docs/plugins#parsers) for this feature. Most built-in parsers, including JavaScript (TypeScript), CSS, HTML, JSON, Markdown (MDX), YAML, and GraphQL, were updated to support this feature. + + +```jsx +/** + * @noformat + */ + +export default matrix( + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 +); +``` + +#### Fix plugin loading in `prettier.getFileInfo()` ([#17548](https://github.com/prettier/prettier/pull/17548) by [@fisker](https://github.com/fisker)) {#change-17548} + +In previous version, `prettier.getFileInfo()` only read `parser` config from `.prettierrc`, but doesn't load plugins to infer parser from plugin `languages`, Prettier 3.6 fixed it. + +```js +// prettier-plugin-foo +export const languages = [ + { + parsers: ["foo"], + extensions: [".foo"], + }, +]; +``` + +```yaml +# .prettierrc +plugins: + - prettier-plugin-foo +``` + +```console +prettier --file-info file.foo + +# Prettier 3.5 +{ "ignored": false, "inferredParser": null } + +# Prettier 3.6 +{ "ignored": false, "inferredParser": "foo" } +``` + +#### Allow plugin to override builtin parsers when inferring parser ([#17549](https://github.com/prettier/prettier/pull/17549) by [@fisker](https://github.com/fisker)) {#change-17549} + +Previously when inferring parser for file, builtin plugins are checked first, so plugins are not able to override parsers for files like `.js`. + +```js +// prettier-plugin-foo +export const languages = [ + { + parsers: ["foo"], + extensions: [".js"], + }, +]; +``` + +```js +// prettier.config.js +import * as prettierPluginFoo from "prettier-plugin-foo"; + +export default { + plugins: [prettierPluginFoo], +}; +``` + +```console +prettier --file-info file.js + +# Prettier 3.5 +{ "ignored": false, "inferredParser": "babel" } + +# Prettier 3.6 +{ "ignored": false, "inferredParser": "foo" } +``` + +### CLI + +#### Forbid use `--config` and `--no-config` together ([#12221](https://github.com/prettier/prettier/pull/12221) by [@Balastrong](https://github.com/Balastrong)) {#change-12221} + +```console +$ prettier --config=.prettierrc --no-config . +[error] Cannot use --no-config and --config together. +``` + +#### Ignore file modified time when `--cache-strategy=content` ([#17438](https://github.com/prettier/prettier/pull/17438) by [@fisker](https://github.com/fisker)) {#change-17438} + +In previous version, when using `--cache-strategy=content`, if the file modified time changed, it still gets re-formatted even the file content didn't change, Prettier 3.6 fixed it. + +#### Fix result message for files can not be formatted ([#17505](https://github.com/prettier/prettier/pull/17505) by [@fisker](https://github.com/fisker)) {#change-17505-2} + +```console +touch unknown +prettier --check unknown + +# Prettier 3.5 +Checking formatting... +unknown +[error] No parser could be inferred for file "". +All matched files use Prettier code style! + +# Prettier 3.6 +Checking formatting... +unknown +[error] No parser could be inferred for file "". +Error occurred when checking code style in the above file. +``` + +#### Fix exitCode when parser cannot infer ([#17505](https://github.com/prettier/prettier/pull/17505) by [@fisker](https://github.com/fisker)) {#change-17505} + +```console +touch unknown +prettier --check unknown > /dev/null;echo $? + +# Prettier 3.5 +[error] No parser could be inferred for file "". +0 + +# Prettier 3.6 +[error] No parser could be inferred for file "". +2 +``` + +### Miscellaneous + +#### Fix embedded format with `cursorOffset` ([#17254](https://github.com/prettier/prettier/pull/17254) by [@fisker](https://github.com/fisker)) {#change-17254} + + +````md + +# Angular note + +```typescript + import {Component} from '@angular/core'; + + @Component({ + selector: 'app-root', + standalone: true, + imports: [], + template: ` +

+ + {{ title }}

+ `, + styleUrls: ['./app.component.css'], + }) + export class AppComponent { + title = 'default'; + } +``` + + +Error: There are too many 'cursor' in doc. + + +# Angular note + +```typescript +import { Component } from "@angular/core"; + +@Component({ + selector: "app-root", + standalone: true, + imports: [], + template: ` +

+ {{ title }} +

+ `, + styleUrls: ["./app.component.css"], +}) +export class AppComponent { + title = "default"; +} +``` +````