website/blog/2020-11-20-2.2.0.md
This release supports new JavaScript parsers espree and meriyah, supports TypeScript 4.1, ships ESM standalone bundles for modern browsers, and includes many bug fixes and improvements!
<!-- truncate -->espree and meriyah parser (#9000, #9514 by @fisker)Two new values for the parser option has been added:
espree - which is the default parser used by ESLint.
Note that espree only works for Finished ECMAScript Proposals, and is stricter than the babel parser.
// Input
type MappedTypeWithNewKeys<T> = {
[K in keyof T as NewKeyType]: T[K]
};
// Prettier 2.1
SyntaxError: Unexpected token, expected "]" (2:17)
1 | type MappedTypeWithNewKeys<T> = {
> 2 | [K in keyof T as NewKeyType]: T[K]
| ^
3 | };
// Prettier 2.2
type MappedTypeWithNewKeys<T> = {
[K in keyof T as NewKeyType]: T[K]
};
// Input
type HelloWorld = `Hello, ${keyof World}`
// Prettier 2.1
SyntaxError: Unexpected token, expected "}" (1:35)
> 1 | type HelloWorld = `Hello, ${keyof World}`
| ^
// Prettier 2.2
type HelloWorld = `Hello, ${keyof World}`;
Prettier now also comes as ES modules, which can be directly used in modern browsers:
import prettier from "https://unpkg.com/prettier/esm/standalone.mjs";
import parserGraphql from "https://unpkg.com/prettier/esm/parser-graphql.mjs";
prettier.format("query { }", {
parser: "graphql",
plugins: [parserGraphql],
});
// Input
const style = css`
width: ${size}${sizeUnit};
`;
// Prettier 2.1
const style = css`
width: ${size} ${sizeUnit};
`;
// Prettier 2.2
const style = css`
width: ${size}${sizeUnit};
`;
// Input
html`${
foo
/* comment */
}`;
html`
${
foo
/* comment */
}
`;
graphql`${
foo
/* comment */
}`;
css`${
foo
/* comment */
}`;
// Prettier 2.1
html`${foo}`;
/* comment */
html`
${foo}
/* comment */
`;
graphql`
${foo}
/* comment */
`;
css`
${foo}
/* comment */
`;
// Prettier 2.2
html`${
foo
/* comment */
}`;
html`
${
foo
/* comment */
}
`;
graphql`${
foo
/* comment */
}`;
css`${
foo
/* comment */
}`;
This improves the formatting for Google Closure Library namespaces.
<!-- prettier-ignore -->// Input
aaaaaaaa.bbbbbbbb.cccccccc.dddddddd.eeeeeeee.ffffffff.gggggggg2 = class extends (
aaaaaaaa.bbbbbbbb.cccccccc.dddddddd.eeeeeeee.ffffffff.gggggggg1
) {
method () {
console.log("foo");
}
};
// Prettier 2.1
aaaaaaaa.bbbbbbbb.cccccccc.dddddddd.eeeeeeee.ffffffff.gggggggg2 = class extends aaaaaaaa
.bbbbbbbb.cccccccc.dddddddd.eeeeeeee.ffffffff.gggggggg1 {
method() {
console.log("foo");
}
};
// Prettier 2.2
aaaaaaaa.bbbbbbbb.cccccccc.dddddddd.eeeeeeee.ffffffff.gggggggg2 = class extends (
aaaaaaaa.bbbbbbbb.cccccccc.dddddddd.eeeeeeee.ffffffff.gggggggg1
) {
method() {
console.log("foo");
}
};
while statements (#9345 by @sosukesuzuki)// Input
while(1) // Comment
foo();
// Prettier 2.1
while (
1 // Comment
)
foo();
// Prettier 2.2
while (1)
// Comment
foo();
@babel/parser 7.12 (#9408, #9476, #9597 by @sosukesuzuki)Updated the JavaScript parser to @babel/parser 7.12. This fixes several bugs and supports some new syntax.
The "module attributes" proposal supported on 2.1 has been significantly changed and also renamed to "import assertions".
import foo from "./foo.json" assert { type: "json" };
let happy = "happy";
export { happy as "😃" };
class C {
static #x = 42;
static y;
static {
try {
this.y = doSomethingWith(this.#x);
} catch {
this.y = "unknown";
}
}
}
// Input
foo = html`<div>\u{prettier}</div>`;
foo = html`\u{prettier}${foo}pr\u{0065}ttier`;
foo = markdown`# \u{prettier}\u{0065}`;
// Prettier 2.1
foo = html``;
foo = html`null${foo}prettier`;
foo = markdown`
# \u{prettier}\u{0065}
`;
// Prettier 2.2
foo = html`<div>\u{prettier}</div>`;
foo = html`\u{prettier}${foo}pr\u{0065}ttier`;
foo = markdown`# \u{prettier}\u{0065}`;
import {a as a} and export {a as a} (#9435 by @fisker)// Input
import { a as a } from "a";
export { b as b } from "b";
// Prettier 2.1
import { a } from "a";
export { b } from "b";
// Prettier 2.2
import { a as a } from "a";
export { b as b } from "b";
// Input
function* f() {
yield <div>generator</div>
}
// Prettier 2.1
function* f() {
yield (<div>generator</div>);
}
// Prettier 2.2
function* f() {
yield <div>generator</div>;
}
// Prettier 2.1
function* mySagas() {
yield effects.takeEvery(rexpress.actionTypes.REQUEST_START, function* ({
id
}) {
console.log(id);
yield rexpress.actions(store).writeHead(id, 400);
yield rexpress.actions(store).end(id, "pong");
console.log("pong");
});
}
// Prettier 2.2
function* mySagas() {
yield effects.takeEvery(
rexpress.actionTypes.REQUEST_START,
function* ({ id }) {
console.log(id);
yield rexpress.actions(store).writeHead(id, 400);
yield rexpress.actions(store).end(id, "pong");
console.log("pong");
}
);
}
require(/* comment */) (#9670 by @fisker)// Input
require(/* comment */)
// Prettier 2.1
Error: Comment "comment" was not printed. Please report this error!
// Prettier 2.2
require(/* comment */);
// Input
let x: {
// prettier-ignore
y: z;
};
// Prettier 2.1
let x: {
// prettier-ignore
y: z;;
};
// Prettier 2.2
let x: {
// prettier-ignore
y: z;
};
// Input
foo = { bar: (a = b) };
// Prettier 2.1
foo = { bar: a = b };
// Prettier 2.2
foo = { bar: (a = b) };
typescript and flow (#9521 by @fisker)// Input
const name: SomeGeneric<
Pick<Config, "ONE_LONG_PROP" | "ANOTHER_LONG_PROP">
> = null;
// Prettier 2.1 (--parser=typescript)
const name: SomeGeneric<Pick<
Config,
"ONE_LONG_PROP" | "ANOTHER_LONG_PROP"
>> = null;
// Prettier 2.1 (--parser=flow)
const name: SomeGeneric<
Pick<Config, "ONE_LONG_PROP" | "ANOTHER_LONG_PROP">
> = null;
// Prettier 2.2 (typescript and flow parser)
const name: SomeGeneric<
Pick<Config, "ONE_LONG_PROP" | "ANOTHER_LONG_PROP">
> = null;
prettier-ignored mapped types (#9551 by @fisker)// Input
type a= {
// prettier-ignore
[A in B]: C | D
}
// Prettier 2.1
type a = {
// prettier-ignore
A in B: C | D;
};
// Prettier 2.2
type a = {
// prettier-ignore
[A in B]: C | D
};
babel parser to babel-flow if the @flow pragma is found (#9071 by @fisker)In practice, this means that as long as your Flow files have the pragma, it's safe to use the .js extension for them. Prettier will correctly parse and print them without any additional configuration. Previously, the pragma was recognized by the parser, but there existed minor correctness issues with the printer. E.g. it's not safe to unquote number keys in Flow.
// Input (with --parser babel)
// @flow
f<T>({ "2": 2 })
// Prettier 2.1
// @flow
f<T>({ 2: 2 });
// Prettier 2.2
// @flow
f<T>({ "2": 2 });
Previously, was not supported. Now, the following is formatted:
<!-- prettier-ignore -->// Input
enum E {
A,
B,
...
}
// Prettier 2.1: parse error
// Prettier 2.2
enum E {
A,
B,
...
}
this parameter annotations (#9457 by @dsainati1, #9489 by @fisker)// Input
function f(this: string, a: number) {
}
type T = (this: boolean, a: number) => boolean;
// Prettier 2.1
function f(this: string, a: number) {}
type T = (a: number) => boolean;
// Prettier 2.2
function f(this: string, a: number) {
}
type T = (this: boolean, a: number) => boolean;
BigIntLiteralTypeAnnotation and BigIntTypeAnnotation (#9523 by @fisker)Add support for BigIntLiteralTypeAnnotation and BigIntTypeAnnotation in Flow.
// Input
const foo: bigint = 1n;
const bar: baz<1n> = 1n;
// Prettier 2.1
Error: unknown type: "BigIntTypeAnnotation"
at ...
// Prettier 2.2
const foo: bigint = 1n;
const bar: baz<1n> = 1n;
// Input
const foo1: Fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo<symbol> = a
const foo2: Fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo<"STRING"> = a;
const foo3: Fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo<0> = a;
// Prettier 2.1
const foo1: Fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo<
symbol
> = a;
const foo2: Fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo<
"STRING"
> = a;
const foo3: Fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo<
0
> = a;
// Prettier 2.2 (typescript and flow parser)
const foo1: Fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo<symbol> = a
const foo2: Fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo<"STRING"> = a;
const foo3: Fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo<0> = a;
prettier-ignored type assertions (#9553 by @fisker)// Input
transform(
// prettier-ignore
(pointTransformer: (Point => Point))
);
// Prettier 2.1
transform(
// prettier-ignore
pointTransformer: (Point => Point)
);
// Prettier 2.2
transform(
// prettier-ignore
(pointTransformer: (Point => Point))
);
// Input
foo/*::<bar>*/(baz);
class Foo {
bar( data: Array<string>) {}
}
// Prettier 2.1
foo/*:: <bar> */(baz);
class Foo {
bar(data: Array/*:: <string> */) {}
}
// Prettier 2.2
foo/*:: <bar> */(baz);
class Foo {
bar(data: Array<string>) {}
}
// Input
@test-space-separated: #aaaaaa // Start with A
#bbbbbb // then some B
#cccccc; // and round it out with C
// Prettier 2.1
@test-space-separated: #aaaaaa a // Start with
#bbbbbb b // then some
#cccccc; // and round it out with C
// Prettier 2.2
@test-space-separated: #aaaaaa // Start with A
#bbbbbb // then some B
#cccccc; // and round it out with C
Node.sourceSpan (#9368 by @fisker)<!-- Input -->
<strong>a</strong>-<strong>b</strong>-
<!-- Prettier 2.1 -->
TypeError: Cannot read property 'line' of undefined
at forceNextEmptyLine ...
<!-- Prettier 2.2 -->
<strong>a</strong>-<strong>b</strong>-
v-for (#9225 by @zweimach)<!-- Input -->
<template>
<div
v-for="({ longLongProp=42, anotherLongLongProp='Hello, World!' }, index) of longLongLongLongLongLongLongLongList"
></div>
<div
v-for="({firstValue, secondValue, thirdValue, fourthValue, fifthValue, sixthValue}, objectKey, index) in objectWithAVeryVeryVeryVeryLongName"
></div>
</template>
<!-- Prettier 2.1 -->
<template>
<div
v-for="({ longLongProp = 42, anotherLongLongProp = 'Hello, World!' },
index) of longLongLongLongLongLongLongLongList"
></div>
<div
v-for="({
firstValue,
secondValue,
thirdValue,
fourthValue,
fifthValue,
sixthValue,
},
objectKey,
index) in objectWithAVeryVeryVeryVeryLongName"
></div>
</template>
<!-- Prettier 2.2 -->
<template>
<div
v-for="(
{ longLongProp = 42, anotherLongLongProp = 'Hello, World!' }, index
) of longLongLongLongLongLongLongLongList"
></div>
<div
v-for="(
{
firstValue,
secondValue,
thirdValue,
fourthValue,
fifthValue,
sixthValue,
},
objectKey,
index
) in objectWithAVeryVeryVeryVeryLongName"
></div>
</template>
script[setup] and style[vars] (#9609 by @fisker)<!-- Input -->
<script setup="props, {emit }"></script>
<style vars="{color }"></style>
<template>
<div>
<div v-slot="{destructuring:{ a:{b}}}"/>
<div v-slot:name="{destructuring:{ a:{b}}}"/>
<div #default="{destructuring:{ a:{b}}}"/>
<slot slot-scope="{destructuring:{ a:{b}}}"/>
</div>
</template>
<!-- Prettier 2.1 -->
<script setup="props, {emit }"></script>
<style vars="{color }"></style>
<template>
<div>
<div v-slot="{ destructuring: { a: { b } } }" />
<div v-slot:name="{ destructuring: { a: { b } } }" />
<div #default="{ destructuring: { a: { b } } }" />
<slot
slot-scope="{
destructuring: {
a: { b },
},
}"
/>
</div>
</template>
<!-- Prettier 2.2 -->
<script setup="props, { emit }"></script>
<style vars="{ color }"></style>
<template>
<div>
<div
v-slot="{
destructuring: {
a: { b },
},
}"
/>
<div
v-slot:name="{
destructuring: {
a: { b },
},
}"
/>
<div
#default="{
destructuring: {
a: { b },
},
}"
/>
<slot
slot-scope="{
destructuring: {
a: { b },
},
}"
/>
</div>
</template>
<Textarea /> (#9403 by @fisker, fixes in simple-html-tokenizer by @rwjblue)// Input
<Textarea />
{{#if true}}
Test
{{/if}}
// Prettier 2.1
<Textarea />
{{#if true}}
Test
{{/if}}
// Prettier 2.1 (second format)
<Textarea />
{{#if true}}
Test
{{/if}}
// Prettier 2.2
<Textarea />
{{#if true}}
Test
{{/if}}
<!-- Input -->
Paragraph with $14 million.
Paragraph with $14 million. But if more $dollars on the same line...
<!-- Prettier 2.1 -->
Paragraph with \$14 million.
Paragraph with $14 million. But if more $dollars on the same line...
<!-- Prettier 2.2 -->
Paragraph with $14 million.
Paragraph with $14 million. But if more $dollars on the same line...
require("prettier").format("```a\n\n\n\n", { parser: "markdown" });
<!-- Prettier 2.1 -->
'```a\n\n```\n'
<!-- Prettier 2.2 -->
'```a\n\n\n\n```\n'
[[wiki-style]] links (#9275 by @iamrecursion)[[wiki-style]] links ensures that they do not get broken by
the prettier formatting by being wrapped over multiple lines.[[]] brackets) are treated as raw
text. This is because the various tools that rely on the [[]] syntax do not
agree on what is allowable between them.<!-- Input -->
If I have a prose that forces a wiki link to end up crossing the [[line width limit]] like this. It's wrapped into an invalid state.
<!-- Prettier 2.1 -->
If I have a prose that forces a wiki link to end up crossing the [[line width
limit]] like this. It's wrapped into an invalid state.
<!-- Prettier 2.2 -->
If I have a prose that forces a wiki link to end up crossing the
[[line width limit]] like this. It's wrapped into an invalid state.
Since Prettier 1.12, code blocks starting like ```js {something=something} are detected as JavaScript ones and are therefore formatted.
Back in the day, not many tools used to separate the language from the metadata, so it was decided to make whitespace optional and thus detect ```js{something=something} as JavaScript too.
With the release of Remark v8 (which is used by Prettier), code block language detection and formatting became inconsistent in several rare edge cases. Besides, it was noticed that Prettier‘s formatting behaviour mismatched syntax highlighting in VSCode. To encourage consistency between different tools and to better align with the Commonmark spec, use of whitespace between the language name and the metadata was made compulsory.
<!-- prettier-ignore --><!-- Input -->
```js {something=something}
console.log ( "hello world" );
```
```js{something=something}
console.log ( "hello world" );
```
<!-- Prettier 2.1 -->
```js {something=something}
console.log("hello world");
```
```js{something=something}
console.log("hello world");
```
<!-- Prettier 2.2 -->
```js {something=something}
console.log("hello world");
```
```js{something=something}
console.log ( "hello world" );
```
<!-- Input -->
Test line 1
| Specify the selected option : | Option 1 |
| ----------------------------- | -------- |
Test line 6
<!-- Prettier 2.1 -->
Test line 1
| Specify the selected option : | Option 1 |
| ----------------------------- | -------- |
Test line 6
<!-- Prettier 2.2 -->
Test line 1
| Specify the selected option : | Option 1 |
| ----------------------------- | -------- |
Test line 6
<!-- Input -->
# title
<Jsx>
text
</Jsx>
<!-- Prettier 2.1 -->
# title
<Jsx>
text
</Jsx>
(Extra empty lines added after `<Jsx>` and `</Jsx>`)
<!-- Prettier 2.2 -->
# title
<Jsx>
text
</Jsx>
trailingComma option (#9665 by @fisker)When --trailing-comma=none, should not add trailing comma to flowMapping and flowSequence.
# Input
flow-mapping:
{
"object-does-not-fit-within-print-width": "------",
"TEST": "comma IS added here"
}
flow-sequence:
[
"object-does-not-fit-within-print-width", "------",
"TEST", "comma IS added here"
]
# Prettier 2.1
mapping:
{
"object-does-not-fit-within-print-width": "------",
"TEST": "comma IS added here",
}
flow-sequence:
[
"object-does-not-fit-within-print-width",
"------",
"TEST",
"comma IS added here",
]
# Prettier 2.2
flow-mapping:
{
"object-does-not-fit-within-print-width": "------",
"TEST": "comma IS added here"
}
flow-sequence:
[
"object-does-not-fit-within-print-width",
"------",
"TEST",
"comma IS added here"
]
flowMapping and flowSequence (#9669 by @fisker)# Input
a:
[
a, b,
# comment
]
b:
# prettier-ignore
{
a: 1, b: 2,
# comment
}
# Prettier 2.1
a: [a, b]
# comment
b:
# prettier-ignore
{
a: 1, b: 2,
# comment
}
# comment
# Prettier 2.1 (second format)
a:
[a, b]
# comment
b:
# prettier-ignore
{
a: 1, b: 2,
# comment
}
# comment
# comment
# Prettier 2.2
a: [
a,
b,
# comment
]
b:
# prettier-ignore
{
a: 1, b: 2,
# comment
}
json for .jsonl files (#9371 by @fisker)// Prettier 2.1
$ prettier --check .
Checking formatting...
[error] bad.jsonl: SyntaxError: Unexpected token (2:1)
[error] 1 | '{"type": "t/f", "head": "England", "relation": "invaded", "tail": "United States"}'
[error] > 2 | '{"type": "t/f", "head": "England", "relation": "attacked", "tail": "Baltimore"}'
[error] | ^
[error] 3 |
All matched files use Prettier code style!
// Prettier 2.2
$ prettier --check .
Checking formatting...
All matched files use Prettier code style!
Prettier did not flush line-suffix contents at the end of the document if there was no trailing newline. This fix forces all of those contents to be flushed even without trailing newlines.
pre-commit support has moved to https://github.com/pre-commit/mirrors-prettier, please update your .pre-commit-config.yaml file .
- - repo: https://github.com/prettier/prettier
+ - repo: https://github.com/pre-commit/mirrors-prettier
- rev: "2.2.0"
+ rev: "v2.2.0"
hooks:
- id: prettier
$ cat 1/index.js
hello('world')
// Prettier 2.1
$ prettier 1
[error] The "path" argument must be of type string. Received type number (1)
// Prettier 2.2
$ prettier 1
hello("world");