Skip to content

Latest commit

 

History

History
2320 lines (1824 loc) · 54.5 KB

2020-08-24-2.1.0.md

File metadata and controls

2320 lines (1824 loc) · 54.5 KB
author authorURL title
Sosuke Suzuki (@sosukesuzuki)
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

Add --embedded-language-formatting={auto,off} option (#7875 by @bakkot, #8825 by @fisker)

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

Labeled Tuple Elements (#8885 by @fisker, #8982 by @sosukesuzuki)
// 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];
Short-Circuiting Assignment Operators (#8982 by @sosukesuzuki)
// Input
a ||= b;

// Prettier 2.0
SyntaxError: Expression expected. (1:5)
> 1 | a ||= b;

// Prettier 2.1
a ||= b;
Type annotations on catch clauses (#8805 by @fisker)
// Input
try {} catch (e: any) {}

// Prettier 2.0
try {
} catch (e) {}

// Prettier 2.1
try {
} catch (e: any) {}

Other changes

JavaScript

Support the F# and Smart pipeline operator proposals (#6319 by @sosukesuzuki, @thorn0, #7979 by @sosukesuzuki)

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

Fix end-of-line comments if followed by trailing whitespace (#8069 by @shisama)

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

Fix inconsistent parsing of injected expressions in styled-components template literals (#8097 by @thecodrr)

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

Fix object trailing commas that last property is ignored (#8111 by @fisker)

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

Keep object key with escape sequence as it is (#8160 by @fisker)

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

Fix extra space after minus in CSS-in-JS (#8255 by @thorn0)

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

Fix comments in the extends part of class declarations/expressions (#8312 by @thorn0)

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

Don't wrap arrays in Jest test.each template strings (#8354 by @yogmel)

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

Support insertPragma and requirePragma in files with shebang (#8376 by @fisker)

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

Fix range formatting indentation (#8410 by @thorn0)

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

Improve detection of source elements for range formatting (#8419 by @thorn0)

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

Support Private Fields in in (#8431 by @sosukesuzuki)

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;

Support ES Module Attributes and JSON modules (#8436 by @fisker)

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

Support record and tuple syntax (#8453 by @fisker)

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

Wrap jsx element on the left of "<" with parentheses (#8461 by @sosukesuzuki)

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

Fix indentation for binary expressions with trailing comments (#8476 by @sosukesuzuki)

// Input
a +
  a + // comment
  a;

// Prettier 2.0
a +
a + // comment
  a;

// Prettier 2.1
a +
  a + // comment
  a;

Fix unstable comments in binary expressions (#8491 by @thorn0)

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

Quote and unquote number keys (#8508 by @lydell)

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.

Prefer leading comment when there is a comment on after "?" in conditional types (#8557 by @sosukesuzuki)

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

Break ternary expressions that include a multiline block comment (#8592 by @sosukesuzuki)

// Input
test
  ? /* comment
       comment
    */
    foo
  : bar;

// Prettier 2.0
test ? /* comment
       comment
    */ foo : bar;

// Prettier 2.1
test
  ? /* comment
       comment
    */
    foo
  : bar;

Fix unstable pair of comments between class methods (#8731 by @fisker)

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

Fix duplicated prettier-ignore comments (#8742 by @fisker)

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

Support Decimal Proposal (#8901 by @fisker)

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;

Add parens when yielding jsx (#9011 by @fisker)

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

Fix the babel-ts parser so that it emits a proper syntax error for (a:b) (#8046 by @thorn0)

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 |

Parenthesize string literals to avoid interpreting as directives (#8422 by @thorn0)

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

Support TypeScript 3.9 breaking change for Optional Chaining and Non-Null Assertions (#8450 by @sosukesuzuki)

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

Fix function type param contains nullable param (#8365 by @fisker)

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

Fix export default of Flow Enum (#8768 by @gkz)

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

Do not break code with a comment at the end of an at-rule (#7009 by @evilebottnawi)

/* Input */
@at-root .foo
// .bar
{

}

/* Prettier 2.0 */
@at-root .foo
// .bar {
}

/* Prettier 2.1 */
@at-root .foo
// .bar
{
}

Fix url() unquoted content manipulation (#7592 by @mattiacci)

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

Incorrect whitespace added after escaped colon in css grid line name (#8535 by @boyenn)

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

Add support for @supports selector() (#8545 by @boyenn)

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

Improve Prettier handling of arbitrary arguments (#8567, #8566 by @boyenn)

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

Fix extra indentation of lines following comments in scss (#7844 by @boyenn)

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

Fix inline comments between property and value (#8366 by @fisker)

// Input
a {
  color: // comment
         red;
}

// Prettier 2.0
a {
  color: // comment red;
}

// Prettier 2.1
a {
  color: // comment
    red;
}

Comments at the end of the file were lost if the final semicolon was omitted (#8675 by @fisker)

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

Fix :extend pseudo-class (#8178 by @fisker)

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

Fix inline comments contains /* (#8360 by @fisker)

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

Omit trailing semicolon on single line style attributes (#8013 by @bschlenk)

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

Preserve non-ASCII whitespace characters in HTML (#8137 by @fisker)

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' ]

Support legacy HTML-like comments script blocks (#8173 by @fisker, #8394 by @fisker)

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>

  1. type="module"
  2. type="text/babel" and data-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>

Treat <select> as inline-block and <optgroup>/<option> as block (#8275 by @thorn0, #8620 by @fisker)

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>

Fix broken URLs with commas in srcset (#8359 by @fisker)

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

Support <script type="text/html> (#8371 by @sosukesuzuki)

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

Support front matter with dynamic language (#8381 by @fisker)

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>

Don't preserve line breaks around text-only content (#8614 by @fisker)

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>

Recognize known html tags (#8621 by @fisker)

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

Fix formatting element with void element as its last child (#8643 by @ikatyang)

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

Improve formatting Vue SFC root blocks (#8023 by @sosukesuzuki, #8465 by @fisker)

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.

Improve parsing for custom blocks (#8153 by @sosukesuzuki)

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

Fix broken format with upper case HTML tag (#8280 by @fisker)

<!-- Input -->
<!doctype html><HTML></HTML>

<!-- Prettier 2.0 -->
<!DOCTYPE html>><HTML></HTML>

<!-- Prettier 2.1 -->
<!DOCTYPE html><HTML></HTML>

Fix ugly formatting for one line template in Vue SFC (#8325 by @sosukesuzuki)

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

Support Vue DOM Template (#8326 by @sosukesuzuki)

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>

Improve upper case HTML tag formatting in DOM template (#8337 by @sosukesuzuki)

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

Fix parenthesized interpolation format (#8747 by @fisker)

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

Fix named slots shorthand value is not formatted (#8839 by @wenfangdu)

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

Fix optional chaining with computed properties and handling of this (#8253 by @thorn0, #7942 by @fisker, fixes in angular-estree-parser by @ikatyang)

<!-- Input -->
{{ a?.b[c] }}
{{ a  ( this )}}

<!-- Prettier 2.0 -->
{{ (a?.b)[c] }}
{{ a  ( this )}}

<!-- Prettier 2.1 -->
{{ a?.b[c] }}
{{ a(this) }}

Preserve parentheses around pipes in objects literals for compatibility with AngularJS 1.x (#8254 by @thorn0)

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

Respect singleQuote option around attribute value more complex than a bare text (#8375 by @dcyriller)

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

Fix formatting of classic components inside element (#8593 by @mikoscz)

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

Support escaping a mustache with a backslash (#8634 by @dcyriller)

{{!-- Input --}}
\{{mustache}}
\\{{mustache}}
\\\{{mustache}}

{{!-- Prettier 2.0 --}}
{{mustache}}
\{{mustache}}
\\{{mustache}}

{{!-- Prettier 2.1 --}}
\{{mustache}}
\\{{mustache}}
\\\{{mustache}}

Format only class names in attributes (#8677 by @dcyriller)

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

Improve wrapping of GraphQL fragment directives (#7721 by @sasurau4)

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

Fix comments between interfaces (#8006 by @fisker)

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

Allow interfaces to implement other interfaces (#8007 by @fisker)

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

Update remark-parse to v8 (#8140 by @saramarcondes, @fisker, @thorn0)

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.

Correctly format CJK sentences with Variation Selector (#8511 by @ne-sachirou)

<!-- Input -->
麻󠄁羽󠄀‼️

<!-- Prettier 2.0 -->
麻 󠄁 羽 󠄀 ‼️

<!-- Prettier 2.1 -->
麻󠄁羽󠄀‼️

YAML

Fix unstable format with prettier-ignore (#8355 by @fisker)

# 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

Preserve blank lines in comments (#8356 by @fisker)

# 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

Update yaml and yaml-unist-parser (#8386 by @fisker, fixes in yaml-unist-parser by @ikatyang)

# 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
    | ^^^^^^^^^^^

Fix error on YAML Inline Extend syntax (#8888 by @fisker, @evilebottnawi, fixes in yaml-unist-parser by @ikatyang)

# 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

Add plugins' parsers to the parser option (#8390 by @thorn0)

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

Fix prettier.getFileInfo() (#8548, #8551, #8585 by @fisker)

  • When passing {resolveConfig: true}, the inferredParser 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"}, the inferredParser result might incorrect.
  • If given filePath is ignored, the inferredParser is always null 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 }

Fix resolve editorConfig for files in deep directory (#8591 by @fisker)

Previous version can't find .editorconfig for files in deep directory (depth great than 9 to project root, see #5705).

Support .cjs and .json5 configuration files (#8890, #8957 by @fisker)

Added new format of configuration files:

  • .prettierrc.json5
  • .prettierrc.cjs
  • prettier.config.cjs

Fix wrong range format on files with BOM (#8936 by @fisker)

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

Fix filenames contains CJK or emoji not correctly ignored (#8098 by @fisker)

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

Added --ignore-unknown(alias -u) flag (#8829 by @fisker)

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

Add -w alias for --write option (#8833 by @fisker)

# 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

Stop suggesting -_ for unknown options (#8934 by @fisker)

# 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?