Prettier 3.7: Enhanced Formatting Consistency and New Plugin Features
Prettier 3.7 delivers significant improvements in formatting consistency for TypeScript and Flow, resolves numerous bugs, adds support for Angular 21 and GraphQL 16.12, and introduces powerful new APIs for plugin developers.
We are thrilled to announce the release of Prettier 3.7! This update primarily focuses on refining the TypeScript and Flow formatting experience, introducing greater consistency and predictability for classes and interfaces. We also invite your feedback on an upcoming change regarding inconsistent opening brace logic for class and interface bodies.
Beyond these core improvements, Prettier 3.7 includes fixes for numerous bugs, adds support for new features in Angular 21 and GraphQL 16.12, and brings Front Matter support to Handlebars. For plugin developers, new APIs are available to offer enhanced control over comment attachment and handling of ignored nodes.
If you value Prettier's work, please consider sponsoring us directly via our OpenCollective or by sponsoring the projects we depend on. Your continued support is greatly appreciated!
Author:
Fisker Cheung
Highlights
TypeScript
Fix inconsistent printing between class and interface (#18094, #18091, #18215 by @fisker)
This release significantly enhances the consistency between Class and Interface formatting. Previously, these similar constructs could be formatted quite differently, leading to visual inconsistencies. We've aligned their formatting rules for a cleaner and more predictable output. This includes:
- Removal of extra indentation for type parameters in classes.
For example:
// 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 { } - Alignment of interface heritage printing with classes.
- Alignment of single heritage printing with super classes.
Inconsistent opening brace print logic of class and interface body
In Prettier v2.3, the opening brace { of a class body was moved to a new line when the class had multiple heritages, aiming to improve visual separation. This change, however, was not universally welcomed. We are now seeking community input on applying this same change to interfaces by leaving a comment on this issue. If no better solution emerges, this alignment for interface bodies will be implemented in Prettier v4.
// Prettier 3.7
declare class loooooooooooooooooooong implements looooooooooooooooooong, loooooooooooooooooooong {
property: string;
}
interface loooooooooooooooooooong extends looooooooooooooooooong, loooooooooooooooooooong {
// <-- This
property: string;
}
These changes also impact Flow syntax.
Other Changes
JavaScript
- Allow import attributes to break into multiple lines (#17329 by @fisker)
// 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 by @fisker)
Prettier now supports the Stage 2 "Discard Bindings" proposal via Babel.
const [void] = x; const { x: void } = x; - Fix inconsistent comment format (#17723 by @fisker)
Comments within complex
ifconditions now maintain their intended position.// 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 by @BPScott)
Prettier now avoids changing indentation for
test.fixme,test.describe.skip, andtest.describe.fixmefunctions, similar totest.skip. - Avoid breaking
{import,require.resolve,require.resolve.paths,import.meta.resolve}()with long module names (#17882, #17908 by @kovsu & @fisker)// Prettier 3.6 const b = require.resolve( "./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module", ); // Prettier 3.7 const b = require.resolve( "./a/long/long/long/long/long/long/long/long/long/long/long/path/to/module" ); - Improve comment handling inside if statement (#17998 by @fisker)
// 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 by @fisker)// Prettier 3.6 require( // Comment "foo" ); // Prettier 3.7 require( // Comment "foo", ); - Remove indentation in logical expression in
Boolean()call (#18087 by @kovsu) Reduces diffs when changing conditions or converting between!!andBoolean().// Prettier 3.7 const foo = Boolean( a_long_long_condition || a_long_long_long_condition || a_long_long_long_condition ); - Fix comments handling for for-statements (#18099 by @fisker, @sosukesuzuki)
// 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 by @fisker)
// 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 by @fisker)
// 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 by @fs0414)
Ensures correct operator precedence.
// Prettier 3.6 1 << bit % 8; // Prettier 3.7 1 << (bit % 8); - Fix inconsistent break for array literals (#18172 by @Dunqing, @fisker)
// Prettier 3.7 assert.deepStrictEqual(linesCollection.getViewLinesIndentGuides___(-1, -1), [1],); assert.deepStrictEqual(linesCollection.getViewLinesIndentGuides(-1, -1), [1, 2],); - Fix inconsistent logical expression print (#18205 by @fisker)
// Prettier 3.7 fn( a && a_long_long_long_long_long_long_long_long_long_long_long_long_long_condition ? a : b, ); - Fix inconsistent print between
CallExpressionandNewExpression(#18206 by @fisker)// 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 by @fisker)
// 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 by @fisker)
// 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 by @fisker)
// Prettier 3.7 for ( let i = 0, j = 0, len = allMatches.length, lenJ = selections.length; i < len; ) { } - Improve super class format (#18325 by @fisker)
// Prettier 3.7 class EnsureNoDisposablesAreLeakedInTestSuiteSuite extends eslint.Rule.RuleModule {}
TypeScript (Continued)
- Fix misplacement of comments after arrow (#17421 by @o-m12a, @t-mangoe)
// Prettier 3.7 export const test = (): any => /* first line second line */ null; - Add missing parentheses to arrow function in instantiation expression (#17724 by @fisker)
// Prettier 3.7 void (<_T extends never>() => {})(); - Fix
TSMappedTypeformat (#17785 by @fisker) Resolves a crash when formatting specific mapped types.// Prettier 3.7 export type A = B extends { C?: { [D in infer E]?: F } } ? G : H; - Print trailing comma in
TSImportTypeoptions (#17798 by @fisker) Supports trailing commas in import type attributes as fixed in TypeScript v5.9.// Prettier 3.7 type A = import("foo", { with: { type: "json", }, }); - Improve CommonJS module
require()with comments (#18035 by @fisker)// Prettier 3.7 import foo = require( // Comment "foo" ); - Line breaking after
=in type parameters (#18043 by @fisker)// Prettier 3.7 export type OuterType2< LongerLongerLongerLongerInnerType = LongerLongerLongerLongerLongerLongerLongerLongerOtherType, > = { a: 1 }; - Remove unexpected blank line before union types (#18109 by @jspereiramoura, @fisker)
This change also affects Flow syntax.// Prettier 3.7 type SuperLongTypeNameLoremIpsumLoremIpsumBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBla = | Fooo1000 | Baz2000 | BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong; - Fix inconsistent comment printing between
typescriptandflowparser (#18110 by @fisker) Ensures consistent comment placement across both parsers for interface types.// 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 by @fisker)
// Prettier 3.7 interface A { foo; <T>(): T } - Fix inconsistent print of
as constbetween flow and typescript parsers (#18161 by @fisker) Standardizes comment placement withas const.// Prettier 3.7 (Same output for `--parser=typescript` and `--parser=flow`) 1 /* comment */ as const; - Fix comment around
as/satisfiesexpression (#18162 by @fisker)// Prettier 3.7 1 as const /* comment */; - Fix misaligned union type (#18165 by @fisker)
// Prettier 3.7 interface I { elements: // comment | [string, ExpressionNode, ExpressionNode] | [string, ExpressionNode, ExpressionNode, ObjectExpression]; } - Remove extra empty line in union type (#18197 by @Dunqing)
// Prettier 3.7 type SuperLongTypeNameLoremIpsumLoremIpsumBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBla = | Fooo1000 | Baz2000 | BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;
Flow
- Add basic support for "match" syntax (#17681 by @fisker)
Prettier now supports Flow's
matchsyntax.// 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 by @SamChou19815)
// Prettier 3.7
opaque type Counter super empty extends Box
CSS
- Handle attribute selector with case-sensitive and uppercase case-insensitive flags (#17841, #17865 by @kovsu)
/* 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 by @fisker)
Resolves a crash when encountering custom properties like
--l: , #000;. - Fix selector being lowercased incorrectly inside css modules (#17929 by @kovsu)
Preserves original casing for selectors in CSS modules, e.g.,
myColor. - Fix formatting of CSS selectors containing
//(#17938 by @kovsu)/* Prettier 3.7 */ a[href="http://example.com"] { color: red; } - Remove unexpected space between font size and line height (#18114 by @kovsu)
/* Prettier 3.7 */ a { font: var(--size)/1; } - Fix extra indent for CSS comma-separated values after a block comment (#18228 by @seiyab)
/* 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 by @kovsu)
// Prettier 3.7 .foo { @include bar('A (B)'); } - Fix formatting of space-separated values (#17903 by @kovsu)
// Prettier 3.7 .foo { @include transition(min-height ($spacer / 2) ease-in-out); }
Less
- Fix variable name being lowercased incorrectly (#17820 by @kovsu)
Preserves original casing for Less variable names.
// Prettier 3.7 @fooBackground: line-gradient(#f00); a { background: @fooBackground; } - Keep property/variable accessors tight (#17983 by @kovsu)
// Prettier 3.7 .average(@x, @y) { @result: ((@x + @y) / 2); } div { padding: .average(16px, 50px)[@result]; }
HTML
- Support formatting
allowattribute of iframe element (#17879 by @kovsu)<!-- 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 by @kovsu)
Prettier now formats JavaScript within inline event handlers.
<!-- 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, #18294 by @fisker)
Adds support for new assignment operators introduced in Angular 20.1 and regular expressions in Angular 21.
<!-- Prettier 3.7 --> <b (click)="a ??= b"> {{ /\d+/g }} </b> - Fix comments getting duplicated in interpolation (#17862 by @fisker)
<!-- Prettier 3.7 --> {{ a() // comment }} - Fix formatting of "non-null assertion" (#18047 by @fisker)
<!-- Prettier 3.7 --> {{ foo?.bar!.baz }}
Ember / Handlebars
- Added Front Matter support to Handlebars (#17781 by @Codezilluh)
Handlebars files can now include Front Matter.
---
title: My page title keywords:
- word
- other word
{{title}}
-
{{#each keywords}}
- {{this}} {{/each}}
GraphQL
- Support "executable descriptions" (#18214 by @fisker)
Prettier now supports descriptions on executable definitions.
# Prettier 3.7 "Description" query { node { id } }
Markdown
- Improve emoji size measurement (#17813 by @seiyab)
Enhances table alignment in Markdown, especially with emojis.
<!-- Prettier 3.7 --> | | | | :-: | :-: | | ✔ | ✘ | | ✘ | ✔ | | ✔ | ✘ | - Infer TOML parser for Front Matter (#17965 by @kovsu) TOML Front Matter is now processed by the appropriate plugin, if available, for HTML and CSS files as well.
- Fix strong emphasis format (#18010 by @yin1999)
A supplementary fix for #17143, ensuring correct handling of nested strong/italic emphasis.
<!-- Prettier 3.7 --> 1 ** * 2 * ** 3 1 ** * 2 * ** 3
MDX
- Fix
importandexportparsing (#17996 by @kovsu & @fisker) Ensuresimportandexportkeywords are correctly parsed when appearing within Markdown lists in MDX files.{/* 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 by @kovsu)
# Prettier 3.7 only: issues # Comment - Preserve explicit document end marker (#18296 by @fisker)
# Prettier 3.7 a: a --- b: b ... c: c ... --- d: d - Use explicit key style for flow-mapping keys with trailing comments (#18324 by @kovsu, @fisker)
# Prettier 3.7 { ?"foo" # comment : bar }
API
- Allow
plugin.parser.preprocess()to return aPromise(#17679 by @fisker) Aligns withplugin.printer.preprocess(), which already supports Promises. While supported, async work is still recommended forplugin.parser.parse(). - Allow
AstPath#call()to access property of nullish properties (#17860 by @fisker)AstPath#call()no longer throws errors when attempting to access properties of potentiallynullorundefinedchild nodes, simplifying checks for non-existent nodes. - Pass ancestors to
plugin.printer.canAttachComment()(#18055 by @fisker) Plugins can now use ancestor information to prevent comments from being attached to non-printable child nodes, avoiding comment loss.export const canAttachComment = (node, [parent]) => !( parent?.type === "Property" && parent.shorthand && parent.key === node && parent.key !== parent.value ); - Add support for
plugin.printer.printPrettierIgnored()(#18070 by @fisker) Plugins can now customize howprettier-ignored nodes are printed, allowing for custom parenthesization or leading semicolons to prevent ASI issues in--no-semimode. - Allow plugin to provide an
estreeprinter (#18072 by @fisker) Plugins can now create a plugin that solely provides anestreeprinter, simplifying development for those building upon built-inestreeformatting.
CLI
- Avoid creating
node_modules/.cache/directory when--cacheis not enabled (#18124 by @chiawendt) Runningprettier .without the--cacheflag no longer creates an emptynode_modules/.cache/directory, improving cleanliness.