---
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!

<!-- truncate -->

## Highlights

### 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
```

### 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.

## 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}

<!-- prettier-ignore -->
```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.

<!-- prettier-ignore -->
```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.

<!-- prettier-ignore -->
```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}

<!-- prettier-ignore -->
```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}

<!-- prettier-ignore -->
```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}

<!-- prettier-ignore -->
```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}

<!-- prettier-ignore -->
```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.

<!-- prettier-ignore -->
```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}

<!-- prettier-ignore -->
```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}

<!-- prettier-ignore -->
```jsx
// Input
<SuspendyTree>
  <div style={{ height: 200, overflow: "scroll" }}>
    {Array(20)
      .fill()
      ?.map((_, i) => (
        <h2 key={i}>{i + 1}</h2>
      ))}
  </div>
</SuspendyTree>;

// Prettier 3.5 (ESTree based parsers like espree and typescript)
<SuspendyTree>
  <div style={{ height: 200, overflow: "scroll" }}>
    {Array(20)
      .fill()
      ?.map((_, i) => <h2 key={i}>{i + 1}</h2>)}
  </div>
</SuspendyTree>;

// Prettier 3.5 (babel and babel-ts parser)
<SuspendyTree>
  <div style={{ height: 200, overflow: "scroll" }}>
    {Array(20)
      .fill()
      ?.map((_, i) => (
        <h2 key={i}>{i + 1}</h2>
      ))}
  </div>
</SuspendyTree>;

// Prettier 3.6 (parsers of both types)
<SuspendyTree>
  <div style={{ height: 200, overflow: "scroll" }}>
    {Array(20)
      .fill()
      ?.map((_, i) => (
        <h2 key={i}>{i + 1}</h2>
      ))}
  </div>
</SuspendyTree>;
```

### TypeScript

#### Support import type attribute in `TSImportType` ([#16881](https://github.com/prettier/prettier/pull/16881) by [@fisker](https://github.com/fisker)) {#change-16881}

<!-- prettier-ignore -->
```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}

<!-- prettier-ignore -->
```jsx
// Input
export type ErrorLike =
  SerializedProps<Error> & 
  // 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<Error> & // 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<Error> & // 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<Error> &
  // 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}

<!-- prettier-ignore -->
```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}

<!-- prettier-ignore -->
```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}

<!-- prettier-ignore -->
```jsx
// Input
type T<U> = 'a' | ('b' extends U ? 'c' : empty);
type T<U> = 'a' & ('b' extends U ? 'c' : empty);

// Prettier 3.5
type T<U> = "a" | "b" extends U ? "c" : empty;
type T<U> = "a" & "b" extends U ? "c" : empty;

// Prettier 3.6
type T<U> = "a" | ("b" extends U ? "c" : empty);
type T<U> = "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}

<!-- prettier-ignore -->
```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}

<!-- prettier-ignore -->
```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.

<!-- prettier-ignore -->
```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}

<!-- prettier-ignore -->
```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}

<!-- prettier-ignore -->
```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}

<!-- prettier-ignore -->
```html
<!-- Input -->
<constructor>
	text
</constructor>

<!-- Prettier 3.5 -->
TypeError: Vn(...).startsWith is not a function

<!-- Prettier 3.6 -->
<constructor> text </constructor>
```

### 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 19.2 added [support for `TemplateLiteral`](https://blog.angular.dev/angular-19-2-is-now-available-673ec70aea12#ed7b).

<!-- prettier-ignore -->
```html
<!-- Input -->
<div>{{ `Hello, ${
getName('world')}` }}</div>

<!-- Prettier 3.5 -->
<div>
  {{ `Hello, ${
getName('world')}` }}
</div>

<!-- Prettier 3.6 -->
<div>{{ `Hello, ${getName("world")}` }}</div>
```

#### 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}

<!-- prettier-ignore -->
```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}

<!-- prettier-ignore -->
```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 `<mj-style>` tag ([#17338](https://github.com/prettier/prettier/pull/17338) by [@iryusa](https://github.com/iryusa)) {#change-17338}

<!-- prettier-ignore -->
```mjml
<!-- Input -->
<mj-style>
.hello {
  color: blue;
    border: 1px solid blue;
font-size:12px;
} p { font-size: 14px; }
</mj-style>

<!-- Prettier 3.5 -->
<mj-style>
  .hello { color: blue; border: 1px solid blue; font-size:12px; } p { font-size:
  14px; }
</mj-style>

<!-- Prettier 3.6 -->
<mj-style>
  .hello {
    color: blue;
    border: 1px solid blue;
    font-size: 12px;
  }
  p {
    font-size: 14px;
  }
</mj-style>
```

#### Correctly parse `<mj-style>` and `<mj-raw>` ([#17400](https://github.com/prettier/prettier/pull/17400) by [@fisker](https://github.com/fisker)) {#change-17400}

<!-- prettier-ignore -->
```html
<!-- Input -->
<mj-style>
  a::before {
    content: "</p>";
  }
</mj-style>

<!-- Prettier 3.5 -->
SyntaxError: Unexpected closing tag "p". 

<!-- Prettier 3.6 -->
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}

<!-- prettier-ignore -->
```md
<!-- Input -->
> `x`
> `y`

> _x_
> _y_

> [foo](http://foo)
> [bar](http://bar)

> `this` behaves
> `correctly`

<!-- Prettier 3.5 -->
> `x` > `y`

> _x_ > _y_

> [foo](http://foo) > [bar](http://bar)

> `this` behaves `correctly`

<!-- Prettier 3.6 -->
> `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}

<!-- prettier-ignore -->
```md
<!-- Input -->
- Level 1
  - Level 1-1

- Level 2

<!-- Prettier 3.5 -->
- Level 1

  - Level 1-1

- Level 2


<!-- Prettier 3.6 -->
- 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`.

<!-- prettier-ignore -->
```md
<!-- Input -->
1***2***3
1**_2_**3

<!-- Prettier 3.5 -->
1**_2_**3
1**_2_**3

<!-- Prettier 3.6 -->
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}

<!-- prettier-ignore -->
```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.

<!-- prettier-ignore -->
```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 "</path/to/unknown>".
All matched files use Prettier code style!

# Prettier 3.6
Checking formatting...
unknown
[error] No parser could be inferred for file "</path/to/unknown>".
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 "</path/to/unknown>".
0

# Prettier 3.6
[error] No parser could be inferred for file "</path/to/unknown>".
2
```

### Miscellaneous

#### Fix embedded format with `cursorOffset` ([#17254](https://github.com/prettier/prettier/pull/17254) by [@fisker](https://github.com/fisker)) {#change-17254}

<!-- prettier-ignore -->
````md
<!-- Input (--cursor-offset=1) -->
# Angular note

```typescript
  import {Component} from '@angular/core';
  
  @Component({
    selector: 'app-root',
    standalone: true,
    imports: [],
    template: `
      <h1>
      
      {{ title }}</h1>
    `,
    styleUrls: ['./app.component.css'],
  })
  export class AppComponent {
    title = 'default';
  }
```

<!-- Prettier 3.5 -->
Error: There are too many 'cursor' in doc.

<!-- Prettier 3.6 -->
# Angular note

```typescript
import { Component } from "@angular/core";

@Component({
  selector: "app-root",
  standalone: true,
  imports: [],
  template: `
    <h1>
      {{ title }}
    </h1>
  `,
  styleUrls: ["./app.component.css"],
})
export class AppComponent {
  title = "default";
}
```
````
