---
authors: "fisker"
title: "Prettier 3.7: Improved formatting consistency and new plugin features!"
---

We are excited to announce Prettier 3.7! This release focuses on polishing the TypeScript and Flow experience, specifically by aligning the formatting of classes and interfaces to be more consistent and predictable. We also want your opinion on the upcoming change to fix [inconsistent opening brace print logic of class and interface body](https://github.com/prettier/prettier/issues/18115).

Additionally, we also fixed lots of bugs, added support for new features in Angular 21 and Graphql 16.12, added Front Matter support to Handlebars.

For plugin developers, we've added new APIs to give you more control over comment attachment and handling of ignored nodes.

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. Thank you for your continued support!

<!-- truncate -->

## Highlights

### TypeScript

#### Fix the inconsistent printing between class and interface ([#18094](https://github.com/prettier/prettier/pull/18094), [#18091](https://github.com/prettier/prettier/pull/18091), [#18215](https://github.com/prettier/prettier/pull/18215) by [@fisker](https://github.com/fisker)) {#change-18094}

In this release, we've focused heavily on improving consistency between Class and Interface formatting. Previously, these two similar constructs were printed quite differently, leading to visual inconsistencies. We've aligned their formatting rules to provide a more predictable and cleaner output.

##### The extra indentation for type parameters in class has been removed

<!-- prettier-ignore -->
```tsx
// Input
interface MarkDef<
  M extends string | Mark = Mark,
  ES extends ExprRef | SignalRef = ExprRef | SignalRef,
>
  extends A, B {}

declare class MarkDef<
  M extends string | Mark = Mark,
  ES extends ExprRef | SignalRef = ExprRef | SignalRef,
>
  implements A, B {}

// Prettier 3.6
interface MarkDef<
  M extends string | Mark = Mark,
  ES extends ExprRef | SignalRef = ExprRef | SignalRef,
> extends A,
    B {}

declare class MarkDef<
    M extends string | Mark = Mark,
    ES extends ExprRef | SignalRef = ExprRef | SignalRef,
  >
  implements A, B {}

// Prettier 3.7
interface MarkDef<
  M extends string | Mark = Mark,
  ES extends ExprRef | SignalRef = ExprRef | SignalRef,
>
  extends A, B {}

declare class MarkDef<
  M extends string | Mark = Mark,
  ES extends ExprRef | SignalRef = ExprRef | SignalRef,
>
  implements A, B {}
```

##### Align interface heritages print with class

<!-- prettier-ignore -->
```tsx
// Input
export interface AreaConfig<ES extends ExprRef | SignalRef>
  extends MarkConfig<ES>, PointOverlayMixins<ES>, LineOverlayMixins<ES> {}

export class AreaConfig<ES extends ExprRef | SignalRef>
  implements MarkConfig<ES>, PointOverlayMixins<ES>, LineOverlayMixins<ES> {}

// Prettier 3.6
export interface AreaConfig<ES extends ExprRef | SignalRef>
  extends MarkConfig<ES>,
    PointOverlayMixins<ES>,
    LineOverlayMixins<ES> {}

export class AreaConfig<ES extends ExprRef | SignalRef>
  implements MarkConfig<ES>, PointOverlayMixins<ES>, LineOverlayMixins<ES> {}

// Prettier 3.7
export interface AreaConfig<ES extends ExprRef | SignalRef>
  extends MarkConfig<ES>, PointOverlayMixins<ES>, LineOverlayMixins<ES> {}

export class AreaConfig<ES extends ExprRef | SignalRef>
  implements MarkConfig<ES>, PointOverlayMixins<ES>, LineOverlayMixins<ES> {}
```

##### Align single heritage print with super class

<!-- prettier-ignore -->
```tsx
// Input
class ExtendsLongOneWithGenerics
  extends
    Bar<
      SomeLongTypeSomeLongTypeSomeLongTypeSomeLongType,
      ToBreakLineToBreakLineToBreakLine,
    > {}
class ExtendsLongOneWithGenerics
  implements
    Bar<
      SomeLongTypeSomeLongTypeSomeLongTypeSomeLongType,
      ToBreakLineToBreakLineToBreakLine,
    > {}
interface ExtendsLongOneWithGenerics
  extends
    Bar<
      SomeLongTypeSomeLongTypeSomeLongTypeSomeLongType,
      ToBreakLineToBreakLineToBreakLine,
    > {}

// Prettier 3.6
class ExtendsLongOneWithGenerics extends Bar<
  SomeLongTypeSomeLongTypeSomeLongTypeSomeLongType,
  ToBreakLineToBreakLineToBreakLine
> {}
class ExtendsLongOneWithGenerics
  implements
    Bar<
      SomeLongTypeSomeLongTypeSomeLongTypeSomeLongType,
      ToBreakLineToBreakLineToBreakLine
    > {}
interface ExtendsLongOneWithGenerics
  extends Bar<
    SomeLongTypeSomeLongTypeSomeLongTypeSomeLongType,
    ToBreakLineToBreakLineToBreakLine
  > {}

// Prettier 3.7
class ExtendsLongOneWithGenerics extends Bar<
  SomeLongTypeSomeLongTypeSomeLongTypeSomeLongType,
  ToBreakLineToBreakLineToBreakLine
> {}
class ExtendsLongOneWithGenerics implements Bar<
  SomeLongTypeSomeLongTypeSomeLongTypeSomeLongType,
  ToBreakLineToBreakLineToBreakLine
> {}
interface ExtendsLongOneWithGenerics extends Bar<
  SomeLongTypeSomeLongTypeSomeLongTypeSomeLongType,
  ToBreakLineToBreakLineToBreakLine
> {}
```

##### Inconsistent opening brace print logic of class and interface body

In Prettier v2.3, to improve visual separation between class head and body, [we started to print the opening `{` of the class body on a new line when the class has multiple heritages](https://prettier.io/blog/2021/05/09/2.3.0.html#improve-visual-separation-between-header-and-body-in-classes-with-multiline-headers-10085-by-sosukesuzuki).

<!-- prettier-ignore -->
```tsx
// Prettier 2.2
class loooooooooooooooooooong
  extends looooooooooooooooooong
  implements loooooooooooooooooooong {
  property: string;
}

// Prettier 2.3
class loooooooooooooooooooong
  extends looooooooooooooooooong
  implements loooooooooooooooooooong
{
  property: string;
}
```

However, not everyone is happy with this change.

Let us know what you think about applying this change to interfaces by leaving a comment on [this issue](https://github.com/prettier/prettier/issues/18115).

If you have a better solution for this issue, we'll be happy to discuss it too.

Unless a better solution comes along, we'll align the interface body print with the one for the class body in Prettier v4.

<!-- prettier-ignore -->
```tsx
// Input
declare class loooooooooooooooooooong
  implements looooooooooooooooooong, loooooooooooooooooooong {
  property: string;
}

interface loooooooooooooooooooong
  extends looooooooooooooooooong, loooooooooooooooooooong {
  property: string;
}

// Prettier 3.7
declare class loooooooooooooooooooong
  implements looooooooooooooooooong, loooooooooooooooooooong
{
  property: string;
}

interface loooooooooooooooooooong
  extends looooooooooooooooooong, loooooooooooooooooooong { // <-- This
  property: string;
}
```

_These changes also affect Flow syntax_

## Other Changes

### JavaScript

#### Allow break import attributes into multiple lines ([#17329](https://github.com/prettier/prettier/pull/17329) by [@fisker](https://github.com/fisker)) {#change-17329}

<!-- prettier-ignore -->
```jsx
// Input
import syntaxImportAssertions from "@babel/plugin-syntax-import-assertions" with {
  BABEL_8_BREAKING: "false",
  USE_ESM: "true", IS_STANDALONE: "false" };

// Prettier 3.6
import syntaxImportAssertions from "@babel/plugin-syntax-import-assertions" with { BABEL_8_BREAKING: "false", USE_ESM: "true", IS_STANDALONE: "false" };

// Prettier 3.7
import syntaxImportAssertions from "@babel/plugin-syntax-import-assertions" with {
  BABEL_8_BREAKING: "false",
  USE_ESM: "true",
  IS_STANDALONE: "false",
};
```

#### Add support for "Discard Bindings" proposal ([#17708](https://github.com/prettier/prettier/pull/17708) by [@fisker](https://github.com/fisker)) {#change-17708}

The Stage 2 proposal ["Discard Bindings"](https://github.com/tc39/proposal-discard-binding) is now supported via Babel. Also keep in mind our [policy on non-standardized syntax](https://prettier.io/docs/en/rationale.html#disclaimer-about-non-standard-syntax) before using this proposed syntax feature with Prettier.

<!-- prettier-ignore -->
```jsx
const [void] = x;

const {x:void} = x;
```

#### Fix inconsistent comment format ([#17723](https://github.com/prettier/prettier/pull/17723) by [@fisker](https://github.com/fisker)) {#change-17723}

<!-- prettier-ignore -->
```jsx
// Input
if (
  true
  // This is a really complicated part of the condition, so we need a big ol'
  // comment here to explain it.
  && flibble.blibble.blobble?.bloo
) {
  doThings();
}

// Prettier 3.6 (--parser=typescript --experimental-operator-position=start)
if (
  true
  && // This is a really complicated part of the condition, so we need a big ol'
  // comment here to explain it.
  flibble.blibble.blobble?.bloo
) {
  doThings();
}

// Prettier 3.6 (--parser=babel --experimental-operator-position=start)
if (
  true
  // This is a really complicated part of the condition, so we need a big ol'
  // comment here to explain it.
  && flibble.blibble.blobble?.bloo
) {
  doThings();
}

// Prettier 3.7
if (
  true
  // This is a really complicated part of the condition, so we need a big ol'
  // comment here to explain it.
  && flibble.blibble.blobble?.bloo
) {
  doThings();
}
```

#### Add additional Playwright test functions ([#17876](https://github.com/prettier/prettier/pull/17876) by [@BPScott](https://github.com/BPScott)) {#change-17876}

Prettier already avoids changing indentation for test functions when you add `.skip` to
them. It now also treats the Playwright functions [`test.fixme`](https://playwright.dev/docs/api/class-test#test-fixme), [`test.describe.skip`](https://playwright.dev/docs/api/class-test#test-describe-skip) and [`test.describe.fixme`](https://playwright.dev/docs/api/class-test#test-describe-fixme) similar to `test.skip`.

<!-- prettier-ignore -->
```js
// Input
test.fixme("does something really long and complicated so I have to write a very long name for the test", () => {
  // code
});

test.describe.skip("does something really long and complicated so I have to write a very long name for the test", () => {
  // code
});

test.describe.fixme("does something really long and complicated so I have to write a very long name for the test", () => {
  // code
});

// Prettier 3.6
test.fixme(
  "does something really long and complicated so I have to write a very long name for the test",
  () => {
    // code
  },
);

test.describe.skip(
  "does something really long and complicated so I have to write a very long name for the test",
  () => {
    // code
  },
);

test.describe.fixme(
  "does something really long and complicated so I have to write a very long name for the test",
  () => {
    // code
  },
);

// Prettier 3.7
test.fixme("does something really long and complicated so I have to write a very long name for the test", () => {
  // code
});

test.describe
  .skip("does something really long and complicated so I have to write a very long name for the test", () => {
  // code
});

test.describe
  .fixme("does something really long and complicated so I have to write a very long name for the test", () => {
  // code
});
```

#### Avoid break `{import,require.resolve,require.resolve.paths,import.meta.resolve}()` with long module name ([#17882](https://github.com/prettier/prettier/pull/17882), [#17908](https://github.com/prettier/prettier/pull/17908) by [@kovsu](https://github.com/kovsu) & [@fisker](https://github.com/fisker)) {#change-17882}

<!-- prettier-ignore -->
```js
// Input
const a = require("./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module");
const b = require.resolve("./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module");
const c = require.resolve.paths("./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module");

const d = await import("./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module")
const e = import.meta.resolve("./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module");

// Prettier 3.6
const a = require("./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module");
const b = require.resolve(
  "./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module",
);
const c = require.resolve.paths(
  "./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module",
);

const d = await import(
  "./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module"
);
const e = import.meta.resolve(
  "./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module",
);

// Prettier 3.7
const a = require("./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module");
const b =
  require.resolve("./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module");
const c = require.resolve
  .paths("./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module");

const d =
  await import("./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module");
const e = import.meta
  .resolve("./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module");
```

#### Improve comment handing inside if statement ([#17998](https://github.com/prettier/prettier/pull/17998) by [@fisker](https://github.com/fisker)) {#change-17998}

<!-- prettier-ignore -->
```jsx
// Input
if (foo) // comment
{
  doThing();
} else // comment for else
{
  doSomethingElse();
}

// Prettier 3.6
if (foo) {
  // comment
  doThing();
} // comment for else
else {
  doSomethingElse();
}

// Prettier 3.7
if (foo) // comment
{
  doThing();
} else // comment for else
{
  doSomethingElse();
}
```

#### Improve `require()` call with comments ([#18037](https://github.com/prettier/prettier/pull/18037) by [@fisker](https://github.com/fisker)) {#change-18037}

<!-- prettier-ignore -->
```jsx
// Input
require(
// Comment
"foo"
);

// Prettier 3.6
require(// Comment
"foo");

// Prettier 3.7
require(
  // Comment
  "foo",
);
```

#### Remove indention in logical expression in `Boolean()` call ([#18087](https://github.com/prettier/prettier/pull/18087) by [@kovsu](https://github.com/kovsu)) {#change-18087}

Reduce diff when changing a condition to an opposite value, or change between `!!` and `Boolean()`.

<!-- prettier-ignore -->
```js
// Input
const foo = Boolean(
  a_long_long_condition ||
  a_long_long_long_condition ||
  a_long_long_long_condition
);
const bar = !!(
  a_long_long_condition ||
  a_long_long_long_condition ||
  a_long_long_long_condition
);

// Prettier 3.6
const foo = Boolean(
  a_long_long_condition ||
    a_long_long_long_condition ||
    a_long_long_long_condition,
);
const bar = !!(
  a_long_long_condition ||
  a_long_long_long_condition ||
  a_long_long_long_condition
);

// Prettier 3.7
const foo = Boolean(
  a_long_long_condition ||
  a_long_long_long_condition ||
  a_long_long_long_condition
);
const bar = !!(
  a_long_long_condition ||
  a_long_long_long_condition ||
  a_long_long_long_condition
);
```

#### Fix comments handling for for-statements ([#18099](https://github.com/prettier/prettier/pull/18099) by [@fisker](https://github.com/fisker), [@sosukesuzuki](https://github.com/sosukesuzuki)) {#change-18099}

<!-- prettier-ignore -->
```js
// Input
for (x of y)
  // Comment
  bar();

// Prettier 3.6
// Comment
for (x of y) bar();

// Prettier 3.7
for (x of y)
  // Comment
  bar();
```

#### Improve comment printing around empty statement ([#18108](https://github.com/prettier/prettier/pull/18108) by [@fisker](https://github.com/fisker)) {#change-18108}

<!-- prettier-ignore -->
```jsx
// Input
for (
  index = 0;
  doSomething(foo[index]) !== bar && doSomething(foo[index]) !== baz;
  index ++
) /* No op */;

// Prettier 3.6
for (
  index = 0;
  doSomething(foo[index]) !== bar && doSomething(foo[index]) !== baz;
  index++ /* No op */
);

// Prettier 3.7
for (
  index = 0;
  doSomething(foo[index]) !== bar && doSomething(foo[index]) !== baz;
  index++
) /* No op */ ;
```

#### Fix inconsistent comment print between class methods and object methods ([#18147](https://github.com/prettier/prettier/pull/18147) by [@fisker](https://github.com/fisker)) {#change-18147}

<!-- prettier-ignore -->
```jsx
// Input
class x {
  method() // Class method
  {
    return 1
  }
}

const object = {
  method() // Object method
  {
    return 1
  }
}

// Prettier 3.6
class x {
  method() { // Class method
    return 1;
  }
}

const object = {
  method() {
    // Object method
    return 1;
  },
};

// Prettier 3.7
class x {
  method() {
    // class method
    return 1;
  }
}

const object = {
  method() {
    // object method
    return 1;
  },
};
```

#### Add missing parentheses in bitwise operators ([#18163](https://github.com/prettier/prettier/pull/18163) by [@fs0414](https://github.com/fs0414)) {#change-18163}

<!-- prettier-ignore -->
```js
// Input
1 << (bit % 8);
1 >> (bit - 8);

// Prettier 3.6
1 << bit % 8;
1 >> (bit - 8);

// Prettier 3.7
1 << (bit % 8);
1 >> (bit - 8);
```

#### Fix inconsistent break for array literals ([#18172](https://github.com/prettier/prettier/pull/18172) by [@Dunqing](https://github.com/Dunqing), [@fisker](https://github.com/fisker)) {#change-18172}

<!-- prettier-ignore -->
```jsx
// Input
assert.deepStrictEqual(linesCollection.getViewLinesIndentGuides___(-1, -1), [1]);
assert.deepStrictEqual(linesCollection.getViewLinesIndentGuides(-1, -1), [1, 2]);

// Prettier 3.6
assert.deepStrictEqual(linesCollection.getViewLinesIndentGuides___(-1, -1), [
  1,
]);
assert.deepStrictEqual(
  linesCollection.getViewLinesIndentGuides(-1, -1),
  [1, 2],
);

// Prettier 3.7
assert.deepStrictEqual(
  linesCollection.getViewLinesIndentGuides___(-1, -1),
  [1],
);
assert.deepStrictEqual(
  linesCollection.getViewLinesIndentGuides(-1, -1),
  [1, 2],
);
```

#### Fix inconsistent logical expression print ([#18205](https://github.com/prettier/prettier/pull/18205) by [@fisker](https://github.com/fisker)) {#change-18205}

<!-- prettier-ignore -->
```jsx
// Input
fn(
  a &&
    a_long_long_long_long_long_long_long_long_long_long_long_long_long_condition
      ? a
      : b
);

new Fn(
  a &&
    a_long_long_long_long_long_long_long_long_long_long_long_long_long_condition
      ? a
      : b
);

// Prettier 3.6
fn(
  a &&
    a_long_long_long_long_long_long_long_long_long_long_long_long_long_condition
    ? a
    : b,
);

new Fn(
  a &&
  a_long_long_long_long_long_long_long_long_long_long_long_long_long_condition
    ? a
    : b,
);

// Prettier 3.7
fn(
  a &&
    a_long_long_long_long_long_long_long_long_long_long_long_long_long_condition
    ? a
    : b,
);

new Fn(
  a &&
    a_long_long_long_long_long_long_long_long_long_long_long_long_long_condition
    ? a
    : b,
);
```

#### Fix inconsistent print between `CallExpression` and `NewExpression` ([#18206](https://github.com/prettier/prettier/pull/18206) by [@fisker](https://github.com/fisker)) {#change-18206}

<!-- prettier-ignore -->
```jsx
// Input
TelemetryTrustedValue(
  instance.capabilities.get(
    TerminalCapability?.PromptTypeDetection
  )?.promptType
)

new TelemetryTrustedValue(
  instance.capabilities.get(
    TerminalCapability?.PromptTypeDetection
  )?.promptType
)

// Prettier 3.6
TelemetryTrustedValue(
  instance.capabilities.get(TerminalCapability?.PromptTypeDetection)
    ?.promptType,
);

new TelemetryTrustedValue(
  instance.capabilities.get(
    TerminalCapability?.PromptTypeDetection,
  )?.promptType,
);

// Prettier 3.7
TelemetryTrustedValue(
  instance.capabilities.get(TerminalCapability?.PromptTypeDetection)
    ?.promptType,
);

new TelemetryTrustedValue(
  instance.capabilities.get(TerminalCapability?.PromptTypeDetection)
    ?.promptType,
)
```

#### Remove redundant parentheses around JSX element ([#18243](https://github.com/prettier/prettier/pull/18243) by [@fisker](https://github.com/fisker)) {#change-18243}

<!-- prettier-ignore -->
```jsx
// Input
new A(
  <div>
    <div></div>
  </div>
)

// Prettier 3.6
new A(
  (
    <div>
      <div></div>
    </div>
  ),
);

// Prettier 3.7
new A(
  <div>
    <div></div>
  </div>,
);
```

#### Improve formatting of logical expression as callee of new expression ([#18245](https://github.com/prettier/prettier/pull/18245) by [@fisker](https://github.com/fisker)) {#change-18245}

<!-- prettier-ignore -->
```jsx
// Input
a = new (
  a_long_long_long_long_condition || a_long_long_long_long_condition || a_long_long_long_long_condition
)();

// Prettier 3.6
a = new (a_long_long_long_long_condition ||
  a_long_long_long_long_condition ||
  a_long_long_long_long_condition)();

// Prettier 3.7
a = new (
  a_long_long_long_long_condition ||
  a_long_long_long_long_condition ||
  a_long_long_long_long_condition
)();
```

#### Remove empty line in for statement without "update" ([#18300](https://github.com/prettier/prettier/pull/18300) by [@fisker](https://github.com/fisker)) {#change-18300}

<!-- prettier-ignore -->
```jsx
// Input
for ( let i = 0, j = 0, len = allMatches.length, lenJ = selections.length;i < len;) {}

// Prettier 3.6
for (
  let i = 0, j = 0, len = allMatches.length, lenJ = selections.length;
  i < len;

) {}

// Prettier 3.7
for (
  let i = 0, j = 0, len = allMatches.length, lenJ = selections.length;
  i < len;
) {}
```

#### Improve super class format ([#18325](https://github.com/prettier/prettier/pull/18325) by [@fisker](https://github.com/fisker)) {#change-18325}

<!-- prettier-ignore -->
```jsx
// Input
class EnsureNoDisposablesAreLeakedInTestSuiteSuite extends eslint.Rule.RuleModule {};

// Prettier 3.6
class EnsureNoDisposablesAreLeakedInTestSuiteSuite extends eslint.Rule
  .RuleModule {}

// Prettier 3.7
class EnsureNoDisposablesAreLeakedInTestSuiteSuite
  extends eslint.Rule.RuleModule {}
```

### TypeScript

#### Fix misplacement of comments after arrow ([#17421](https://github.com/prettier/prettier/pull/17421) by [@o-m12a](https://github.com/o-m12a), [@t-mangoe](https://github.com/t-mangoe)) {#change-17421}

<!-- prettier-ignore -->
```ts
// Input
export const test = (): any => /* first line
second line
*/
    null;

// Prettier 3.6
export const test = (): any /* first line
second line
*/ => null;

// Prettier 3.6 (Second format)
SyntaxError: Unexpected token (1:22)
> 1 | export const test = (): any /* first line
    |                      ^
  2 | second line
  3 | */ => null;
  4 |

// Prettier 3.7
export const test = (): any =>
  /* first line
second line
*/
  null;
```

#### Add missing parentheses to arrow function in instantiation expression ([#17724](https://github.com/prettier/prettier/pull/17724) by [@fisker](https://github.com/fisker)) {#change-17724}

<!-- prettier-ignore -->
```tsx
// Input
void (<_T extends never>() => {})<never>;

// Prettier 3.6
void <_T extends never>() => {}<never>;

// Prettier 3.7
void (<_T extends never>() => {})<never>;
```

#### Fix `TSMappedType` format ([#17785](https://github.com/prettier/prettier/pull/17785) by [@fisker](https://github.com/fisker)) {#change-17785}

<!-- prettier-ignore -->
```tsx
// Input (--parser=babel-ts)
export type A = B extends { C?: { [D in infer E]?: F } } ? G : H

// Prettier 3.6
TypeError: Cannot read properties of undefined (reading 'startsWith')

// Prettier 3.7
export type A = B extends { C?: { [D in infer E]?: F } } ? G : H;
```

#### Print trailing comma in `TSImportType` options ([#17798](https://github.com/prettier/prettier/pull/17798) by [@fisker](https://github.com/fisker)) {#change-17798}

Trailing comma in import type attribute wasn't allowed before TypeScript v5.9, now [the bug](https://github.com/microsoft/TypeScript/issues/61916) has been fixed.

<!-- prettier-ignore -->
```tsx
// Input
type A = import("foo", {
    with:{
        type:'json',
    }  // <- Should be a comma here
})

// Prettier 3.6
type A = import("foo", {
  with: {
    type: "json",
  } // <- Should be a comma here
});

// Prettier 3.7
type A = import("foo", {
  with: {
    type: "json",
  }, // <- Should be a comma here
});
```

#### Improve CommonJS module `require()` with comments ([#18035](https://github.com/prettier/prettier/pull/18035) by [@fisker](https://github.com/fisker)) {#change-18035}

<!-- prettier-ignore -->
```tsx
// Input
import foo = require(
// Comment
"foo"
);

// Prettier 3.6
import foo = require(// Comment
"foo");

// Prettier 3.7
import foo = require(
  // Comment
  "foo"
);
```

#### Line breaking after `=` in type parameters ([#18043](https://github.com/prettier/prettier/pull/18043) by [@fisker](https://github.com/fisker)) {#change-18043}

<!-- prettier-ignore -->
```tsx
// Input
export type OuterType2<
  LongerLongerLongerLongerInnerType = LongerLongerLongerLongerLongerLongerLongerLongerOtherType
> = { a: 1 };

// Prettier 3.6
export type OuterType2<
  LongerLongerLongerLongerInnerType = LongerLongerLongerLongerLongerLongerLongerLongerOtherType,
> = { a: 1 };

// Prettier 3.7
export type OuterType2<
  LongerLongerLongerLongerInnerType =
    LongerLongerLongerLongerLongerLongerLongerLongerOtherType,
> = { a: 1 };
```

#### Remove unexpected blank line before union types ([#18109](https://github.com/prettier/prettier/pull/18109) by [@jspereiramoura](https://github.com/jspereiramoura), [@fisker](https://github.com/fisker)) {#change-18109}

<!-- prettier-ignore -->
```tsx
// Input
type SuperLongTypeNameLoremIpsumLoremIpsumBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBla =
  Fooo1000 | Baz2000 | BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;
type A = // comment
  Fooo1000 | Baz2000 | BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;

// Prettier 3.6
type SuperLongTypeNameLoremIpsumLoremIpsumBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBla =

    | Fooo1000
    | Baz2000
    | BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;
type A = // comment

    | Fooo1000
    | Baz2000
    | BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;

// Prettier 3.7
type SuperLongTypeNameLoremIpsumLoremIpsumBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBla =
  | Fooo1000
  | Baz2000
  | BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;
type A = // comment
  | Fooo1000
  | Baz2000
  | BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;
```

_This change also affect Flow syntax_

#### Fix inconsistent comment printing between `typescript` and `flow` parser ([#18110](https://github.com/prettier/prettier/pull/18110) by [@fisker](https://github.com/fisker)) {#change-18110}

<!-- prettier-ignore -->
```tsx
// Input
interface A {
  a: // Comment
    B;
  b: // Comment
    | Fooo1000
    | Baz2000
    | BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;
  c: // Comment
  	& Fooo1000
    & Baz2000
    & BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;
}

// Prettier 3.6 (--parser=typescript)
interface A {
  a: // Comment
  B;
  b: // Comment
  | Fooo1000
    | Baz2000
    | BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;
  c: // Comment
  Fooo1000 &
    Baz2000 &
    BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;
}

// Prettier 3.6 (--parser=flow)
interface A {
  a: B; // Comment
  b:  // Comment
    | Fooo1000
    | Baz2000
    | BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;
  c: Fooo1000 & // Comment
    Baz2000 &
    BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;
}

// Prettier 3.7 (Same output for `--parser=typescript` and `--parser=flow`)
interface A {
  a: B; // Comment
  b:  // Comment
    | Fooo1000
    | Baz2000
    | BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;
  c: // Comment
  Fooo1000 &
    Baz2000 &
    BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;
}
```

#### Fix missing semicolon before call signatures ([#18118](https://github.com/prettier/prettier/pull/18118) by [@fisker](https://github.com/fisker)) {#change-18118}

<!-- prettier-ignore -->
```tsx
// Input
interface A {
  foo;
  <T>(): T;
}
type B = {
  foo;
  <T>(): T;
}

// Prettier 3.6 (--no-semi, first format)
interface A {
  foo
  <T>(): T
}
type B = {
  foo
  <T>(): T
}

// Prettier 3.6 (--no-semi, second format)
interface A {
  foo<T>(): T
}
type B = {
  foo<T>(): T
}

// Prettier 3.7
interface A {
  foo;
  <T>(): T
}
type B = {
  foo;
  <T>(): T
}
```

#### Fix inconsistent print of `as const` between flow and typescript parsers ([#18161](https://github.com/prettier/prettier/pull/18161) by [@fisker](https://github.com/fisker)) {#change-18161}

<!-- prettier-ignore -->
```tsx
// Input
1 as /* comment */ const;

// Prettier 3.6 (--parser=typescript)
1 as /* comment */ const;

// Prettier 3.6 (--parser=flow)
1 /* comment */ as const;

// Prettier 3.7 (Same output for `--parser=typescript` and `--parser=flow`)
1 /* comment */ as const;
```

#### Fix comment around `as`/`satisfies` expression ([#18162](https://github.com/prettier/prettier/pull/18162) by [@fisker](https://github.com/fisker)) {#change-18162}

<!-- prettier-ignore -->
```tsx
// Input
1 as /*
comment
*/
const;

// Prettier 3.6 (First format)
1 /*
comment
*/ as const;

// Prettier 3.6 (Second format)
SyntaxError: Unexpected keyword or identifier. (3:4)
  1 | 1 /*
  2 | comment
> 3 | */ as const;
    |    ^
  4 |

// Prettier 3.7
1 as const /*
comment
*/;
```

#### Fix miss aligned union type ([#18165](https://github.com/prettier/prettier/pull/18165) by [@fisker](https://github.com/fisker)) {#change-18165}

<!-- prettier-ignore -->
```tsx
// Input
interface I {
  elements: // comment
    | [string, ExpressionNode, ExpressionNode]
    | [string, ExpressionNode, ExpressionNode, ObjectExpression]
}

// Prettier 3.6
interface I {
  elements: // comment
  | [string, ExpressionNode, ExpressionNode]
    | [string, ExpressionNode, ExpressionNode, ObjectExpression];
}

// Prettier 3.7
interface I {
  elements:  // comment
    | [string, ExpressionNode, ExpressionNode]
    | [string, ExpressionNode, ExpressionNode, ObjectExpression];
}
```

#### Remove extra empty line in union type ([#18197](https://github.com/prettier/prettier/pull/18197) by [@Dunqing](https://github.com/Dunqing)) {#change-18197}

<!-- prettier-ignore -->
```tsx
// Input
type SuperLongTypeNameLoremIpsumLoremIpsumBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBla =
  Fooo1000 | Baz2000 | BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;

// Prettier 3.6
type SuperLongTypeNameLoremIpsumLoremIpsumBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBla =

    | Fooo1000
    | Baz2000
    | BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;

// Prettier 3.7
type SuperLongTypeNameLoremIpsumLoremIpsumBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBla =
  | Fooo1000
  | Baz2000
  | BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;
```

### Flow

#### Add basic support for "match" syntax ([#17681](https://github.com/prettier/prettier/pull/17681) by [@fisker](https://github.com/fisker)) {#change-17681}

<!-- prettier-ignore -->
```flow
// Input
const e = match (a) {
  1 => true,
  'foo' => false,
  2 => {obj: 'literal'},
};

// Prettier 3.6
SyntaxError: Unexpected token `{`, expected the token `;` (1:21)
> 1 | const e = match (a) {
    |                     ^
  2 |   1 => true,
  3 |   'foo' => false,
  4 |   2 => {obj: 'literal'},

// Prettier 3.7
const e = match (a) {
  1 => true,
  "foo" => false,
  2 => { obj: "literal" },
};
```

#### Add support for opaque type with lower and upper bound ([#17792](https://github.com/prettier/prettier/pull/17792) by [@SamChou19815](https://github.com/SamChou19815)) {#change-17792}

<!-- prettier-ignore -->
```flow
// Input
opaque type Counter super empty extends Box<T> = Container<T>;
opaque type Counter super Box<T> = Container<T>;
declare opaque type Counter super empty extends Box<T>;
declare opaque type Counter super Box<T>;

// Prettier 3.6
SyntaxError: Unexpected identifier, expected the token `=` (1:21)

// Prettier 3.7
opaque type Counter super empty extends Box<T> = Container<T>;
opaque type Counter super Box<T> = Container<T>;
declare opaque type Counter super empty extends Box<T>;
declare opaque type Counter super Box<T>;
```

### CSS

#### Handle attribute selector with case-sensitive and uppercase case-insensitive flags ([#17841](https://github.com/prettier/prettier/pull/17841), [#17865](https://github.com/prettier/prettier/pull/17865) by [@kovsu](https://github.com/kovsu)) {#change-17841}

<!-- prettier-ignore -->
```css
/* Input */
[type=a s],
[type=a S],
[type=a I] {
  list-style-type: lower-alpha;
}

/* Prettier 3.6 */
[type="a s"],
[type="a S"],
[type="a I"] {
  list-style-type: lower-alpha;
}

/* Prettier 3.7 */
[type="a" s],
[type="a" S],
[type="a" I] {
  list-style-type: lower-alpha;
}
```

#### Fix crash when formatting special custom properties ([#17899](https://github.com/prettier/prettier/pull/17899) by [@fisker](https://github.com/fisker)) {#change-17899}

<!-- prettier-ignore -->
```css
/* Input */
:root {
  --l: , #000;
}

/* Prettier 3.6 */
TypeError: Cannot read properties of undefined (reading 'value')

/* Prettier 3.7 */
:root {
  --l: , #000;
}
```

#### Fix selector been lowercased incorrectly inside css modules ([#17929](https://github.com/prettier/prettier/pull/17929) by [@kovsu](https://github.com/kovsu)) {#change-17929}

<!-- prettier-ignore -->
```css
/* Input */
:export {
  nest: {
    myColor: blue;
  }
  myColor: red;
}

/* Prettier 3.6 */
:export {
  nest: {
    mycolor: blue;
  }
  myColor: red;
}

/* Prettier 3.7 */
:export {
  nest: {
    myColor: blue;
  }
  myColor: red;
}
```

#### Fix formatting of CSS selectors contains `//` ([#17938](https://github.com/prettier/prettier/pull/17938) by [@kovsu](https://github.com/kovsu)) {#change-17938}

<!-- prettier-ignore -->
```css
/* Input */
a[href="http://example.com"] {
  color: red;
}

/* Prettier 3.6 */
a[href="http://example.com"]
{
  color: red;
}

/* Prettier 3.7 */
a[href="http://example.com"] {
  color: red;
}
```

#### Remove unexpected space between font size and line height ([#18114](https://github.com/prettier/prettier/pull/18114) by [@kovsu](https://github.com/kovsu)) {#change-18114}

<!-- prettier-ignore -->
```css
/* Input */
a {
  font: var(--size)/1;
}

/* Prettier 3.6 */
a {
  font: var(--size) / 1;
}

/* Prettier 3.7 */
a {
  font: var(--size)/1;
}
```

#### Fix extra indent for CSS comma-separated values after a block comment ([#18228](https://github.com/prettier/prettier/pull/18228) by [@seiyab](https://github.com/seiyab)) {#change-18228}

<!-- prettier-ignore -->
```css
/* Input */
.foo {
  background-image:
    linear-gradient(to top, blue, red 100%),
    /* texture */
    repeating-linear-gradient(90deg, pink, yellow 20px, green 20px, pink 40px),
    repeating-linear-gradient(90deg, pink, yellow 20px, green 20px, pink 40px);
}

/* Prettier 3.6 */
.foo {
  background-image:
    linear-gradient(to top, blue, red 100%),
    /* texture */
      repeating-linear-gradient(90deg, pink, yellow 20px, green 20px, pink 40px),
    repeating-linear-gradient(90deg, pink, yellow 20px, green 20px, pink 40px);
}

/* Prettier 3.7 */
.foo {
  background-image:
    linear-gradient(to top, blue, red 100%),
    /* texture */
    repeating-linear-gradient(90deg, pink, yellow 20px, green 20px, pink 40px),
    repeating-linear-gradient(90deg, pink, yellow 20px, green 20px, pink 40px);
}
```

### SCSS

#### Fix parentheses space problem in mixin argument ([#17836](https://github.com/prettier/prettier/pull/17836) by [@kovsu](https://github.com/kovsu)) {#change-17836}

<!-- prettier-ignore -->
```scss
// Input
.foo {
  @include bar('A (B)');
}

// Prettier 3.6
.foo {
  @include bar('A( B)');
}

// Prettier 3.7
.foo {
  @include bar('A (B)');
}
```

#### Fix formatting of space-separated values ([#17903](https://github.com/prettier/prettier/pull/17903) by [@kovsu](https://github.com/kovsu)) {#change-17903}

<!-- prettier-ignore -->
```scss
// Input
.foo {
  @include transition(min-height ($spacer/2) ease-in-out);
}

// Prettier 3.6
.foo {
  @include transition(min-height($spacer/2) ease-in-out);
}

// Prettier 3.7
.foo {
  @include transition(min-height ($spacer/2) ease-in-out);
}
```

### Less

#### Fix variable name being lowercased incorrectly ([#17820](https://github.com/prettier/prettier/pull/17820) by [@kovsu](https://github.com/kovsu)) {#change-17820}

<!-- prettier-ignore -->
```less
// Input
@fooBackground:line-gradient(#f00);

a {
  background: @fooBackground;
}

// Prettier 3.6
@foobackground:line-gradient (#f00);

a {
  background: @fooBackground;
}


// Prettier 3.7
@fooBackground: line-gradient(#f00);

a {
  background: @fooBackground;
}
```

#### Keep property/variable accessors tight ([#17983](https://github.com/prettier/prettier/pull/17983) by [@kovsu](https://github.com/kovsu)) {#change-17983}

<!-- prettier-ignore -->
```less
// Input
.average(@x, @y) {
  @result: ((@x + @y) / 2);
}

div {
  padding: .average(16px, 50px)   [   @result   ];
}

// Prettier 3.6
.average(@x, @y) {
  @result: ((@x + @y) / 2);
}

div {
  padding: .average(16px, 50px) [ @result];
}

// Prettier 3.7
.average(@x, @y) {
  @result: ((@x + @y) / 2);
}

div {
  padding: .average(16px, 50px)[@result];
}
```

### HTML

#### Support format `allow` attribute of iframe element ([#17879](https://github.com/prettier/prettier/pull/17879) by [@kovsu](https://github.com/kovsu)) {#change-17879}

<!-- prettier-ignore -->
```html
<!-- Input -->
<iframe allow="layout-animations 'none'; unoptimized-images 'none'; oversized-images 'none'; sync-script 'none'; sync-xhr 'none'; unsized-media 'none';"></iframe>

<!-- Prettier 3.6 -->
<iframe allow="layout-animations 'none'; unoptimized-images 'none'; oversized-images 'none'; sync-script 'none'; sync-xhr 'none'; unsized-media 'none';"></iframe>

<!-- Prettier 3.7 -->
<iframe
  allow="
    layout-animations 'none';
    unoptimized-images 'none';
    oversized-images 'none';
    sync-script 'none';
    sync-xhr 'none';
    unsized-media 'none';
  "
></iframe>
```

#### Format inline event handler ([#17909](https://github.com/prettier/prettier/pull/17909) by [@kovsu](https://github.com/kovsu)) {#change-17909}

<!-- prettier-ignore -->
```html
<!-- Input -->
<button
  type="button"
  onclick="console .log(    'Hello, this is my old-fashioned event handler!')"
>Press me</button>

<!-- Prettier 3.6 -->
<button
  type="button"
  onclick="console .log(    'Hello, this is my old-fashioned event handler!')"
>
  Press me
</button>

<!-- Prettier 3.7 -->
<button
  type="button"
  onclick="console.log('Hello, this is my old-fashioned event handler!')"
>
  Press me
</button>
```

### Angular

#### Support Angular 21 ([#17722](https://github.com/prettier/prettier/pull/17722), [#18294](https://github.com/prettier/prettier/pull/18294) by [@fisker](https://github.com/fisker)) {#change-17722}

Angular 20.1 added support for new assignment operators.
Angular 21 added support for regular expression.

<!-- prettier-ignore -->
```html
<!-- Input -->
<b (click)="
  a   ??= b">{{  /\d+/g}}</b>

<!-- Prettier 3.6 -->
<b
  (click)="
  a   ??= b"
  >{{  /\d+/g}}</b
>

<!-- Prettier 3.7 -->
<b (click)="a ??= b">{{ /\d+/g }}</b>
```

#### Fix comments get duplicated in interpolation ([#17862](https://github.com/prettier/prettier/pull/17862) by [@fisker](https://github.com/fisker)) {#change-17862}

<!-- prettier-ignore -->
```html
<!-- Input -->
{{a() // comment}}

<!-- Prettier 3.6 -->
{{ a(// comment) // comment }}

<!-- Prettier 3.7 -->
{{
  a() // comment
}}
```

#### Fix formatting of "non-null assertion" ([#18047](https://github.com/prettier/prettier/pull/18047) by [@fisker](https://github.com/fisker)) {#change-18047}

<!-- prettier-ignore -->
```html
<!-- Input -->
{{ foo?.bar!.baz }}

<!-- Prettier 3.6 -->
{{ (foo?.bar)!.baz }}

<!-- Prettier 3.7 -->
{{ foo?.bar!.baz }}
```

### Ember / Handlebars

#### Added Front Matter support to Handlebars ([#17781](https://github.com/prettier/prettier/pull/17781) by [@Codezilluh](https://github.com/Codezilluh)) {#change-17781}

Front matter can now be used in Handlebars.

<!-- prettier-ignore -->
```hbs
---
title: My page title
keywords:
  - word
  - other word
---

<h1>{{title}}</h1>
<ul>
  {{#each keywords}}
    <li>{{this}}</li>
  {{/each}}
</ul>
```

#### Preserve `else if` syntax for custom helpers ([#17856](https://github.com/prettier/prettier/pull/17856) by [@kovsu](https://github.com/kovsu)) {#change-17856}

<!-- prettier-ignore -->
```hbs
{{! Input }}
{{#animated-if this.foo}}
foo content
{{else if (this.bar)}}
bar content
{{/animated-if}}

{{! Prettier 3.6 }}
{{#animated-if this.foo}}
  foo content
{{else}}{{#if (this.bar)}}
    bar content
  {{/if}}{{/animated-if}}

{{! Prettier 3.7 }}
{{#animated-if this.foo}}
  foo content
{{else if (this.bar)}}
  bar content
{{/animated-if}}
```

#### Remove extra blank lines in `<style>` tags ([#18065](https://github.com/prettier/prettier/pull/18065) by [@kovsu](https://github.com/kovsu), [@fisker](https://github.com/fisker)) {#change-18065}

<!-- prettier-ignore -->
```hbs
{{! Input }}
<style>
  #foo {
    color: red;
  }
</style>

{{! Prettier 3.6 (--html-whitespace-sensitivity=ignore) }}
<style>

  #foo {
    color: red;
  }

</style>

{{! Prettier 3.7 (--html-whitespace-sensitivity=ignore) }}
<style>
  #foo {
    color: red;
  }
</style>
```

#### Don't force elements to break with `--html-whitespace-sensitivity=ignore` ([#18133](https://github.com/prettier/prettier/pull/18133) by [@fisker](https://github.com/fisker)) {#change-18133}

<!-- prettier-ignore -->
```hbs
{{! Input }}
<div> </div>

{{! Prettier 3.6 (--html-whitespace-ensitivity=ignore) }}
<div>
</div>

{{! Prettier 3.7 (--html-whitespace-ensitivity=ignore) }}
<div></div>
```

### GraphQL

#### Support "executable descriptions" ([#18214](https://github.com/prettier/prettier/pull/18214) by [@fisker](https://github.com/fisker)) {#change-18214}

<!-- prettier-ignore -->
```gql
# Input
"Description"
query {
  node {
    id
  }
}

# Prettier 3.6
SyntaxError: Syntax Error: Unexpected description, descriptions are supported only on type definitions. (1:1)
> 1 | "Description"
    | ^
  2 | query {
  3 |   node {
  4 |     id

# Prettier 3.7
"Description"
query {
  node {
    id
  }
}
```

### Markdown

#### Improve emoji size measurement ([#17813](https://github.com/prettier/prettier/pull/17813) by [@seiyab](https://github.com/seiyab)) {#change-17813}

This change improves table alignment in all languages.

<!-- prettier-ignore -->
```md
<!-- Input -->
|     |     |
| :-: | :-: |
|  ✔  |  ✘  |
|  ✘  |  ✔  |
|  ✔  |  ✘  |

<!-- Input -->
|     |     |
| :-: | :-: |
| ✔  |  ✘  |
|  ✘  | ✔  |
| ✔  |  ✘  |


<!-- Prettier 3.7 -->
|     |     |
| :-: | :-: |
|  ✔  |  ✘  |
|  ✘  |  ✔  |
|  ✔  |  ✘  |
```

#### Infer TOML parser for Front Matter ([#17965](https://github.com/prettier/prettier/pull/17965) by [@kovsu](https://github.com/kovsu)) {#change-17965}

TOML Front Matter can be processed by the appropriate plugin if any.
Works for HTML and CSS files too.

#### Fix strong emphasis format ([#18010](https://github.com/prettier/prettier/pull/18010) by [@yin1999](https://github.com/yin1999)) {#change-18010}

This is a supplementary fix for #17143, where the original PR could not determine whether the contents on the left and right sides were both words.

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

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

<!-- Prettier 3.7 -->
1***2***3
1***2***3
```

### MDX

#### Fix `import` and `export` parsing ([#17996](https://github.com/prettier/prettier/pull/17996) by [@kovsu](https://github.com/kovsu) & [@fisker](https://github.com/fisker)) {#change-17996}

<!-- prettier-ignore -->
```mdx
{/* Input */}
- import is a word in lists
- export is a word in lists, too!

{/* Prettier 3.6 */}
- import is a word in list
  s
- export is a word in lists, too
  !

{/* Prettier 3.7 */}
- import is a word in lists
- export is a word in lists, too!
```

### YAML

#### Preserve empty line between map and comment ([#17843](https://github.com/prettier/prettier/pull/17843) by [@kovsu](https://github.com/kovsu)) {#change-17843}

<!-- prettier-ignore -->
```yaml
# Input
only: issues

# Comment

# Prettier 3.6
only: issues
# Comment

# Prettier 3.7
only: issues

# Comment
```

#### Preserve explicit document end marker ([#18296](https://github.com/prettier/prettier/pull/18296) by [@fisker](https://github.com/fisker)) {#change-18296}

<!-- prettier-ignore -->
```yaml
# Input
a: a
---
b: b
...
c: c
...
---
d: d

# Prettier 3.6
a: a
---
b: b
---
c: c
---
d: d

# Prettier 3.7
a: a
---
b: b
...
c: c
...
---
d: d
```

#### Use explicit key style for flow-mapping keys with trailing comments ([#18324](https://github.com/prettier/prettier/pull/18324) by [@kovsu](https://github.com/kovsu), [@fisker](https://github.com/fisker)) {#change-18324}

<!-- prettier-ignore -->
```yaml
# Input
{ "foo" # comment
  :bar }

# Prettier 3.6
{ "foo": bar } # comment

# Prettier 3.7
{ ? "foo" # comment
  : bar }
```

### API

#### Allow `plugin.parser.preprocess()` to return a `Promise` ([#17679](https://github.com/prettier/prettier/pull/17679) by [@fisker](https://github.com/fisker)) {#change-17679}

Align with [`plugin.printer.preprocess()`](https://prettier.io/docs/plugins#optional-preprocess), which allows to return a `Promise`.

We still suggest move your async work into `plugin.parser.parse()`, which already allow to return a `Promise`, we may remove support for `plugin.parser.preprocess()` in future.

#### Allow `AstPath#call()` to access property of nullish properties ([#17860](https://github.com/prettier/prettier/pull/17860) by [@fisker](https://github.com/fisker)) {#change-17860}

Previously, to check for a possible non-existent child node, we had to ensure the node existed first.

```js
const isFoo = path.call(() => path.node?.type === "Foo", "foo", "bar");
// Uncaught TypeError: Cannot read properties of undefined (reading 'bar')
```

We have to

```js
const isFoo =
  path.node.foo?.bar &&
  path.call(() => path.node?.type === "Foo", "foo", "bar");
```

Since Prettier 3.7, accessing a property of nullish properties no longer throws errors.

#### Pass ancestors to `plugin.printer.canAttachComment()` ([#18055](https://github.com/prettier/prettier/pull/18055) by [@fisker](https://github.com/fisker)) {#change-18055}

This prevent attaching comments to a specific child of node.

For example in this JavaScript code `const object = {property};`, the `Identifier` node (`property`) appears as both `Property.key` and `Property.value` in the AST, obviously it can only print once, if the comment is attached to the non-printable child the comment will get lost.

Plugins can now avoid this by adding a `canAttachComment` like this:

```js
export const canAttachComment = (node, [parent]) =>
  !(
    parent?.type === "Property" &&
    parent.shorthand &&
    parent.key === node &&
    parent.key !== parent.value
  );

export const print = (path, options, print) => {
  const { node } = path;
  switch (node.type) {
    case "Property":
      if (node.shorthand) {
        return print("value");
      }
    // ...
  }
};
```

#### Add support for `plugin.printer.printPrettierIgnored()` ([#18070](https://github.com/prettier/prettier/pull/18070) by [@fisker](https://github.com/fisker)) {#change-18070}

For a node with `prettier-ignore` comment, Prettier prints the text of the node directly. However, this may cause problems, for example, if the node needs to be parenthesized or needs to print a leading semicolon to prevent ASI issue in `--no-semi` mode.

Since Prettier 3.7, plugins can add a `printPrettierIgnored()` function to the printer to customize the `prettier-ignore`d node print process. This function uses the extract same signature as [`plugin.printer.print()`](https://prettier.io/docs/plugins#print)

#### Allow plugin to provide an `estree` printer ([#18072](https://github.com/prettier/prettier/pull/18072) by [@fisker](https://github.com/fisker)) {#change-18072}

Previously, if a plugin wanted to make a plugin with an `estree` printer that outputs different code based on the built-in one, the plugin needed to provide both `parsers` and `printers`. Prettier 3.7 allows a plugin to create a plugin that only provides an `estree` printer.

### CLI

#### Avoid creating `node_modules/.cache/` directory when `--cache` is not enabled ([#18124](https://github.com/prettier/prettier/pull/18124) by [@chiawendt](https://github.com/chiawendt)) {#change-18124}

Running `prettier .` without `--cache` no longer creates an empty `node_modules/.cache/` directory.
