Prettier 2.1: new --embedded-language-formatting option and new JavaScript/TypeScript features!
This release adds a new --embedded-language-formatting
option, supports new JavaScript/TypeScript features, and includes many bug fixes and improvements!
Highlights
API
#7875 by @bakkot, #8825 by @fisker)
Add --embedded-language-formatting={auto,off} option (When Prettier identifies cases where it looks like you've placed some code it knows how to format within a string in another file, like in a tagged template in JavaScript with a tag named html
or in code blocks in Markdown, it will try to format that code by default.
Sometimes this behavior is undesirable, since it can change the behavior of your code. This option allows you to switch between the default behavior (auto
) and disabling this feature entirely (off
). It applies to all languages where Prettier recognizes embedded code, not just JavaScript.
// Input
html`
<p>
I am expecting this to come out exactly like it went in.
`;
// using --embedded-language-formatting=auto (or omitting this option)
html`
<p>
I am expecting this to come out exactly like it went in.
</p>
`;
// using --embedded-language-formatting=off
html`
<p>
I am expecting this to come out exactly like it went in.
`;
TypeScript
Support for TypeScript 4.0
#8885 by @fisker, #8982 by @sosukesuzuki)
Labeled Tuple Elements (// Input
type Range = [start: number, end: number];
// Prettier 2.0
SyntaxError: Unexpected token, expected "," (1:20)
> 1 | type Range = [start: number, end: number];
// Prettier 2.1
type Range = [start: number, end: number];
#8982 by @sosukesuzuki)
Short-Circuiting Assignment Operators (// Input
a ||= b;
// Prettier 2.0
SyntaxError: Expression expected. (1:5)
> 1 | a ||= b;
// Prettier 2.1
a ||= b;
#8805 by @fisker)
Type annotations on catch clauses (// Input
try {} catch (e: any) {}
// Prettier 2.0
try {
} catch (e) {}
// Prettier 2.1
try {
} catch (e: any) {}
Other changes
JavaScript
#6319 by @sosukesuzuki, @thorn0, #7979 by @sosukesuzuki)
Support the F# and Smart pipeline operator proposals (- F# Pipeline Operator proposal
- Smart Pipelines proposal
- Babel Blog: What's Happening With the Pipeline (
|>
) Proposal?
F#-style Pipeline:
// Input
promises |> await;
// Output (Prettier 2.0)
SyntaxError: Unexpected token (1:18)
> 1 | promises |> await;
| ^
// Output (Prettier 2.1)
promises |> await;
Smart Pipeline:
// Input
5 |> # * 2
// Output (Prettier 2.0)
SyntaxError: Unexpected character '#' (1:6)
> 1 | 5 |> # * 2
| ^
// Output (Prettier 2.1)
5 |> # * 2
#8069 by @shisama)
Fix end-of-line comments if followed by trailing whitespace (If a comments line had trailing whitespaces, comments were not detected as end-of-line.
// Input
var a = { /* extra whitespace --> */
b };
var a = { /* no whitespace --> */
b };
// Prettier 2.0
var a = {
/* extra whitespace --> */
b,
};
var a = {
/* no whitespace --> */ b,
};
// Prettier 2.1
var a = {
/* extra whitespace --> */ b,
};
var a = {
/* no whitespace --> */ b,
};
#8097 by @thecodrr)
Fix inconsistent parsing of injected expressions in styled-components template literals (// Input
const SingleConcat = styled.div`
${something()}
& > ${Child}:not(:first-child) {
margin-left:5px;
}
`
const MultiConcats = styled.div`
${something()}
& > ${Child}${Child2}:not(:first-child) {
margin-left:5px;
}
`
const SeparatedConcats = styled.div`
font-family: "${a}", "${b}";
`
// Prettier 2.0 -- same as input
// Prettier 2.1
const SingleConcat = styled.div`
${something()}
& > ${Child}:not(:first-child) {
margin-left: 5px;
}
`;
const MultiConcats = styled.div`
${something()}
& > ${Child}${Child2}:not(:first-child) {
margin-left: 5px;
}
`;
const SeparatedConcats = styled.div`
font-family: "${a}", "${b}";
`;
#8111 by @fisker)
Fix object trailing commas that last property is ignored (// Input
const foo = {
// prettier-ignore
bar: "baz"
}
// Prettier 2.0
const foo = {
// prettier-ignore
bar: "baz"
};
// Prettier 2.1
const foo = {
// prettier-ignore
bar: "baz",
};
#8160 by @fisker)
Keep object key with escape sequence as it is (// Input
const a = {
"\u2139": 'why "\\u2139" converted to "i"?',
};
// Prettier 2.0
const a = {
ℹ: 'why "\\u2139" converted to "i"?',
};
// Prettier 2.1
const a = {
"\u2139": 'why "\\u2139" is converted to "i"?',
};
#8255 by @thorn0)
Fix extra space after minus in CSS-in-JS (// Input
css`
color: var(--global--color--${props.color});
`
// Prettier 2.0
css`
color: var(--global--color-- ${props.color});
`;
// Prettier 2.1
css`
color: var(--global--color--${props.color});
`;
extends
part of class declarations/expressions (#8312 by @thorn0)
Fix comments in the // Input
class a extends a // comment
{
constructor() {}
}
// Prettier 2.0
class a extends a // comment {
constructor() {}
}
// Prettier 2.1
class a extends a { // comment
constructor() {}
}
test.each
template strings (#8354 by @yogmel)
Don't wrap arrays in Jest // Input
test.each`
a | b | c
${1} | ${[{ start: 1, end: 3 },{ start: 15, end: 20 },]} | ${[]}
`("example test", ({a, b, c}) => {})
// Prettier 2.0
test.each`
a | b | c
${1} | ${[
{ start: 1, end: 3 },
{ start: 15, end: 20 }
]} | ${[]}
`("example test", ({ a, b, c }) => {});
// Prettier 2.1
test.each`
a | b | c
${1} | ${[{ start: 1, end: 3 }, { start: 15, end: 20 }]} | ${[]}
`("example test", ({ a, b, c }) => {});
insertPragma
and requirePragma
in files with shebang (#8376 by @fisker)
Support // `--insert-pragma`
// Input
#!/usr/bin/env node
hello
.world();
// Prettier 2.0
SyntaxError: Unexpected token (3:1)
1 | /** @format */
2 |
> 3 | #!/usr/bin/env node
| ^
4 | hello
5 | .world();
// Prettier 2.1
#!/usr/bin/env node
/** @format */
hello.world();
// `--require-pragma`
// Input
#!/usr/bin/env node
/**
* @format
*/
hello
.world();
// Prettier 2.0
#!/usr/bin/env node
/**
* @format
*/
hello
.world();
// Prettier 2.1
#!/usr/bin/env node
/**
* @format
*/
hello.world();
#8410 by @thorn0)
Fix range formatting indentation (> echo -e "export default class Foo{\n/**/\n}" | prettier --range-start 16 --range-end 31 --parser babel
// Prettier 2.0
export default class Foo {
/**/
}
// Prettier 2.1
export default class Foo {
/**/
}
#8419 by @thorn0)
Improve detection of source elements for range formatting (Not all statement types were detected (read here how range formatting works in Prettier).
// Input
for (const element of list) { /* ... */ }
// ^^^^^^^^^^^^^^^^^^^^^^ ← range
// Prettier 2.0
for (const element of list) { /* ... */ }
// Prettier 2.1
for (const element of list) {
/* ... */
}
in
(#8431 by @sosukesuzuki)
Support Private Fields in Support Stage-2 proposal Private Fields in in
.
// Input
#prop in obj;
// Prettier 2.0
SyntaxError: Unexpected token (1:1)
> 1 | #prop in obj;
| ^
2 |
// Prettier 2.1
#prop in obj;
#8436 by @fisker)
Support ES Module Attributes and JSON modules (Support Stage-2 proposal ES Module Attributes and JSON modules.
// Input
import foo from "foo.json" with type: "json";
// Prettier 2.0
SyntaxError: Unexpected token, expected ";" (1:28)
> 1 | import foo from "foo.json" with type: "json";
| ^
// Prettier 2.1
import foo from "foo.json" with type: "json";
#8453 by @fisker)
Support record and tuple syntax (Support Stage-2 proposal JavaScript Records & Tuples Proposal.
Only support #[]
/#{}
syntax, not {| |}
/ [| |]
.
Tuples
// Input
#[1, 2, 3]
// Prettier 2.0
SyntaxError: Unexpected token (1:1)
> 1 | #[1, 2, 3]
| ^
// Prettier 2.1
#[1, 2, 3];
Records
// Input
#{
a: 1,
b: 2,
c: 3,
}
// Prettier 2.0
SyntaxError: Unexpected token (1:1)
> 1 | #{
| ^
2 | a: 1,
3 | b: 2,
4 | c: 3,
// Prettier 2.1
#{
a: 1,
b: 2,
c: 3,
};
#8461 by @sosukesuzuki)
Wrap jsx element on the left of "<" with parentheses (// Input
(<div/>) < 5;
// Prettier 2.0
<div/> < 5;
// Prettier 2.0 second outout
SyntaxError: Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>? (1:9)
> 1 | <div /> < 5;
| ^
2 |
// Prettier 2.1
(<div />) < 5;
#8476 by @sosukesuzuki)
Fix indentation for binary expressions with trailing comments (// Input
a +
a + // comment
a;
// Prettier 2.0
a +
a + // comment
a;
// Prettier 2.1
a +
a + // comment
a;
#8491 by @thorn0)
Fix unstable comments in binary expressions (// Input
Math.min(
(
/* foo */
document.body.scrollHeight -
(window.scrollY + window.innerHeight)
) - devsite_footer_height,
0,
)
// Prettier 2.0 (first output)
Math.min(
/* foo */
document.body.scrollHeight -
(window.scrollY + window.innerHeight) -
devsite_footer_height,
0
);
// Prettier 2.0 (second output)
Math.min(
/* foo */
document.body.scrollHeight -
(window.scrollY + window.innerHeight) -
devsite_footer_height,
0
);
// Prettier 2.1 (first and second outputs)
Math.min(
/* foo */
document.body.scrollHeight -
(window.scrollY + window.innerHeight) -
devsite_footer_height,
0
);
// Input
const topOfDescriptionBox =
Layout.window.width + // Images are 1:1 aspect ratio, full screen width
Layout.headerHeight;
// Prettier 2.0 (first output)
const topOfDescriptionBox =
Layout.window.width + Layout.headerHeight; // Images are 1:1 aspect ratio, full screen width
// Prettier 2.0 (second output)
const topOfDescriptionBox = Layout.window.width + Layout.headerHeight; // Images are 1:1 aspect ratio, full screen width
// Prettier 2.1 (first and second outputs)
const topOfDescriptionBox =
Layout.window.width + // Images are 1:1 aspect ratio, full screen width
Layout.headerHeight;
#8508 by @lydell)
Quote and unquote number keys (Prettier removes quotes from object keys if they are identifiers. Now, Prettier also removes quotes from object keys that are numbers.
If you use quoteProps: "consistent"
, Prettier can also add quotes to number keys so that all properties end up with quotes.
// Input
x = {
"a": null,
"1": null,
};
// Prettier 2.0
x = {
a: null,
"1": null,
};
// Prettier 2.1
x = {
a: null,
1: null,
};
Prettier only touches “simple” numbers such as 1
and 123.5
. It won’t make the following transformations, as they feel unexpected:
1e2 -> "100"
0b10 -> "10"
1_000 -> "1000"
1.0 -> "1"
0.99999999999999999 -> "1"
999999999999999999999 -> "1e+21"
2n -> "2"
"1e+100" -> 1e100
(Please don’t use confusing numbers as object keys!)
Note that Prettier only unquotes numbers using the "babel"
parser. It’s not completely safe to do so in TypeScript.
#8557 by @sosukesuzuki)
Prefer leading comment when there is a comment on after "?" in conditional types (// Input
type A = B extends T
? // comment
foo
: bar;
// Prettier 2.0
type A = B extends T // comment
? foo
: bar;
// Prettier 2.1
type A = B extends T
? // comment
foo
: bar;
#8592 by @sosukesuzuki)
Break ternary expressions that include a multiline block comment (// Input
test
? /* comment
comment
*/
foo
: bar;
// Prettier 2.0
test ? /* comment
comment
*/ foo : bar;
// Prettier 2.1
test
? /* comment
comment
*/
foo
: bar;
#8731 by @fisker)
Fix unstable pair of comments between class methods (// Input
class C {
ma() {} /* D */ /* E */
mb() {}
}
// Prettier 2.0
class C {
ma() {} /* E */ /* D */
mb() {}
}
// Prettier 2.0 (Second format)
class C {
ma() {} /* D */ /* E */
mb() {}
}
// Prettier 2.1
class C {
ma() {} /* D */ /* E */
mb() {}
}
prettier-ignore
comments (#8742 by @fisker)
Fix duplicated // Input
a = <div {.../* prettier-ignore */{}}/>
a = <div {...{}/* prettier-ignore */}/>
// Prettier 2.0
a = <div {/* prettier-ignore */ .../* prettier-ignore */ {}} />;
a = <div {...{} /* prettier-ignore */ /* prettier-ignore */} />;
// Prettier 2.1
a = <div {.../* prettier-ignore */ {}} />;
a = <div {...{} /* prettier-ignore */} />;
#8901 by @fisker)
Support Decimal Proposal (Support Stage-1 proposal Decimal Proposal.
// Input
0.3m;
// Prettier 2.0
SyntaxError: Identifier directly after number (1:4)
> 1 | 0.3m;
// Prettier 2.1
0.3m;
#9011 by @fisker)
Add parens when yielding jsx (In v2.0.0
we removed the parens when yielding jsx, this works for most parsers, but ESLint throws when parsing it, related issue.
// Input
function* f() {
yield <div>generator</div>
}
// Prettier 2.0
function* f() {
yield <div>generator</div>
}
// Prettier 2.1
function* f() {
yield (<div>generator</div>);
}
TypeScript
babel-ts
parser so that it emits a proper syntax error for (a:b)
(#8046 by @thorn0)
Fix the Previously, such code was parsed without errors, but an error was thrown in the printer, and this error was printed in an unfriendly way, with a stack trace. Now a proper syntax error is thrown by the parser.
// Input
(a:b)
// Prettier 2.0
[error] test.ts: Error: unknown type: "TSTypeCastExpression"
[error] ... [a long stack trace here] ...
// Prettier 2.1
[error] test.ts: SyntaxError: Did not expect a type annotation here. (1:2)
[error] > 1 | (a:b)
[error] | ^
[error] 2 |
#8422 by @thorn0)
Parenthesize string literals to avoid interpreting as directives (Prettier wraps any string literal which is in statement position in parentheses because otherwise such strings would get interpreted as directives if they occurred at the top of a function or program, which can change the behavior of the program. It is not technically necessary to do this for strings which are not on the first line of a function or program. But doing so anyway is more consistent and can highlight bugs. See for example this thread on twitter.
Previously this didn't consistently work for the typescript
parser. Only strings already wrapped in parentheses retained them.
// Input
f();
'use foo';
('use bar');
// Prettier 2.0
f();
"use foo";
("use bar");
// Prettier 2.1
f();
("use foo");
("use bar");
#8450 by @sosukesuzuki)
Support TypeScript 3.9 breaking change for Optional Chaining and Non-Null Assertions (See https://devblogs.microsoft.com/typescript/announcing-typescript-3-9/#breaking-changes
// Input
(a?.b)!.c;
// Prettier 2.0
a?.b!.c;
// Prettier 2.1
(a?.b)!.c;
Flow
#8365 by @fisker)
Fix function type param contains nullable param (// Input
let f: <A>(
((?A) => B),
) => B;
// Prettier 2.0
let f: <A>((?A) => B) => B;
// Prettier 2.0 (Second format)
SyntaxError: Unexpected token (1:12)
> 1 | let f: <A>((?A) => B) => B;
// Prettier 2.1
let f: <A>(((?A) => B)) => B;
#8768 by @gkz)
Fix export default of Flow Enum (Do not add a trailing semicolon if default exporting a Flow Enum.
// Input
export default enum B {}
// Prettier 2.0
export default enum B {};
// Prettier 2.1
export default enum B {}
CSS
#7009 by @evilebottnawi)
Do not break code with a comment at the end of an at-rule (/* Input */
@at-root .foo
// .bar
{
}
/* Prettier 2.0 */
@at-root .foo
// .bar {
}
/* Prettier 2.1 */
@at-root .foo
// .bar
{
}
#7592 by @mattiacci)
Fix url() unquoted content manipulation (Improve the handling of unquoted URL content in CSS/SCSS/Less. This doesn't address the underlying parsing issues, but at least ensures Prettier doesn't modify URLs.
/* Input */
@import url(https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900&display=swap);
@import url(//fonts.googleapis.com/css?family=#{ get-font-family('Roboto') }:100,300,500,700,900&display=swap);
.validUnquotedUrls{
background: url(data/+0ThisShouldNotBeLowerCased);
background: url(https://foo/A*3I8oSY6AKRMAAAAAAAAAAABkARQnAQ);
background: url(https://example.com/some/quite,long,url,with,commas.jpg);
}
/* Prettier 2.0 */
@import url(
https://fonts.googleapis.com/css?family=Roboto:100,
300,
400,
500,
700,
900&display=swap
);
@import url(
//fonts.googleapis.com/css?family=#{get-font-family("Roboto")}:100,
300,
500,
700,
900&display=swap
);
.validUnquotedUrls {
background: url(data/+0thisshouldnotbelowercased);
background: url(https://foo/A*3i8osy6akrmaaaaaaaaaaabkarqnaq);
background: url(https://example.com/some/quite, long, url, with, commas.jpg);
}
/* Prettier 2.1 */
@import url(https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900&display=swap);
@import url(//fonts.googleapis.com/css?family=#{ get-font-family('Roboto') }:100,300,500,700,900&display=swap);
.validUnquotedUrls{
background: url(data/+0ThisShouldNotBeLowerCased);
background: url(https://foo/A*3I8oSY6AKRMAAAAAAAAAAABkARQnAQ);
background: url(https://example.com/some/quite,long,url,with,commas.jpg);
}
#8535 by @boyenn)
Incorrect whitespace added after escaped colon in css grid line name (/* Input */
.grid {
grid-template-rows:
[row-1-00\:00] auto;
}
/* Prettier 2.0 */
.grid {
grid-template-rows: [row-1-00\: 00] auto;
}
/* Prettier 2.1 */
.grid {
grid-template-rows: [row-1-00\:00] auto;
}
#8545 by @boyenn)
Add support for @supports selector(<custom-selector>) (/* Input */
@supports selector(:focus-visible) {
button:focus {
outline: none;
}
button:focus-visible {
outline: 2px solid orange;
}
}
/* Prettier 2.0 */
@supports selector(: focus-visible) {
button:focus {
outline: none;
}
button:focus-visible {
outline: 2px solid orange;
}
}
/* Prettier 2.1 */
@supports selector(:focus-visible) {
button:focus {
outline: none;
}
button:focus-visible {
outline: 2px solid orange;
}
}
#8567, #8566 by @boyenn)
Improve Prettier handling of arbitrary arguments (Prettier no longer unexpectedly add extra space after function when passing arbitrary arguments. Prettier no longer breaks code when inline number lists are used as arbitrary arguments.
/* Input */
body {
test: function($list...);
foo: bar(returns-list($list)...);
background-color: rgba(50 50 50 50...);
}
/* Prettier 2.0 */
body {
test: function($list...);
foo: bar(returns-list($list) ...);
background-color: rgba(50 50 50 50..);
}
/* Prettier 2.1 */
body {
test: function($list...);
foo: bar(returns-list($list)...);
background-color: rgba(50 50 50 50...);
}
SCSS
#7844 by @boyenn)
Fix extra indentation of lines following comments in scss (Previously, Prettier would place extra indentation of lines following comments within SCSS maps Prettier now no longer places these indentations
/* Input */
$my-map: (
'foo': 1, // Foo
'bar': 2, // Bar
);
/* Prettier 2.0 */
$my-map: (
"foo": 1,
// Foo
"bar": 2,
// Bar
);
/* Prettier 2.1 */
$my-map: (
"foo": 1,
// Foo
"bar": 2,
// Bar
);
#8366 by @fisker)
Fix inline comments between property and value (// Input
a {
color: // comment
red;
}
// Prettier 2.0
a {
color: // comment red;
}
// Prettier 2.1
a {
color: // comment
red;
}
#8675 by @fisker)
Comments at the end of the file were lost if the final semicolon was omitted (// Input
@mixin foo() {
a {
color: #f99;
}
}
@include foo() /* comment*/
// Prettier 2.0
@mixin foo() {
a {
color: #f99;
}
}
@include foo();
// Prettier 2.1
@mixin foo() {
a {
color: #f99;
}
}
@include foo(); /* comment*/
Less
:extend
pseudo-class (#8178 by @fisker)
Fix The selector is parsed as value before, now it's recognized as selector.
// Input
.hello {
&:extend(.input[type="checkbox"]:checked ~ label)}
// Prettier 2.0
.hello {
&:extend(.input[type= "checkbox" ]: checked ~label);
}
// Prettier 2.1
.hello {
&:extend(.input[type="checkbox"]:checked ~ label);
}
/*
(#8360 by @fisker)
Fix inline comments contains When inline comments contains /*
, some other comment not correctly printed.
// Input
@import "a";
// '/*' <-- this breaks formatting
@import 'b';
/* block */
/*no-space block*/
// Prettier 2.0
@import "a";
// '/*' <-- this breaks formatting
@import "b";
@import 'b
@import 'b';
/* bl
// Prettier 2.1
@import "a";
// '/*' <-- this breaks formatting
@import "b";
/* block */
/*no-space block*/
HTML
#8013 by @bschlenk)
Omit trailing semicolon on single line style attributes (<!-- Input -->
<div style="margin: 0; padding: 20px"></div>
<div style="margin: 0; padding: 20px; position: relative; display: inline-block; color: blue"></div>
<!-- Prettier 2.0 -->
<div style="margin: 0; padding: 20px;"></div>
<div
style="
margin: 0;
padding: 20px;
position: relative;
display: inline-block;
color: blue;
"
></div>
<!-- Prettier 2.1 -->
<div style="margin: 0; padding: 20px"></div>
<div
style="
margin: 0;
padding: 20px;
position: relative;
display: inline-block;
color: blue;
"
></div>
#8137 by @fisker)
Preserve non-ASCII whitespace characters in HTML (Non-ASCII whitespace characters like U+00A0
U+2005
etc. are not considered whitespace in html, they should not be removed.
// Prettier 2.0
[...require("prettier").format("<i> \u2005 </i>", { parser: "html" })]
.slice(3, -5)
.map((c) => c.charCodeAt(0).toString(16));
// -> [ '20' ]
// `U+2005` is removed
// Prettier 2.1
[...require("prettier").format("<i> \u2005 </i>", { parser: "html" })]
.slice(3, -5)
.map((c) => c.charCodeAt(0).toString(16));
// -> [ '20', '2005', '20' ]
#8173 by @fisker, #8394 by @fisker)
Support legacy HTML-like comments script blocks (Previously we parse html <script>
blocks as "module"(ECMAScript Module grammar), this is why we can't parse comments starts with <!--
(aka HTML-like comments), now we parse <script>
blocks as "script", unless this <script>
type="module"
type="text/babel"
anddata-type="module"
, introduced in babel@v7.10.0
<!-- Input -->
<SCRIPT>
<!--
alert("hello" + ' world!')
//--></SCRIPT>
<!-- Prettier 2.0 -->
SyntaxError: Unexpected token (2:1)
1 |
> 2 | <!--
| ^
3 | alert("hello" + ' world!')
4 | //-->
<!-- Prettier 2.1 -->
<script>
<!--
alert("hello" + " world!");
//-->
</script>
<select>
as inline-block and <optgroup>
/<option>
as block (#8275 by @thorn0, #8620 by @fisker)
Treat Now Prettier knows that it's safe to add whitespace inside select
, option
and optgroup
tags.
<!-- Input -->
<select><option>Blue</option><option>Green</option><optgroup label="Darker"><option>Dark Blue</option><option>Dark Green</option></optgroup></select>
<!-- Prettier 2.0 -->
<select
><option>Blue</option
><option>Green</option
><optgroup label="Darker"
><option>Dark Blue</option><option>Dark Green</option></optgroup
></select
>
<!-- Prettier 2.1 -->
<select>
<option>Blue</option>
<option>Green</option>
<optgroup label="Darker">
<option>Dark Blue</option>
<option>Dark Green</option>
</optgroup>
</select>
#8359 by @fisker)
Fix broken URLs with commas in srcset (<!-- Input -->
<img
srcset="
_20200401_145009_szrhju_c_scale,w_200.jpg 200w,
_20200401_145009_szrhju_c_scale,w_1400.jpg 1400w"
src="_20200401_145009_szrhju_c_scale,w_1400.jpg"
>
<!-- Prettier 2.0 -->
<img
srcset="
_20200401_145009_szrhju_c_scale,
w_200.jpg 200w,
_20200401_145009_szrhju_c_scale,
w_1400.jpg 1400w
"
src="_20200401_145009_szrhju_c_scale,w_1400.jpg"
/>
<!-- Prettier 2.1 -->
<img
srcset="
_20200401_145009_szrhju_c_scale,w_200.jpg 200w,
_20200401_145009_szrhju_c_scale,w_1400.jpg 1400w
"
src="_20200401_145009_szrhju_c_scale,w_1400.jpg"
/>
<script type="text/html>
(#8371 by @sosukesuzuki)
Support <!-- Input -->
<script type="text/html">
<div>
<p>foo</p>
</div>
</script>
<!-- Prettier 2.0 -->
<script type="text/html">
<div>
<p>foo</p>
</div>
</script>
<!-- Prettier 2.1 -->
<script type="text/html">
<div>
<p>foo</p>
</div>
</script>
#8381 by @fisker)
Support front matter with dynamic language (Support dynamic language detection in front matter, also available for css
, less
, scss
, and markdown
parser.
<!-- Input -->
---my-awsome-language
title: Title
description: Description
---
<h1>
prettier</h1>
<!-- Prettier 2.0 -->
---my-awsome-language title: Title description: Description ---
<h1>
prettier
</h1>
<!-- Prettier 2.1 -->
---my-awsome-language
title: Title
description: Description
---
<h1>
prettier
</h1>
#8614 by @fisker)
Don't preserve line breaks around text-only content (Previously, Prettier always preserved line breaks around inline nodes (i.e. inline elements, text, interpolations). In general, Prettier, as much as possible, tries to avoid relying on original formatting, but there are at least two cases when collapsing inline nodes into a single line is undesirable, namely list-like content and conditional constructions (e.g. v-if
/v-else
in Vue). A good way to detect those cases couldn't be found, so such a trade-off was made. It turned out, however, for text-only content, this relaxation of rules was unnecessary and only led to confusingly inconsistent formatting.
<!-- Input -->
<div>
Hello, world!
</div>
<div>
Hello, {{ username }}!
</div>
<!-- Prettier 2.0 -->
<div>
Hello, world!
</div>
<div>Hello, {{ username }}!</div>
<!-- Prettier 2.1 -->
<div>Hello, world!</div>
<div>Hello, {{ username }}!</div>
#8621 by @fisker)
Recognize known html tags (<!-- Input -->
<div>before<details><summary>summary long long long long </summary>details</details>after</div>
<div>before<dialog open>dialog long long long long long long long long </dialog>after</div>
<div>before<object data="horse.wav"><param name="autoplay" value="true"/><param name="autoplay" value="true"/></object>after</div>
<!-- Prettier 2.0 -->
<div>
before<details><summary>summary long long long long </summary>details</details
>after
</div>
<div>
before<dialog open>dialog long long long long long long long long </dialog
>after
</div>
<div>
before<object data="horse.wav"
><param name="autoplay" value="true" /><param
name="autoplay"
value="true" /></object
>after
</div>
<!-- Prettier 2.1 -->
<div>
before
<details>
<summary>summary long long long long</summary>
details
</details>
after
</div>
<div>
before
<dialog open>dialog long long long long long long long long</dialog>
after
</div>
<div>
before<object data="horse.wav">
<param name="autoplay" value="true" />
<param name="autoplay" value="true" /></object
>after
</div>
#8643 by @ikatyang)
Fix formatting element with void element as its last child (<!-- Input -->
<video controls width="250">
<source src="/media/examples/flower.webm"
type="video/webm">
<source src="/media/examples/flower.mp4"
type="video/mp4"
></video>text after
<!-- Prettier 2.0 -->
<video controls width="250">
<source src="/media/examples/flower.webm" type="video/webm" />
<source src="/media/examples/flower.mp4" type="video/mp4" /></video
>text after
<!-- Prettier 2.1 -->
<video controls width="250">
<source src="/media/examples/flower.webm" type="video/webm" />
<source src="/media/examples/flower.mp4" type="video/mp4" /></video
>text after
Vue
#8023 by @sosukesuzuki, #8465 by @fisker)
Improve formatting Vue SFC root blocks (Support formatting all language blocks(including custom blocks with lang
attribute) with builtin parsers and plugins.
<!-- Input -->
<template lang="pug">
div.text( color = "primary", disabled ="true" )
</template>
<i18n lang="json">
{
"hello": 'prettier',}
</i18n>
<!-- Prettier 2.0 -->
<template lang="pug">
div.text( color = "primary", disabled ="true" )
</template>
<i18n lang="json">
{
"hello": 'prettier',}
</i18n>
<!-- Prettier 2.1 -->
<template lang="pug">
.text(color="primary", disabled="true")
</template>
<i18n lang="json">
{
"hello": "prettier"
}
</i18n>
@prettier/plugin-pug is required for this example.
#8153 by @sosukesuzuki)
Improve parsing for custom blocks (<!-- Input -->
<custom lang="javascript">
const foo = "</";
</custom>
<!-- Prettier 2.0 -->
SyntaxError: Unexpected character """ (2:19)
[error] 1 | <custom lang="javascript">
[error] > 2 | const foo = "</";
[error] | ^
[error] 3 | </custom>
<!-- Prettier 2.1 -->
<custom lang="javascript">
const foo = "</";
</custom>
#8280 by @fisker)
Fix broken format with upper case HTML tag (<!-- Input -->
<!doctype html><HTML></HTML>
<!-- Prettier 2.0 -->
<!DOCTYPE html>><HTML></HTML>
<!-- Prettier 2.1 -->
<!DOCTYPE html><HTML></HTML>
template
in Vue SFC (#8325 by @sosukesuzuki)
Fix ugly formatting for one line <!-- Input -->
<template><p>foo</p><div>foo</div></template>
<!-- Prettier 2.0 -->
<template
><p>foo</p>
<div>foo</div></template
>
<!-- Prettier 2.1 -->
<template>
<p>foo</p>
<div>foo</div>
</template>
#8326 by @sosukesuzuki)
Support Vue DOM Template (When use vue parse for HTML, parse template as HTML.
<!-- Input -->
<!DOCTYPE html>
<html>
<body STYLE="color: #333">
<DIV id="app">
<DIV>First Line</DIV><DIV>Second Line</DIV>
</DIV>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
new Vue({
el: "#app",
data() {
return {}
},
});
</script>
</body>
</html>
<!-- Prettier 2.0 -->
<!DOCTYPE html>
<html>
<body STYLE="color: #333">
<DIV id="app"> <DIV>First Line</DIV><DIV>Second Line</DIV> </DIV>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
new Vue({
el: "#app",
data() {
return {};
},
});
</script>
</body>
</html>
<!-- Prettier 2.1 -->
<!DOCTYPE html>
<html>
<body style="color: #333">
<div id="app">
<div>First Line</div>
<div>Second Line</div>
</div>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
new Vue({
el: "#app",
data() {
return {};
},
});
</script>
</body>
</html>
#8337 by @sosukesuzuki)
Improve upper case HTML tag formatting in DOM template (<!-- Input -->
<!DOCTYPE html><HTML>
<body>
<div v-if="foo === 'foo'">
</div>
<script>
new Vue({el: '#app'})
</script>
</body>
</HTML>
<!-- Prettier 2.0 -->
<!DOCTYPE html>
<HTML>
<body>
<div v-if="foo === 'foo'">
</div>
<script>
new Vue({el: '#app'})
</script>
</body>
</HTML>
<!-- Prettier 2.1 -->
<!DOCTYPE html>
<HTML>
<body>
<div v-if="foo === 'foo'"></div>
<script>
new Vue({ el: "#app" });
</script>
</body>
</HTML>
#8747 by @fisker)
Fix parenthesized interpolation format (<!-- Input -->
<template>
<span>{{(a|| b)}} {{z&&(a&&b)}}</span>
</template>
<!-- Prettier 2.0 -->
<template>
<span>{{(a|| b)}} {{z&&(a&&b)}}</span>
</template>
<!-- Prettier 2.1 -->
<template>
<span>{{ a || b }} {{ z && a && b }}</span>
</template>
#8839 by @wenfangdu)
Fix named slots shorthand value is not formatted (<!-- Input -->
<template>
<div #default="{foo:{bar:{baz}}}"></div>
</template>
<!-- Prettier 2.0 -->
<template>
<div #default="{foo:{bar:{baz}}}"></div>
</template>
<!-- Prettier 2.1 -->
<template>
<div #default="{ foo: { bar: { baz } } }"></div>
</template>
Angular
this
(#8253 by @thorn0, #7942 by @fisker, fixes in angular-estree-parser
by @ikatyang)
Fix optional chaining with computed properties and handling of <!-- Input -->
{{ a?.b[c] }}
{{ a ( this )}}
<!-- Prettier 2.0 -->
{{ (a?.b)[c] }}
{{ a ( this )}}
<!-- Prettier 2.1 -->
{{ a?.b[c] }}
{{ a(this) }}
#8254 by @thorn0)
Preserve parentheses around pipes in objects literals for compatibility with AngularJS 1.x (<!-- Input -->
<div ng-style="{ 'color': ('#222' | darken)}"></div>
<!-- Prettier 2.0 -->
<div ng-style="{ color: '#222' | darken }"></div>
<!-- Prettier 2.1 -->
<div ng-style="{ 'color': ('#222' | darken)}"></div>
Handlebars (alpha)
#8375 by @dcyriller)
Respect singleQuote option around attribute value more complex than a bare text ({{!-- Input --}}
<a href='/{{url}}'></a>
<a href="/{{url}}"></a>
<a href='url'></a>
<a href="url"></a>
{{!-- Prettier 2.0 --}}
<a href="/{{url}}"></a>
<a href="/{{url}}"></a>
<a href='url'></a>
<a href='url'></a>
{{!-- Prettier 2.1 --}}
<a href='/{{url}}'></a>
<a href='/{{url}}'></a>
<a href='url'></a>
<a href='url'></a>
#8593 by @mikoscz)
Fix formatting of classic components inside element ({{!-- Input --}}
<div>
{{classic-component-with-many-properties
class="hello"
param=this.someValue
secondParam=this.someValue
thirdParam=this.someValue
}}
</div>
{{!-- Prettier 2.0 --}}
<div>
{{
classic-component-with-many-properties
class="hello"
param=this.someValue
secondParam=this.someValue
thirdParam=this.someValue
}}
</div>
{{!-- Prettier 2.1 --}}
<div>
{{classic-component-with-many-properties
class="hello"
param=this.someValue
secondParam=this.someValue
thirdParam=this.someValue
}}
</div>
#8634 by @dcyriller)
Support escaping a mustache with a backslash ({{!-- Input --}}
\{{mustache}}
\\{{mustache}}
\\\{{mustache}}
{{!-- Prettier 2.0 --}}
{{mustache}}
\{{mustache}}
\\{{mustache}}
{{!-- Prettier 2.1 --}}
\{{mustache}}
\\{{mustache}}
\\\{{mustache}}
#8677 by @dcyriller)
Format only class names in attributes ({{!-- Input --}}
<div class=' class '></div>
<div title=' other attribute '></div>
{{!-- Prettier 2.0 --}}
<div class="class"></div>
<div title="other attribute"></div>
{{!-- Prettier 2.1 --}}
<div class="class"></div>
<div title=" other attribute "></div>
GraphQL
#7721 by @sasurau4)
Improve wrapping of GraphQL fragment directives (# Input
fragment TodoList_list on TodoList @argumentDefinitions(
count: {type: "Int", defaultValue: 10},
) {
title
}
# Prettier 2.0
fragment TodoList_list on TodoList
@argumentDefinitions(count: { type: "Int", defaultValue: 10 }) {
title
}
# Prettier 2.1
fragment TodoList_list on TodoList
@argumentDefinitions(count: { type: "Int", defaultValue: 10 }) {
title
}
#8006 by @fisker)
Fix comments between interfaces (# Input
type Type1 implements
A &
# comment 1
B
# comment 2
& C {a: a}
# Prettier 2.0
type Type1 implements A & # comment 1
B & # comment 2
C {
a: a
}
# Prettier 2.0 (Second format)
type Type1 implements A & B & C { # comment 1 # comment 2
a: a
}
# Prettier 2.1
type Type1 implements A &
# comment 1
B &
# comment 2
C {
a: a
}
#8007 by @fisker)
Allow interfaces to implement other interfaces (See "RFC: Allow interfaces to implement other interfaces"
# Input
interface Resource implements Node {
id: ID!
url: String
}
# Prettier 2.0
interface Resource {
id: ID!
url: String
}
# Prettier 2.1
interface Resource implements Node {
id: ID!
url: String
}
Markdown
remark-parse
to v8 (#8140 by @saramarcondes, @fisker, @thorn0)
Update remark, the Markdown parser that Prettier uses, got a long-overdue update (5.0.0 → 8.0.2, see remark's changelog). This fixed tons of old bugs, in particular related to parsing list items indented with tabs.
Please note that the new version is stricter in parsing footnotes, a syntax extension not defined in any specification. Previously, Prettier would parse (and output, depending on the --tab-width
option) multiline footnotes indented with any number of spaces. The new version recognizes only multiline footnotes indented with 4 spaces. This change isn't considered breaking as the syntax is non-standard, but if you happen to use it, before updating Prettier, you might want to use its older version with --tab-width=4
to make footnotes in your files compatible with the new version.
#8511 by @ne-sachirou)
Correctly format CJK sentences with Variation Selector (<!-- Input -->
麻󠄁羽󠄀‼️
<!-- Prettier 2.0 -->
麻 󠄁 羽 󠄀 ‼️
<!-- Prettier 2.1 -->
麻󠄁羽󠄀‼️
YAML
prettier-ignore
(#8355 by @fisker)
Fix unstable format with # Input
# prettier-ignore
---
prettier: true
...
hello: world
# Prettier 2.0
# prettier-ignore
---
prettier: true
---
hello: world
# Prettier 2.0 (Second format)
# prettier-ignore
---
prettier: true
---
hello: world
# Prettier 2.1
# prettier-ignore
---
prettier: true
---
hello: world
#8356 by @fisker)
Preserve blank lines in comments (# Input
a:
- a: a
# - b: b
# - c: c
- d: d
b:
- a: a
# - b: b
# - c: c
# Prettier 2.0
a:
- a: a
# - b: b
# - c: c
- d: d
b:
- a: a
# - b: b
# - c: c
# Prettier 2.1
a:
- a: a
# - b: b
# - c: c
- d: d
b:
- a: a
# - b: b
# - c: c
yaml
and yaml-unist-parser
(#8386 by @fisker, fixes in yaml-unist-parser
by @ikatyang)
Update yaml
: Add explicit error for block scalars with more-indented leading empty linesyaml-unist-parser
: fix: no false positive for document head end marker position
# Input
# --- comments ---
# Prettier 2.0
--- # --- comments ---
# Prettier 2.1
# --- comments ---
# Input
empty block scalar: >
# comment
# Prettier 2.0
empty block scalar: >
# comment
# Prettier 2.1
SyntaxError: Block scalars with more-indented leading empty lines must use an explicit indentation indicator (1:21)
> 1 | empty block scalar: >
| ^
> 2 |
| ^^
> 3 | # comment
| ^^^^^^^^^^^
#8888 by @fisker, @evilebottnawi, fixes in yaml-unist-parser
by @ikatyang)
Fix error on YAML Inline Extend syntax (# Input
foo:
<<: &anchor
K1: "One"
K2: "Two"
bar:
<<: *anchor
K3: "Three"
# Prettier 2.0
SyntaxError: Merge nodes can only have Alias nodes as values (2:2)
1 | foo:
> 2 | <<: &anchor
| ^^^^^^^^^^^
> 3 | K1: "One"
| ^^^^^^^^^^^^
> 4 | K2: "Two"
| ^^^^^^^^^^^^
> 5 |
| ^
6 | bar:
7 | <<: *anchor
8 | K3: "Three"
# Prettier 2.1
foo:
<<: &anchor
K1: "One"
K2: "Two"
bar:
<<: *anchor
K3: "Three"
API
parser
option (#8390 by @thorn0)
Add plugins' parsers to the When a plugin defines a language, the parsers specified for this language are now automatically added to the list of valid values of the parser
option.
This might be useful for editor integrations or other applications that need a list of available parsers.
npm install --save-dev --save-exact prettier @prettier/plugin-php
const hasPhpParser = prettier
.getSupportInfo()
.options.find((option) => option.name === "parser")
.choices.map((choice) => choice.value)
.includes("php"); // false in Prettier 2.0, true in Prettier 2.1
prettier.getFileInfo()
(#8548, #8551, #8585 by @fisker)
Fix - When passing
{resolveConfig: true}
, theinferredParser
should be the parser resolved from config file, previous version might returns wrong result for files supported by builtin parsers. - When passing
{resolveConfig: true}
and{ignorePath: "a/file/in/different/dir"}
, theinferredParser
result might incorrect. - If given
filePath
is ignored, theinferredParser
is alwaysnull
now.
$ echo {"parser":"flow"}>.prettierrc
$ node -p "require('prettier').getFileInfo.sync('./foo.js', {resolveConfig: true})"
# Prettier 2.0
# { ignored: false, inferredParser: 'babel' }
# Prettier 2.1
# { ignored: false, inferredParser: 'flow' }
$ echo ignored.js>>.prettierignore
$ node -p "require('prettier').getFileInfo.sync('./ignored.js')"
# Prettier 2.0
# { ignored: true, inferredParser: 'babel' }
# Prettier 2.1
# { ignored: true, inferredParser: null }
#8591 by @fisker)
Fix resolve editorConfig for files in deep directory (Previous version can't find .editorconfig
for files in deep directory (depth great than 9 to project root, see #5705).
.cjs
and .json5
configuration files (#8890, #8957 by @fisker)
Support Added new format of configuration files:
.prettierrc.json5
.prettierrc.cjs
prettier.config.cjs
#8936 by @fisker)
Fix wrong range format on files with BOM (When files have BOM, in previous version, the real range is wrongly calculated.
const text = "\uFEFF" + "foo = 1.0000;bar = 1.0000;";
// ^^^^^^^^^^^^^ Range
const result = require("prettier")
.format(text, {
parser: "babel",
rangeStart: 1,
rangeEnd: 13,
})
// Visualize BOM
.replace("\uFEFF", "<<BOM>>")
// Visualize EOL
.replace("\n", "<<EOL>>");
console.log(result);
// Prettier 2.0
// -> <<BOM>>foo = 1.0;<<EOL>>bar = 1.0;
// ^^^^^^^^^ This part should not be formatted
// Prettier 2.1
// -> <<BOM>>foo = 1.0;bar = 1.0000;
CLI
#8098 by @fisker)
Fix filenames contains CJK or emoji not correctly ignored (// Prettier 2.0
$ echo "dir" > .prettierignore
$ prettier **/*.js -l
dir/😁.js
dir/中文.js
not-ignored.js
// Prettier 2.1
$ echo "dir" > .prettierignore
$ prettier **/*.js -l
not-ignored.js
--file-info
respect the .prettierrc
and --no-config
(#8586, #8830 by @fisker)
$ echo {"parser":"ninja"}>.prettierrc
# Prettier 2.0
$ prettier --file-info file.js
# { "ignored": false, "inferredParser": "babel" }
$ prettier --file-info file.js --no-config
# { "ignored": false, "inferredParser": "babel" }
# Prettier 2.1
$ prettier --file-info file.js
# { "ignored": false, "inferredParser": "ninja" }
$ prettier --file-info file.js --no-config
# { "ignored": false, "inferredParser": "babel" }
--ignore-unknown
(alias -u
) flag (#8829 by @fisker)
Added # Prettier 2.0
npx prettier * --check
Checking formatting...
foo.unknown[error] No parser could be inferred for file: foo.unknown
All matched files use Prettier code style!
# Prettier 2.1
npx prettier * --check --ignore-unknown
Checking formatting...
All matched files use Prettier code style!
-w
alias for --write
option (#8833 by @fisker)
Add # Prettier 2.0
$ prettier index.js -w
[warn] Ignored unknown option -w. Did you mean -_?
"use strict";
module.exports = require("./src/index");
# Prettier 2.1
$ prettier index.js -w
index.js 30ms
-_
for unknown options (#8934 by @fisker)
Stop suggesting # Prettier 2.0
$ prettier foo.js -a
[warn] Ignored unknown option -a. Did you mean -_?
# Prettier 2.1
$ prettier foo.js -a
[warn] Ignored unknown option -a. Did you mean -c?