Hoppa till huvudinnehållet

Prettier 3.7: Förbättrad formateringskonsekvens och nya plugin-funktioner!

· 28 min att läsa
Inofficiell Beta-översättning

Denna sida har översatts av PageTurner AI (beta). Inte officiellt godkänd av projektet. Hittade du ett fel? Rapportera problem →

Vi är glada att presentera Prettier 3.7! Den här versionen fokuserar på att förfina upplevelsen för TypeScript och Flow, specifikt genom att justera formateringen av klasser och gränssnitt för att bli mer konsekvent och förutsägbar. Vi vill också höra din åsikt om den kommande ändringen som åtgärdar inkonsekvent logik för utskrift av inledande klammerparenteser i klass- och gränssnittskroppar.

Dessutom har vi åtgärdat många buggar, lagt till stöd för nya funktioner i Angular 21 och GraphQL 16.12, samt infört stöd för Front Matter i Handlebars.

För plugin-utvecklare har vi lagt till nya API:er som ger er mer kontroll över kommentarshantering och hantering av ignorerade noder.

Om du uppskattar Prettier och vill stödja vårt arbete, överväg att sponsra oss direkt via vår OpenCollective eller genom att sponsra projekt vi är beroende av. Tack för ditt fortsatta stöd!

Höjdpunkter

TypeScript

Åtgärda inkonsekvent utskrift mellan klass och gränssnitt (#18094, #18091, #18215 av @fisker)

I den här versionen har vi fokuserat intensivt på att förbättra konsekvensen mellan klass- och gränssnittsformatering. Tidigare skrevs dessa två liknande konstruktioner ut på ganska olika sätt, vilket ledde till visuella inkonsekvenser. Vi har justerat deras formateringsregler för att ge en mer förutsägbar och renare utdata.

Överflödig indrag för typparametrar i klasser har tagits bort
// 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 {}
Justera utskrift av gränssnittsarv mot klassers
// 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> {}
Justera utskrift av enstaka arv mot superklass
// 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
> {}
Inkonsekvent logik för utskrift av inledande klammerparentes i klass- och gränssnittskroppar

I Prettier v2.3 började vi, för att förbättra den visuella separationen mellan klasshuvud och klasskropp, skriva ut den inledande { för klasskroppen på en ny rad när klassen har flera arv.

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

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

Men inte alla är nöjda med denna ändring.

Berätta vad du tycker om att applicera denna ändring på gränssnitt genom att lämna en kommentar på det här issue:t.

Om du har en bättre lösning på detta problem är vi mer än villiga att diskutera den också.

Om inte en bättre lösning dyker upp kommer vi att anpassa utskriften av gränssnittskroppen till den för klasskroppen i Prettier v4.

// 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;
}

Dessa ändringar påverkar även Flows syntax

Andra ändringar

JavaScript

Tillåt brytning av importattribut över flera rader (#17329 av @fisker)

// 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",
};

Lägg till stöd för "Discard Bindings"-förslaget (#17708 av @fisker)

Steg 2-förslaget "Discard Bindings" stöds nu via Babel. Kom också ihåg vår policy för icke-standardiserad syntax innan du använder detta föreslagna syntaxdrag med Prettier.

const [void] = x;

const {x:void} = x;

Åtgärda inkonsekvent kommentarsformat (#17723 av @fisker)

// 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();
}

Lägger till ytterligare Playwright-testfunktioner (#17876 av @BPScott)

Prettier undviker redan att ändra indrag för testfunktioner när du lägger till .skip på dem. Nu hanterar den också Playwright-funktionerna test.fixme, test.describe.skip och test.describe.fixme på samma sätt som test.skip.

// 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
});

Undvik radbrytning i {import,require.resolve,require.resolve.paths,import.meta.resolve}() med långa modulnamn (#17882, #17908 av @kovsu & @fisker)

// 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");

Förbättrad hantering av kommentarer i if-satser (#17998 av @fisker)

// 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();
}

Förbättrad hantering av require()-anrop med kommentarer (#18037 av @fisker)

// Input
require(
// Comment
"foo"
);

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

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

Ta bort indrag i logiska uttryck i Boolean()-anrop (#18087 av @kovsu)

Minskar diff när du ändrar ett villkor till motsatt värde, eller växlar mellan !! och Boolean().

// 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
);

Fixa kommentarshantering för for-satser (#18099 av @fisker, @sosukesuzuki)

// 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();

Förbättrad utskrift av kommentarer kring tomma satser (#18108 av @fisker)

// 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 */ ;

Fixa inkonsekvent kommentarsutskrift mellan klassmetoder och objektmetoder (#18147 av @fisker)

// 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;
},
};

Lägg till saknade parenteser i bitvisa operatorer (#18163 av @fs0414)

// 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);

Fixa inkonsekvent radbrytning för arrayliteraler (#18172 av @Dunqing, @fisker)

// 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],
);

Fixa inkonsekvent utskrift av logiska uttryck (#18205 av @fisker)

// 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,
);

Fixa inkonsekvent utskrift mellan CallExpression och NewExpression (#18206 av @fisker)

// 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,
)

Ta bort överflödiga parenteser runt JSX-element (#18243 av @fisker)

// 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>,
);

Förbättra formateringen av logiska uttryck som anropsobjekt för nytt uttryck (#18245 av @fisker)

// 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
)();

Ta bort tom rad i for-satser utan "update" (#18300 av @fisker)

// 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;
) {}

Förbättra formatet för superklasser (#18325 av @fisker)

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

Fixa felplacering av kommentarer efter pilfunktion (#17421 av @o-m12a, @t-mangoe)

// 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;

Lägg till saknade parenteser för pilfunktion i instansieringsuttryck (#17724 av @fisker)

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

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

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

Fixa format för TSMappedType (#17785 av @fisker)

// 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;

Skriv ut avslutande kommatecken i TSImportType-alternativ (#17798 av @fisker)

Avslutande kommatecken i import type-attribut tilläts inte före TypeScript v5.9, nu har buggen fixats.

// 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
});

Förbättra CommonJS-modulens require() med kommentarer (#18035 av @fisker)

// Input
import foo = require(
// Comment
"foo"
);

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

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

Radbrytning efter = i typparametrar (#18043 av @fisker)

// 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 };

Ta bort oväntad tom rad före unionstyper (#18109 av @jspereiramoura, @fisker)

// 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;

Denna ändring påverkar även Flow-syntax

Fixa inkonsekvent kommentarsutskrift mellan typescript och flow-parser (#18110 av @fisker)

// 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;
}

Fixa saknat semikolon före anropssignaturer (#18118 av @fisker)

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

Fixa inkonsekvent utskrift av as const mellan flow- och typescript-parsers (#18161 av @fisker)

// 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;

Fixa kommentarer runt as/satisfies-uttryck (#18162 av @fisker)

// 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
*/;

Åtgärda feljusterad unionstyp (#18165 by @fisker)

// 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];
}

Ta bort extra tom rad i unionstyp (#18197 by @Dunqing)

// Input
type SuperLongTypeNameLoremIpsumLoremIpsumBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBla =
Fooo1000 | Baz2000 | BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;

// Prettier 3.6
type SuperLongTypeNameLoremIpsumLoremIpsumBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBla =

| Fooo1000
| Baz2000
| BarLoooooooooooooooooooooooooooooooooooooooooooooooooLong;

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

Flow

Lägg till grundläggande stöd för "match"-syntax (#17681 by @fisker)

// 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" },
};

Lägg till stöd för opak typ med övre och nedre gräns (#17792 by @SamChou19815)

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

Hantera attributselektor med skiftlägeskänsliga och versalokänsliga flaggor (#17841, #17865 by @kovsu)

/* 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;
}

Korrigera krasch vid formatering av speciella egendefinierade egenskaper (#17899 by @fisker)

/* Input */
:root {
--l: , #000;
}

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

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

Korrigera felaktig versalisering av selektorer i CSS-moduler (#17929 by @kovsu)

/* 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;
}

Åtgärda formatering av CSS-selektorer som innehåller // (#17938 by @kovsu)

/* 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;
}

Ta bort oväntat mellanrum mellan teckenstorlek och radhöjd (#18114 by @kovsu)

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

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

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

Åtgärda extra indrag för kommaseparerade CSS-värden efter blockkommentar (#18228 by @seiyab)

/* 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

Korrigera mellanrumsproblem med parenteser i mixin-argument (#17836 by @kovsu)

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

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

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

Åtgärda formatering av mellanslagsseparerade värden (#17903 by @kovsu)

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

Korrigera felaktig versalisering av variabelnamn (#17820 by @kovsu)

// 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;
}

Behåll tight formatering av egenskaps-/variabelåtkomster (#17983 by @kovsu)

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

Stöd formatering av allow-attribut för iframe-element (#17879 by @kovsu)

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

Formatera inline-händelsehanterare (#17909 by @kovsu)

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

Stöd för Angular 21 (#17722, #18294 av @fisker)

Angular 20.1 lade till stöd för nya tilldelningsoperatorer. Angular 21 lade till stöd för reguljära uttryck.

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

Åtgärda att kommentarer dupliceras i interpolation (#17862 av @fisker)

<!-- Input -->
{{a() // comment}}

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

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

Åtgärda formateringen av "non-null assertion" (#18047 av @fisker)

<!-- Input -->
{{ foo?.bar!.baz }}

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

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

Ember / Handlebars

Lagt till stöd för Front Matter i Handlebars (#17781 av @Codezilluh)

Front Matter kan nu användas i Handlebars.

---
title: My page title
keywords:
- word
- other word
---

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

Bevara else if-syntax för anpassade hjälpfunktioner (#17856 av @kovsu)

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

Ta bort extra tomma rader i <style>-taggar (#18065 av @kovsu, @fisker)

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

Tvinga inte element att brytas med --html-whitespace-sensitivity=ignore (#18133 av @fisker)

{{! Input }}
<div> </div>

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

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

GraphQL

Stöd för "executable descriptions" (#18214 av @fisker)

# 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

Förbättra mätning av emoji-storlek (#17813 av @seiyab)

Denna ändring förbättrar tabelljusteringen i alla språk.

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

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


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

Härled TOML-tolk för Front Matter (#17965 av @kovsu)

TOML Front Matter kan bearbetas av rätt plugin om sådan finns. Fungerar även för HTML- och CSS-filer.

Åtgärda formatering av stark betoning (#18010 av @yin1999)

Detta är ett kompletterande fix för #17143, där den ursprungliga PR:n inte kunde avgöra om innehållet på vänster och höger sida var ord.

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

Åtgärda tolkning av import och export (#17996 av @kovsu & @fisker)

{/* 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

Bevara tom rad mellan map och kommentar (#17843 av @kovsu)

# Input
only: issues

# Comment

# Prettier 3.6
only: issues
# Comment

# Prettier 3.7
only: issues

# Comment

Bevara explicit dokumentavslutningsmarkör (#18296 by @fisker)

# 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

Använd explicit nyckelstil för flow-mapping-nycklar med efterföljande kommentarer (#18324 by @kovsu, @fisker)

# Input
{ "foo" # comment
:bar }

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

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

API

Tillåt att plugin.parser.preprocess() returnerar ett Promise (#17679 by @fisker)

Anpassning till plugin.printer.preprocess() som redan tillåter att returnera ett Promise.

Vi rekommenderar fortfarande att flytta asynkron arbete till plugin.parser.parse() som redan tillåter att returnera ett Promise. Stöd för plugin.parser.preprocess() kan komma att tas bort i framtiden.

Tillåt att AstPath#call() kommer åt egenskaper hos nullish-egenskaper (#17860 by @fisker)

Tidigare behövde vi först säkerställa att en nod existerade för att kunna kontrollera en eventuellt icke-existerande barnnod.

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

Vi var tvungna att:

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

Från och med Prettier 3.7 ger åtkomst till egenskaper hos nullish-egenskaper inte längre fel.

Skicka förfäder till plugin.printer.canAttachComment() (#18055 by @fisker)

Detta förhindrar att kommentarer fästs vid specifika barnnoder.

Exempelvis i JavaScript-koden const object = {property}; förekommer Identifier-noden (property) både som Property.key och Property.value i AST:t. Uppenbarligen kan den bara skrivas ut en gång, och om kommentaren fästs vid den icke-utskrivbara barnnoden försvinner kommentaren.

Plugins kan nu undvika detta genom att lägga till en canAttachComment så här:

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");
}
// ...
}
};

Lägg till stöd för plugin.printer.printPrettierIgnored() (#18070 by @fisker)

För en nod med prettier-ignore-kommentar skriver Prettier ut nodens text direkt. Detta kan dock orsaka problem, till exempel om noden behöver omges av parenteser eller behöver skriva ut ett inledande semikolon för att förhindra ASI-problem i --no-semi-läge.

Från och med Prettier 3.7 kan plugins lägga till en printPrettierIgnored()-funktion i skrivaren för att anpassa utskriftsprocessen för prettier-ignore-ignorerade noder. Denna funktion använder samma signatur som plugin.printer.print().

Tillåt plugin att tillhandahålla en estree-printer (#18072 by @fisker)

Tidigare behövde en plugin som ville skapa en estree-skrivare med annorlunda utdata än den inbyggda tillhandahålla både parsers och printers. Prettier 3.7 tillåter nu att en plugin enbart tillhandahåller en estree-skrivare.

CLI

Undvik att skapa node_modules/.cache/-katalog när --cache inte är aktiverat (#18124 by @chiawendt)

Att köra prettier . utan --cache skapar inte längre en tom node_modules/.cache/-katalog.