Skip to main content

Prettier 3.5: New objectWrap option, experimentalOperatorPosition option and TS config file support!

· 9 min read

This release includes a lot of bug fixes and the following new features:

  • Support for the new objectWrap option
  • Support for the new experimental experimentalOperatorPosition option
  • Support for TypeScript configuration file

See each section for details.

If you appreciate Prettier and would like to support our work, please consider sponsoring us directly via our OpenCollective or by sponsoring the projects we depend on, such as typescript-eslint, remark, and Babel. Thank you for your continued support!

Why We Added Two New Options

This release introduces two new options. If you’re familiar with Prettier’s Option Philosophy, you might be wondering: “Why add new options?” Rest assured, these aren’t your typical options, nor do they violate our option philosophy.

As the name suggests, experimentalOperatorPosition is experimental. We have a policy for experimental options, which means it will eventually be removed. In the future, the new behavior could become the default, or this option might be dropped entirely. If you’ve been following Prettier for a while, you may recall we once added an experimentalTernaries option, and this follows the same approach.

objectWrap is a bit special. For a long time, we’ve struggled with how to print multi-line objects. We haven’t yet found the perfect solution, so we’ve resorted to a semi-manual approach. For more details, see our Rationale. The current behavior isn’t ideal because the final output can vary based on how the user writes their code. To provide a more consistent format, we’ve decided to introduce the objectWrap option.

Although this release includes two new options, we want to emphasize that we haven’t forgotten Prettier’s option philosophy. These options address specific, long-standing formatting challenges without compromising our option philosophy.

Highlights

JavaScript

Add experimental option for breaking lines before binary operators (#7111 by @btmills)

This is implemented behind the --experimental-operator-position <start|end> flag.

When binary expressions wrap lines, start prints the operators at the start of new lines. Placing binary operators at the beginning of wrapped lines can make the operators more prominent and easier to scan.

// Input
var a = Math.random() * (yRange * (1 - minVerticalFraction)) + minVerticalFraction * yRange - offset;

// `experimentalOperatorPosition: end` (default behavior)
var a =
Math.random() * (yRange * (1 - minVerticalFraction)) +
minVerticalFraction * yRange -
offset;

// `experimentalOperatorPosition: start`
var a =
Math.random() * (yRange * (1 - minVerticalFraction))
+ minVerticalFraction * yRange
- offset;

Implement objectWrap config option (#16163 by @pauldraper, @sosukesuzuki)

Prettier has historically done semi-manual formatting of multi-line JavaScript object literals.

Namely, an object is kept on multiple lines if there is a newline prior to the first property, even if it could fit on a single line. See Multi-line objects for more details.

While this behavior continues to be the default, --object-wrap=collapse instead ignores whitespace when formatting object literals.

// Input
const obj1 = {
name1: "value1", name2: "value2",
};

const obj2 = { name1: "value1",
name2: "value2",
};

// Prettier 3.4
const obj1 = {
name1: "value1",
name2: "value2",
};

const obj2 = { name1: "value1", name2: "value2" };

// Prettier 3.5 (with `--object-wrapping=collapse`)
const obj1 = { name1: "value1", name2: "value2" };

const obj2 = { name1: "value1", name2: "value2" };

API

Add support for TypeScript config files (#16828 by @itsyoboieltr & @fisker)

Added new format of configuration files:

  • .prettierrc.ts
  • .prettierrc.mts
  • .prettierrc.cts
  • prettier.config.ts
  • prettier.config.mts
  • prettier.config.cts

Note:

Currently TypeScript support in Node.js is experimental.

To make TypeScript config files work, Node.js>=22.6.0 is required and Node.js v22 requires --experimental-strip-types.

You can run prettier with

node --experimental-strip-types node_modules/prettier/bin/prettier.cjs . --write

or

NODE_OPTIONS="--experimental-strip-types" prettier . --write

Other TS loaders should also work, but not tested, use at your own risk.

For example, with tsx, you can

node --import tsx node_modules/prettier/bin/prettier.cjs . --write

or

tsx node_modules/prettier/bin/prettier.cjs . --write

Other Changes

JavaScript

Improve word wrapping edge cases in JSX (#16700 by @seiyab)

// Input
br_triggers_expression_break =
<div><br />
text text text text text text text text text text text {this.props.type} </div>

// Prettier 3.4
br_triggers_expression_break = (
<div>
<br />
text text text text text text text text text text text {
this.props.type
}{" "}
</div>
);

// Prettier 3.5
br_triggers_expression_break = (
<div>
<br />
text text text text text text text text text text text{" "}
{this.props.type}{" "}
</div>
);

Flow

Support const type parameters in Flow (#16947 by @gkz)

function f<const T>(): void {}

// Prettier 3.4
// Parse error

// Prettier 3.5
function f<const T>(): void {}

CSS

Break before breaking comma separated values (#16907 by @seiyab)

/* Input */
a {
background-image:
linear-gradient(to bottom, rgb(255 255 0 / 50%), rgb(0 0 255 / 50%)),
url("catfront.png");
}

/* Prettier 3.4 */
a {
background-image: linear-gradient(
to bottom,
rgb(255 255 0 / 50%),
rgb(0 0 255 / 50%)
),
url("catfront.png");
}

/* Prettier 3.5 */
a {
background-image:
linear-gradient(to bottom, rgb(255 255 0 / 50%), rgb(0 0 255 / 50%)),
url("catfront.png");
}

Vue

Support .prop shorthand (#16920 by @fisker)

.foo is shorthand for v-bind:foo.prop. See v-bind builtin directive for details.

<!-- Input -->
<template>
<button .disabled=" a &&b ">Click!</button>
</template>

<!-- Prettier 3.4 -->
<template>
<button .disabled=" a &&b ">Click!</button>
</template>

<!-- Prettier 3.5 -->
<template>
<button .disabled="a && b">Click!</button>
</template>

Angular

Improve line breaks inside ICU blocks (#16922 by @fisker)

<!-- Input -->
<span>The author is {gender, select, male {male} female {female} other {other}}</span>
<span>The author is <span>male consectetur adipiscing elit, sed do eiusmod</span></span>

<!-- Prettier 3.4 -->
<span
>The author is {gender, select, male {male} female {female} other {other}
}</span>
<span
>The author is
<span>male consectetur adipiscing elit, sed do eiusmod</span></span
>

<!-- Prettier 3.5 -->
<span
>The author is
{gender, select, male {male} female {female} other {other}}</span
>
<span
>The author is
<span>male consectetur adipiscing elit, sed do eiusmod</span></span
>

Fix extra new line inside ICU blocks (#16922 by @fisker)

<!-- Input -->
{active, select,
true {
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod temp
}
false {
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod temp
}
}

<!-- Prettier 3.4 -->
{active, select,
true {
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod temp

}
false {
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod temp

}
}

<!-- Prettier 3.5 -->
{active, select,
true {
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod temp
}
false {
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod temp
}
}

Ember / Handlebars

Handle <style> and <pre> tags in Handlebars/Glimmer (#15087 by @jurgenwerk)

{{!-- Input --}}
<pre>
cd ~
ls
echo "hey"
</pre>
<style>
.red { color: red }
.blue {
color: red
}
</style>

{{!-- Prettier 3.4 --}}
<pre>
cd ~ ls echo "hey"
</pre>
<style>
.red { color: red } .blue { color: blue }
</style>

{{!-- Prettier 3.5 --}}
<pre>
cd ~
ls
echo "hey"
</pre>
<style>
.red {
color: red;
}
.blue {
color: red;
}
</style>

Markdown

U+FF5E as CJK punctuation (#16832 by @tats-u)

U+FF5E FULLWIDTH TILDE (~) is commonly used as a substitute for U+301C WAVE DASH (〜) in Windows for Japanese. Full width alphabets are less used in Markdown documents comparing to other types of documents (e.g. Microsoft Office documents), and the full width tilde is much less used as this purpose compared to full width alphabets and digits. Therefore, we can assume that the full width tilde in Markdown documents in the wild are a alternative form of the wave dash and a part of CJK punctuation.

<!-- Input (--prose-wrap=never) -->
a 字 a 字 a 字
60~
100点
60〜
100点

<!-- Prettier 3.4 -->
a 字 a 字 a 字 60~ 100点 60〜10点


<!-- Prettier 3.5 -->
a 字 a 字 a 字 60~10点 60〜100点

The first symbol between 60 and 100 in the above example is U+FF5E FULLWIDTH TILDE (~) and the second one is U+301C WAVE DASH (〜).

API

Support read config from package.json with JSONC syntax on Bun (#17041 by @fisker)

Bun 1.2 added JSONC support in package.json, in previous version of Prettier, it will ignore prettier config in it. Since Prettier 3.5, we can read prettier config from it without error.

However, since it's just a Bun feature and not supported by Node.js, it can only work when running Prettier with Bun.

Important note: Prettier uses json-stringify parser to format package.json file by default, to support formatting package.json file with JSONC syntax, you need override the parser option

export default {
overrides: [
{
files: ["package.json"],
options: {
parser: "jsonc",
},
},
],
};

If you can't upgrade Prettier for some reason, you can still use JSONC syntax in package.json, but don't put your prettier config in it, you'll have to use another configuration file.

Miscellaneous

Use ESM entrypoint for require(ESM) (#16958 by @tats-u)

Node.js 22.12 or later can (experimentally) load ESM modules with require function without runtime flags. This change enables require to load Prettier without the CommonJS entrypoint with almost only the ability to import the ESM entrypoint.

The feature to load ES modules with require is not completely stable but can be used without ExperimentalWarning as of Node 22.13.