Prettier 1.11: CSS fixes and new TypeScript feature support
This release features a ton of CSS formatting fixes as well as support for some new TypeScript features, in addition to some general bugfixes for other languages.
Since the last release, the Prettier website has gotten an all-new design thanks to @orta!
Facebook is 💯% Prettier
Another exciting announcement is that all the JavaScript files in the Facebook codebase have now been converted to Prettier! What's mind-blowing is that there hasn't been a concerted push to convert the codebase to Prettier, we just added the tooling in place and documentation on how to migrate a folder to Prettier and people just started converting their piece of the codebase.
In 8 months, 75% of the codebase was organically converted and last week we did a final push to convert the rest and enforce that every file from now on is using Prettier! It shows that Prettier is robust to support all the crazy edge cases you can imagine and also that it provides a lot of value given the crazy adoption rate.
Highlights
CSS/SCSS/Less
Our CSS formatting got a lot of love from @evilebottnawi during this release!
#3828 by @evilebottnawi)
Format at-rules (Previously, some at-rules (like @if
and @include
) were not formatted by Prettier and were instead printed as-is. They are now formatted:
// Before:
.selector {
@include absolute($top: $long-variable-name, $right: $long-variable-name, $left: auto, $bottom: auto);
}
// After:
.selector {
@include absolute(
$top: $long-variable-name,
$right: $long-variable-name,
$left: auto,
$bottom: auto
);
}
#3959 by @evilebottnawi)
Support popular PostCSS plugins (Some popular PostCSS plugins like postcss-mixins were not working due to how Prettier was formatting CSS. These plugins are now respected:
// Before
$theme: blue;
a {
@mixin $(theme) -colors;
}
// After
$theme: blue;
a {
@mixin $(theme)-colors;
}
#3802 by @evilebottnawi)
Support YAML front-matter block in SCSS (Jekyll relies on YAML front-matter to detect SCSS files, but Prettier was removing it, which would break Jekyll sites when deployed. The YAML front-matter is now preserved, which preserves styling:
---
title: Title
description: Description
---
a {
color: red;
}
TypeScript
!:
) (#4020 by @ikatyang)
Support definite assignment (TypeScript 2.7 added a new feature called definite assignment that can be used in class property initializers. It informs TypeScript that even though a class property does not have an initializer, we can be sure that at runtime it will have a value, rather than undefined
:
class MyComponent {
ngModel!: ng.INgModelController;
}
Prettier 1.10.2 couldn't parse this syntax:
SyntaxError: '=' expected. (2:10)
1 | class MyComponent {
> 2 | ngModel!: ng.INgModelController;
| ^
3 | }
But it is now supported in Prettier 1.11.0.
unique symbol
(#3967 by @ikatyang)
Support TypeScript 2.7 also added a new unique symbol
type:
interface SymbolConstructor {
readonly iterator: unique symbol;
}
Prettier 1.10.2 couldn't parse this syntax:
SyntaxError: ';' expected. (2:29)
1 | interface SymbolConstructor {
> 2 | readonly iterator: unique symbol;
| ^
3 | }
4 |
But it is now supported in Prettier 1.11.0.
#4006 by @Cryrivers)
Support condition types (TypeScript 2.8 will add support for conditional types, which look like ternaries but appear in a type position:
export type DeepReadonly<T> =
T extends any[] ? DeepReadonlyArray<T[number]> :
T extends object ? DeepReadonlyObject<T> :
T;
Prettier 1.10.2 couldn't parse these:
SyntaxError: ';' expected. (2:7)
1 | export type DeepReadonly<T> =
> 2 | T extends any[] ? DeepReadonlyArray<T[number]> :
| ^
3 | T extends object ? DeepReadonlyObject<T> :
4 | T;
But this syntax is supported in Prettier 1.11.0.
JavaScript
--use-tabs
(#3745 by @ikatyang)
Ternaries were indented incorrectly with Because tabs can be represented as different widths, Prettier was sometimes indenting ternaries incorrectly when using tabs. Now we calculate the indentation properly:
// Before:
const abc = props.something
? xyz
: {
prop1: a,
prop2: b,
prop3: false,
};
// After:
const abc = props.something
? xyz
: {
prop1: a,
prop2: b,
prop3: false
};
Other Changes
CSS/SCSS/Less
#3930 by @evilebottnawi)
Lists of lists now have cleaner formatting (We weren't handling lists of lists very well in SCSS. Now we handle them better.
// Before:
$space-scale: (0, "0") (0.25, "0-25") (0.5, "0-5") (0.75, "0-75") (1, "1")
(
1.25,
"1-25"
) (1.5, "1-5") (1.75, "1-75") (2, "2") (2.25, "2-25") (2.5, "2-5")
(
2.75,
"2-75"
) (3, "3") (3.25, "3-25") (3.5, "3-5") (3.75, "3-75") (4, "4");
// After:
$space-scale: (0, "0") (0.25, "0-25") (0.5, "0-5") (0.75, "0-75") (1, "1")
(1.25, "1-25") (1.5, "1-5") (1.75, "1-75") (2, "2") (2.25, "2-25")
(2.5, "2-5") (2.75, "2-75") (3, "3") (3.25, "3-25") (3.5, "3-5")
(3.75, "3-75") (4, "4");
#3906 by @evilebottnawi)
Preserve comment in font-face declaration (Previously, if you had code like this:
@font-face {
font-family: "Prettier";
src: local("Prettier"), /* Local */
url("http://prettier.com/font.woff") /* Network*/
}
Then the "Local" comment was removed by Prettier:
@font-face {
font-family: "Prettier";
src: local("Prettier"), url("http://prettier.com/font.woff"); /* Network*/
}
It is now preserved:
@font-face {
font-family: "Prettier";
src: local("Prettier"), /* Local */ url("http://prettier.com/font.woff"); /* Network*/
}
#3930 by @evilebottnawi)
CSS indentation no longer indents with 3 spaces when line starts with a paren (If a line of CSS was to be indented and the first character in that line was a paren, the CSS was mistakenly indented with 3 spaces instead of the expected 2. Now it's indented with 2 spaces.
// Before:
$longVariable: (
(mobile $mobile) (tablet $tablet) (desktop $desktop) (wide $wide)
);
// After:
$longVariable: (
(mobile $mobile) (tablet $tablet) (desktop $desktop) (wide $wide)
);
#3814 by @evilebottnawi)
Extra space is no longer added inside maps (Prettier was mistakenly adding spaces inside SCSS maps. They are no longer printed.
// Before:
$map: map-merge($map, ($key: $value));
// After:
$map: map-merge($map, ($key: $value));
#3909 by @evilebottnawi)
SCSS comments in selector lists no longer break formatting (Prettier was formatting trailing SCSS comments in CSS selector lists incorrectly, breaking code:
// Before formatting:
.field {
&[data-field-id="1"], // Name
&[data-field-id="2"], // Email
&[data-field-id="3"], // Postal Code
{
background: green;
}
}
// After formatting (Prettier 1.10.2):
.field {
&[data-field-id="1"],
// Name &[data-field-id="2"],
// Email &[data-field-id="3"] {
background: green;
}
}
Prettier now handles these comments correctly:
// After formatting (Prettier 1.11.0):
.field {
&[data-field-id="1"], // Name
&[data-field-id="2"], // Email
&[data-field-id="3"], // Postal Code
{
background: green;
}
}
@import
url (#3770 by @evilebottnawi)
Comma no longer added after Prettier was mistakenly adding a comma after @import
urls. This is no longer added:
/* Before */
@import url("responsive/gt768.css"), screen and (min-width: 768px);
/* After */
@import url("responsive/gt768.css") screen and (min-width: 768px);
!default
directive properly (#3724 by @evilebottnawi)
Handle Prettier was printing the !default
directive in an odd way:
$theme-checkbox-colors: (
default: $theme-color-border,
checked: $theme-color-checked,
disabled: $theme-color-disabled,
disabled-font: $theme-color-font-secondary
)
!default;
It's now handled properly:
$theme-checkbox-colors: (
default: $theme-color-border,
checked: $theme-color-checked,
disabled: $theme-color-disabled,
disabled-font: $theme-color-font-secondary
) !default;
@warn
and @error
directives (#3769 by @evilebottnawi)
Don't format contents of SCSS has a feature that lets you output some text at build-time using @warn
or @error
:
// Unformatted code:
@if ($error) {
@error 'An error occurred: (#{$error}).';
}
Unfortunately, Prettier was treating these directives as media queries, formatting their contents in unexpected ways (in this example, a space is added before the period):
// Formatted code (Prettier 1.10.2):
@if ($error) {
@error 'error (#{$error}) .';
}
Prettier now handles these directives correctly, and will not change the contents of the string:
// Formatted code (Prettier 1.11.0):
@if ($error) {
@error "error (#{$error}).";
}
#3841 by @evilebottnawi)
Don't remove semicolon in Less ruleset declaration (Prettier was mistakenly removing semicolons after Less ruleset declarations, which needed to stay, or else compilation errors would occur. They are now preserved:
// Before:
@detached-ruleset: {
background: red;
}
// After:
@detached-ruleset: {
background: red;
};
#3723 by @hudochenkov)
Don't add newline to empty CSS file (Prettier was previously adding an end-of-file newline to CSS files. We didn't do this for JS files, so we decided to make this behavior consistent in CSS so that it wouldn't introduce surprising source control changes when adding Prettier to a project.
media
params with SCSS interpolation (#3801 by @evilebottnawi)
Ignore Prettier was mistakenly breaking code when a media query contained SCSS interpolation. It is now preserved:
// Unformatted code:
$sm-only: '(min-width: 768px) and (max-width: 991px)';
$lg-and-up: '(min-width: 1200px)';
@media screen and #{$sm-only, $lg-and-up} {
color: #000;
}
// Formatted code (Prettier 1.10.2):
@media screen and, {
color: #000;
}
// Formatted code (Prettier 1.11.0):
$sm-only: "(min-width: 768px) and (max-width: 991px)";
$lg-and-up: "(min-width: 1200px)";
@media screen and #{$sm-only, $lg-and-up} {
color: #000;
}
#3738 by @evilebottnawi)
Don't print two spaces between selector operator and opening bracket (Prettier was mistakenly printing an extra space when a CSS selector ended in an operator (a feature supported by SCSS). This has been fixed:
// Unformatted code:
.this > .ends > .with > .an > .operator > {
// content
}
// Formatted code (Prettier 1.10.2):
.this > .ends > .with > .an > .operator > {
// content
}
// Formatted code (Prettier 1.11.0):
.this > .ends > .with > .an > .operator > {
// content
}
#3768 by @evilebottnawi)
Don't change case of SCSS function names (Prettier was mistakenly lowercasing SCSS function names in certain cases. This has been fixed.
// Unformatted code:
@include breakpoint (getBp(md)) {
&:nth-child(2n + 3) {
clear: both;
}
}
// Formatted code (Prettier 1.10.2):
@include breakpoint (getbp(md)) {
&:nth-child(2n + 3) {
clear: both;
}
}
// Formatted code (Prettier 1.11.0):
@include breakpoint(getBp(md)) {
&:nth-child(2n + 3) {
clear: both;
}
}
>>>
(#3792 by @evilebottnawi)
Keep space around Vue deep selector Prettier was mistakenly stripping spaces around Vue's deep selector:
<!-- Unformatted code: -->
<style scoped>
.box >>> .child-component {
font-size: 24px;
}
</style>
<!-- Formatted code (Prettier 1.10.2): -->
<style scoped>
.box>>>.child-component {
font-size: 24px;
}
</style>
<!-- Formatted code (Prettier 1.11.0): -->
<style scoped>
.box >>> .child-component {
font-size: 24px;
}
</style>
@nest
at-rule (#3975 by @evilebottnawi)
Fix Prettier was mistakenly adding spaces around the &
character in selectors passed to @nest
, which changed which selector the rule compiled into. This has been fixed:
// Unformatted code:
.title {
@nest :global(h1)& {
background: red;
}
}
// Formatted code (Prettier 1.10.2):
.title {
@nest :global(h1) & {
background: red;
}
}
// Formatted code (Prettier 1.11.0):
.title {
@nest :global(h1)& {
background: red;
}
}
progid:DXImageTransform.Microsoft.gradient
as-is (#4028 by @evilebottnawi)
Format In Prettier 1.10.2, we had a lot of logic to handle formatting of Microsoft-browser-specific filter values, but they still weren't formatting very well. Since they are non-standard and infrequently used, we've decided to print them as-is without attempting to format them.
#4048 by @evilebottnawi)
Don't lowercase nesting selector (In Prettier 1.10.2, we were incorrectly lower-casing nesting SCSS selectors:
// Unformatted code:
.foo {
&-1Bar {
}
}
// Formatted code: (Prettier 1.10.2):
.foo {
&-1bar {
}
}
This has been fixed in Prettier 1.11.0:
// Formatted code: (Prettier 1.11.0):
.foo {
&-1Bar {
}
}
JavaScript
#3665 by @duailibe)
Don't print odd-looking parens around return argument with comment (Prettier was printing parens around the argument to a return
statement in an odd way when the argument contained a comment. These parens are now formatted better.
// Unformatted code:
func1(function() {
return func2
//comment
.bar();
});
// Formatted code (Prettier 1.10.2):
func1(function() {
return (func2
//comment
.bar() );
});
// Formatted code (Prettier 1.11.0):
func1(function() {
return (
func2
//comment
.bar()
);
});
#3676 by @ikatyang)
Respect 0-indent markdown-in-js (Prettier's markdown-in-js formatting (triggered by using a template literal tag named md
was inserting indentation):
// Unformatted code
md`
This is some markdown
`
// Formatted code (Prettier 1.10.2)
md`
This is some markdown
`;
This was desired and acceptable behavior for many markdown template tag functions, such as react-markings
, but it broke some other in-house markdown formatters.
Prettier 1.11.0 will now respect the indentation level you set in your markdown, so users of template tag functions like the one provided by react-markings
can continue to indent their code, and users of other template tag functions which do not support indentation can choose not to.
#3830 by @salemhilal)
Format AMD define calls like CJS require calls (When using AMD modules, one pattern is to use define
to specify the dependencies of an anonymous module like so:
define([
"jquery",
"common/global.context",
"common/log.event",
"some_project/square",
"some_project/rectangle",
"some_project/triangle",
"some_project/circle",
"some_project/star"
], function($, Context, EventLogger, Square, Rectangle, Triangle, Circle, Star) {
console.log("some code");
});
Prettier 1.10.2 was breaking this onto multiple lines, which introduced a lot of top-level indentation:
define(
[
"jquery",
"common/global.context",
"common/log.event",
"some_project/square",
"some_project/rectangle",
"some_project/triangle",
"some_project/circle",
"some_project/star"
],
function($, Context, EventLogger, Square, Rectangle, Triangle, Circle, Star) {
console.log("some code");
}
);
Prettier 1.11.0 will now make the array and function expression "hug", which decreases the indentation level:
define([
"jquery",
"common/global.context",
"common/log.event",
"some_project/square",
"some_project/rectangle",
"some_project/triangle",
"some_project/circle",
"some_project/star"
], function(
$,
Context,
EventLogger,
Square,
Rectangle,
Triangle,
Circle,
Star
) {
console.log("some code");
});
skip
like test
(#3735 by @tmquinn)
Format QUnit's Prettier was special-casing formatting for describe
, it
, and test
to improve formatting in tests based on user expectations and requests. However, we were not formatting QUnit's skip
method using the same logic, which led to mixed formatting when switching a test between test
and skip
:
// Unformatted code
test("this is a really long description of some test I want to go here", function (assert) {
assert("something");
});
skip("this is a really long description of some test I want to go here", function (assert) {
assert("something");
});
// Formatted code (Prettier 1.10.2):
test("this is a really long description of some test I want to go here", function(assert) {
assert("something");
});
skip(
"this is a really long description of some test I want to go here",
function(assert) {
assert("something");
}
);
We now treat skip
the same as describe
, it
, and test
, which makes QUnit tests look more uniform:
// Formatted code (Prettier 1.11.0):
test("this is a really long description of some test I want to go here", function(assert) {
assert("something");
});
skip("this is a really long description of some test I want to go here", function(assert) {
assert("something");
});
#4011 by @duailibe)
Break JSX element if a string literal prop has a newline (Newline characters are allowed within a JSX string literal according to the JSX spec, but Prettier was not treating a JSX element as multi-line when one of its attribute values was a string containing a newline character. Prettier will now treat these elements as multi-line as expected:
// Unformatted code:
<path d="M4.765 16.829l3.069-2.946 5.813 5.748
11.33-11.232 3.006 3.18-14.36 14.080z"
/>;
// Formatted code (Prettier 1.10.2):
<path d="M4.765 16.829l3.069-2.946 5.813 5.748
11.33-11.232 3.006 3.18-14.36 14.080z" />;
// Formatted code (Prettier 1.11.0):
<path
d="M4.765 16.829l3.069-2.946 5.813 5.748
11.33-11.232 3.006 3.18-14.36 14.080z"
/>;
#3899 by @vjeux)
Support JSX children spread with flow parser (Using a spread operator in a JSX children expression container position caused a parsing error in Prettier 1.10.2 when using the flow parser:
<JSX>
{...edges}
</JSX>
SyntaxError: Unexpected token ... (2:4)
1 | <JSX>
> 2 | {...edges}
| ^^^
3 | </JSX>
In Prettier 1.11.0, this syntax is supported with the flow parser.
#3948 by @azz)
Fix error when printing flow maybe object return type (In Prettier 1.10.2, this code caused an error to be thrown:
function getScaledData({x}): ?{foo: number} {}
It has been fixed in Prettier 1.11.0.
--insert-pragma
no longer removes duplicate pragmas (#3947 by @azz)
Using --insert-pragma
on code with duplicate pragmas was removing all but one of the duplicates. This has been fixed:
// Unformatted code:
/**
* @x 1
* @x 2
*/
// Formatted code (Prettier 1.10.2):
/**
* @format
* @x 2
*/
// Formatted code (Prettier 1.11.0):
/**
* @format
* @x 1
* @x 2
*/
#3940 by @j-f1)
Wrap flow-typecasted ternaries in parens (To improve code clarity, typecast ternaries will now be wrapped in parens:
// Unformatted code:
const foo = ((1?2:3): number);
// Formatted code (Prettier 1.10.2):
const foo = (1 ? 2 : 3: number);
// Formatted code (Prettier 1.11.0):
const foo = ((1 ? 2 : 3): number);
#3979 by @existentialism)
Fix cases with missing semi when printing DeclareExportDeclaration (Semicolons were being mistakenly removed from declare export default
statements in flow library definition files. This has been fixed.
TypeScript
(void 0)!
(#3989 by @azz)
Don't remove parens from Prettier was mistakenly removing parens from (void 0)!
, which changed the AST of the program. This has been fixed.
#4005 by @ericanderson)
Properly chain when there is a TSNonNullExpression (Prettier was not using its chaining formatting style when the chain included a TypeScript !
non-null expression. This has been fixed:
// Unformatted code:
this.tokenLoads.get(locator).get(start).push({});
this.tokenLoads.get(locator)!.get(start).push({});
// Formatted code (Prettier 1.10.2):
this.tokenLoads
.get(locator)
.get(start)
.push({});
this.tokenLoads.get(locator)!.get(start).push({});
// Formatted code (Prettier 1.11.0):
this.tokenLoads
.get(locator)
.get(start)
.push({});
this.tokenLoads
.get(locator)!
.get(start)
.push({});
Markdown
#3780 by @ikatyang)
Heading after list item gets merged into list (Prettier was mistakenly merging a heading beneath a list item into the list. Now it is treated as a header:
<!-- Unformatted code -->
* Something
### Some heading
<!-- Formatted code (Prettier 1.10.2) -->
* Something
### Some heading
<!-- Formatted code (Prettier 1.11.0) -->
* Something
### Some heading
#3780 by @ikatyang)
Don't parse HTML entities in link URLs (Links whose URL contained HTML entities were mistakenly being changed when run through Prettier. They are now preserved.
<!-- Unformatted code -->
[Test](http://localhost:8080/test?language=DE¤cy=EUR)
<!-- Formatted code (Prettier 1.10.2) -->
[Test](http://localhost:8080/test?language=DE¤cy=EUR)
<!-- Formatted code (Prettier 1.11.0) -->
[Test](http://localhost:8080/test?language=DE¤cy=EUR)
#3676 by @ikatyang)
Fix indentation of template strings within code blocks (Indentation of JS tagged template string content within markdown code blocks was being calculated incorrectly:
<!-- Unformatted code: -->
- 1
- 2
- 3
```js
something`
asd
asd
asd
`
```
<!-- Formatted code (Prettier 1.10.2): -->
* 1
* 2
* 3
```js
something`
asd
asd
asd
`;
```
It has been fixed in Prettier 1.11.0:
<!-- Formatted code (Prettier 1.11.0): -->
* 1
* 2
* 3
```js
something`
asd
asd
asd
`;
```
#3787 by @ikatyang)
Print multiline content correctly in footnoteDefinition (Prettier was mistakenly using the incorrect level of indentation when printing a footnote that contained a code block. This has been fixed:
<!-- Unformatted code: -->
Some text.[^fn]
[^fn]: Here is a footnote which includes code.
```rs
fn main() {
println!("this is some Rust!");
}
```
<!-- Formatted code (Prettier 1.10.2): -->
Some text.[^fn]
[^fn]: Here is a footnote which includes code.
```rs
fn main() {
println!("this is some Rust!");
}
```
<!-- Formatted code (Prettier 1.11.0): -->
Some text.[^fn]
[^fn]: Here is a footnote which includes code.
```rs
fn main() {
println!("this is some Rust!");
}
```
tabWidth
for list items (#3990 by @ikatyang)
Respect We've discovered that CommonMark diverges from the original Markdown syntax for code blocks in list items. This leads to scenarios where indented code-blocks in Markdown where being rendered as regular paragraphs. This change uses the tabWidth
option to determine how much indentation to use in list items. Have a read through #3459 if you're interested in the details.
<!-- before -->
1. Change to your home directory:
cd
<!-- after -->
1. Change to your home directory:
cd
This change should also improve indentation in text editors:
API
#3775 by @ikatyang)
Support options in plugins (As part of fleshing out our beta plugin API for community-made language plugins, we have added support for plugins to define their own options!
Plugin options can now be printed in help:
prettier --plugin @prettier/plugin-python --help
Likewise, plugin options can be specified on the command-line:
prettier --plugin my-cool-prettier-plugin --my-custom-option
And plugin options can also be defined in .prettierrc
:
{ "plugins": ["foo-plugin"], "fooOption": "bar" }
#3622 by @ikatyang)
Don't allow kebab-cased options in config files (Prettier was mistakenly allowing kebab-case variations of options in .prettierrc
files:
{ "print-width": 100 }
This was not intended to be allowed, and has been reverted (in this case, you would need to use printWidth
).
Configuration
--config
is passed (#3992 by @josephfrazier)
Respect EditorConfig when This is a minor change to the the way .editorconfig
files are handled. Previously when --config
was provided, .editorconfig
was ignored.
Thanks to all of Prettier's contributors and the community for making Prettier a successful and productive open-source project! We couldn't do it without everyone ❤️