Prettier 1.14: YAML Support
This release adds YAML support, pragma (i.e. /** @prettier */
) support for every language, and improves performance on large files. It also adds support for several new syntax features, and has a few formatting tweaks to make your code even prettier. ✨
Highlights
YAML
#4563, #4742, #4773, #4854 by @ikatyang)
Support YAML (Prettier can now format YAML files! 🎉
The implementation is highly compliant with the YAML spec, and backed by the excellent yaml
package thanks to @eemeli. A few highlights:
Word wrap
Just like in Markdown, we’ll hard-wrap prose at 80-characters if it doesn’t affect the meaning of the file.
Input:
>
Voilà! In view, a humble vaudevillian veteran cast vicariously as both victim and villain by the vicissitudes of Fate. This visage, no mere veneer of vanity, is a vestige of the vox populi, now vacant, vanished. However, this valourous visitation of a bygone vexation stands vivified and has vowed to vanquish these venal and virulent vermin vanguarding vice and vouchsafing the violently vicious and voracious violation of volition! The only verdict is vengeance; a vendetta held as a votive, not in vain, for the value and veracity of such shall one day vindicate the vigilant and the virtuous. Verily, this vichyssoise of verbiage veers most verbose, so let me simply add that it’s my very good honour to meet you and you may call me V.
Output: (--prose-wrap always
)
>
Voilà! In view, a humble vaudevillian veteran cast vicariously as both victim
and villain by the vicissitudes of Fate. This visage, no mere veneer of
vanity, is a vestige of the vox populi, now vacant, vanished. However, this
valourous visitation of a bygone vexation stands vivified and has vowed to
vanquish these venal and virulent vermin vanguarding vice and vouchsafing the
violently vicious and voracious violation of volition! The only verdict is
vengeance; a vendetta held as a votive, not in vain, for the value and
veracity of such shall one day vindicate the vigilant and the virtuous.
Verily, this vichyssoise of verbiage veers most verbose, so let me simply add
that it’s my very good honour to meet you and you may call me V.
Note: the
proseWrap
option is set topreserve
by default so you’ll have to specifyalways
ornever
to enable this feature.
Ignore a portion of the file
If for some reason you don’t want to format a part of the YAML file, you can always put an ignore comment before it:
# prettier-ignore
key : value
hello: world
Front Matter
#4773 by @ikatyang)
Format YAML front matter (Prettier can now format ---
-delimited YAML front matter in CSS and Markdown files:
Input & Output (Prettier 1.13):
---
key : value
---
# heading
content
Output (Prettier 1.14):
---
key: value
---
# heading
content
Pragma
requirePragma
/insertPragma
in every language (#4688, #4699, #4713 by @ikatyang)
Support Prettier 1.7.0 and 1.8.0 introduced two new options:
--require-pragma
and
--insert-pragma
.
However, these options were only supported in a few languages.
Now these options are available in every language, including YAML!
YAML
# @prettier key: value
CSS/Less/SCSS
/** @prettier */ .class { display: none; }
GraphQL
# @prettier query Browse($offset: Int) { browse(offset: $offset) }
Vue
<!-- @prettier --> <template> <div>Template</div> </template>
JavaScript
#4830 by @suchipi)
Never inline decorators unless they’re lone parameter decorators (Previously, decorators were always inlined since MobX inlined them by convention, but reports from the community led us to discover that MobX is the only major library that follows this convention. Prettier now puts decorators on their own lines unless they’re parameter decorators.
// Input
@observer
class OrderLine {
@observable
price: number = 0;
@observable amount: number = 1;
foo(@required name) {
console.log(name);
}
}
// Output (Prettier 1.13)
@observer
class OrderLine {
@observable price: number = 0;
@observable amount: number = 1;
foo(@required name) {
console.log(name);
}
}
// Output (Prettier 1.14)
@observer
class OrderLine {
@observable
price: number = 0;
@observable
amount: number = 1;
foo(@required name) {
console.log(name);
}
}
#4717 by @karl)
Handle JSX whitespace separately from fbt whitespace (Previously, JSX whitespace was always preserved
since Facebook has a custom translation pipeline (fbt
) that uses JSX syntax but treats whitespace differently than regular JSX,
which meant we couldn’t change JSX whitespace without breaking the Facebook codebase.
In Prettier 1.14, we now detect Facebook fbt
tags and handle whitespace for them differently from other JSX tags,
improving the consistency across different but equivalent inputs.
// Input and Output from Prettier 1.13
first = (
<div>
Text<br />
More text<br />
And more<br />
</div>
);
second = (
<div>
Text<br />More text<br />And more<br />
</div>
);
third = (
<div>
Text
<br />
More text
<br />
And more
<br />
</div>
);
// Output from Prettier 1.14
first = (
<div>
Text
<br />
More text
<br />
And more
<br />
</div>
);
second = (
<div>
Text
<br />
More text
<br />
And more
<br />
</div>
);
third = (
<div>
Text
<br />
More text
<br />
And more
<br />
</div>
);
When the text separating tags or expressions is just a single character we print the entire group on a single line where possible.
// Input and Output from Prettier 1.13
x = (
<div>
{hour}:{minute}:{second}
</div>
);
x = (
<div>
{hour}
:
{minute}
:
{second}
</div>
);
x = (
<div>
{hour}:
{minute}:
{second}
</div>
);
// Output from Prettier 1.14
x = (
<div>
{hour}:{minute}:{second}
</div>
);
x = (
<div>
{hour}:{minute}:{second}
</div>
);
x = (
<div>
{hour}:{minute}:{second}
</div>
);
It also improves the output of edges cases like this:
// Input
this_really_should_split_across_lines =
<div>
before{stuff}after{stuff}after{stuff}after{stuff}after{stuff}after{stuff}after{stuff}after
</div>
// Output (Prettier 1.13)
this_really_should_split_across_lines = (
<div>
before{stuff}after{stuff}after{stuff}after{stuff}after{stuff}after{stuff}after{
stuff
}after
</div>
);
// Output (Prettier 1.14)
this_really_should_split_across_lines = (
<div>
before
{stuff}
after
{stuff}
after
{stuff}
after
{stuff}
after
{stuff}
after
{stuff}
after
{stuff}
after
</div>
);
#4601 by @duailibe)
Break JSX in arrow functions in JSX expressions (In previous versions, JSX in arrow functions in JSX expressions followed the general fit-or-break rule, but it’s less readable when iterating over an array. Prettier 1.14 forces these arrow functions to break, improving readability.
// Input
const UsersList = ({ users }) => (
<section>
<h2>Users list</h2>
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</section>
)
// Output (Prettier 1.13)
const UsersList = ({ users }) => (
<section>
<h2>Users list</h2>
<ul>{users.map(user => <li key={user.id}>{user.name}</li>)}</ul>
</section>
);
// Output (Prettier 1.14)
const UsersList = ({ users }) => (
<section>
<h2>Users list</h2>
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</section>
);
TypeScript
#4625, #4757 by @ikatyang)
Support for TypeScript 3.0 (A few new features that include new syntax are added in the upcoming TypeScript 3.0:
the unknown
type and
tuples in rest parameters and spread expressions.
Prettier 1.14 adds support for them so you can format them when TypeScript 3.0 is released.
// UnknownType
const json: unknown = JSON.parse(jsonText);
// RestType
type Foo = [string, number];
type Bar = [boolean, ...Foo];
// OptionalType
type Baz = [string, number?];
JSON
#4852 by @ikatyang)
Do not put values on a separate line from the key (Putting long values on new rows is the core feature of Prettier, but we found that it doesn’t improve readability for objects with long string values inside JSON files. Prettier 1.14 will not move an object’s string value regardless if it fits the print width or not.
// Input
{
"description": "a long long long long long long long long long long long long long long long long long paragraph"
}
// Output (Prettier 1.13)
{
"description":
"a long long long long long long long long long long long long long long long long long paragraph"
}
// Output (Prettier 1.14)
{
"description": "a long long long long long long long long long long long long long long long long long paragraph"
}
Markdown
#4893 by @ikatyang)
Only align lists if they’re already aligned (Previously, we always align lists for better indenting experience and as a workaround for indented codeblock mis-parsing, but this introduced double spaces in front of ordered lists, which is not common in markdown. In Prettier 1.14, we only align lists in the following cases:
- They’re already aligned.
- There’re at least two spaces in front of the first list item.
- There’s an indented codeblock inside of it.
Input:
1. 123
1. 123
---
1. 123
1. 123
---
11. 123
1. 123
---
11. 123
1. 123
---
1. 123
1. 123
Output: (Prettier 1.13)
1. 123
1. 123
---
1. 123
1. 123
---
11. 123
1. 123
---
11. 123
1. 123
---
1. 123
1. 123
Output: (Prettier 1.14)
1. 123
1. 123
---
1. 123
1. 123
---
11. 123
1. 123
---
11. 123
1. 123
---
1. 123
1. 123
Performance
#4790, #4848 by @sompylasar)
Performance improvement on big files (The core feature of Prettier is to wrap lines when they go past the print width,
and to do this we need to calculate the visual width of every character.
The easiest way to count them is by using JavaScript’s String#length
property
but some non-ASCII characters like CJK characters have widths larger than a Latin character.
As a workaround, we replaced those 2-char-wide characters with 2 spaces before calculating the string’s length.
This works fine but it also slows down Prettier because we have to run the replacement on every token.
In Prettier 1.14, we check if the string contains only ASCII characters
so we don’t need to perform unnecessary string replacement.
This results in a 20% speed-up on large files.
Other changes
API/CLI
plugins
and pluginSearchDirs
in config files (#4667 by @ikatyang)
Support relative paths for In Prettier 1.13, we introduced a new pluginSearchDirs
option that changes where Prettier looks for plugins.
It worked well when specified in the CLI since it was always relative to the current directory,
but relative paths didn’t work in config files.
In Prettier 1.14, relative paths for pluginSearchDirs
and plugins
in config files are now supported.
prettier
installed in a directory not named prettier
(#4706 by @asottile)
Do not throw error if We added support for globally installed plugins in Prettier 1.13 by searching up the directory tree to
find the nearest node_modules
from prettier
. We assumed that there would always be a prettier
directory
which caused Prettier to crash if it was in a differently-named directory.
We changed our searching logic in Prettier 1.14 so you should now be able to rename the prettier
directory if you need to
(for example if publishing a fork to npm).
filepath
in browser (#4721 by @ikatyang)
Support In Prettier 1.13, we added first-class support for running Prettier in the browser, but the only way to
choose which parser to use was via the parser
option. Prettier 1.14 adds support for the filepath
option in the browser
API, which will allow Prettier to infer which parser to use, just like the it can with the Node.js API. This
should be especially useful for web editor applications!
isPreviousLineEmpty
to plugins (#4748 by @warrenseine)
Expose Previously, we exposed isNextLineEmpty
to plugins but not isPreviousLineEmpty
.
Prettier 1.14 exposes it, because it can be useful for some scenarios like directives in C#.
JavaScript
#4697 by @ikatyang)
Support BigInt literals (BigInt literals are now supported in the default babylon
parser.
const bigInt = 1n;
throw
expressions (#4695 by @VojtechStep)
Support Throw expressions are now supported in the default babylon
parser.
const assert = x => x || throw new Error('...');
#4657 by @duailibe)
Always expand the first argument if the second argument is also a call expression (Previously, we had a special case to not break function calls if there were only 2 parameters passed and the first parameter was a function. This worked well, but if the second parameter was also a function, it didn’t look very good.
// Input
somePromise.then((args) => {
this.props.receiveFavoritesActions(id, [].concat(...args));
}, ({ isCanceled }) => !isCanceled && logger.warn(`Error getting actions for the product: ${id}`));
// Output (Prettier 1.13)
somePromise.then(args => {
this.props.receiveFavoritesActions(id, [].concat(...args));
}, ({ isCanceled }) => !isCanceled && logger.warn(`Error getting actions for the product: ${id}`));
// Output (Prettier 1.14)
somePromise.then(
args => {
this.props.receiveFavoritesActions(id, [].concat(...args));
},
({ isCanceled }) =>
!isCanceled && logger.warn(`Error getting actions for the product: ${id}`)
);
#4778 by @ikatyang)
Add parens for await in bind (Previously, Prettier wrongly removed the necessary parentheses for await
in the experimental bind syntax,
causing its meaning to be change. Prettier 1.14 now preserves the parentheses correctly.
// Input
const doBothThings = async () => {
const request = doAsyncThing();
return (await request)::doSyncThing();
};
// Output (Prettier 1.13)
const doBothThings = async () => {
const request = doAsyncThing();
return await request::doSyncThing(); // means `await (request::doSyncThing)`
};
// Output (Prettier 1.14)
const doBothThings = async () => {
const request = doAsyncThing();
return (await request)::doSyncThing();
};
super
and await
(#4823 by @ikatyang)
Allow top level super
and await
are not allowed to be in places other than classes and async functions, respectively,
but our range format option didn’t quite work properly when selecting the contents of a function.
Prettier 1.14 allows them to be everywhere.
super();
await doSomething();
this
and super
in functional composition heuristics (#4836 by @princed)
Blacklist In Prettier 1.13, we improved the formatting for functional composition functions (e.g., pipe
, compose
, etc.)
by putting their parameters on their own line, but this introduced false positives for functions with the same name in classes.
Prettier 1.14 blacklists this
and super
in functional composition heuristics.
// Input
class X {
x() {
this.compose(a(), b);
super.compose(a(), b);
}
}
// Output (Prettier 1.13)
class X {
x() {
this.compose(
a(),
b
);
super.compose(
a(),
b
);
}
}
// Output (Prettier 1.14)
class X {
x() {
this.compose(a(), b);
super.compose(a(), b);
}
}
TypeScript
import.meta
(#4762 by @ikatyang)
Support In Prettier 1.13, the version of the TypeScript parser we used did not support parsing import.meta
syntax.
We updated our TypeScript parser in Prettier 1.14 so they are now parsed and formatted correctly.
console.log(import.meta.url);
#4762 by @ikatyang)
Optional property with StringLiteral key in class (In the prior version, the ?
in an optional property with a string literal as the key was wrongly removed.
We fixed this bug in Prettier 1.14 so it won’t be removed.
// Input
export class ClassExample {
"a-prop"?: boolean;
}
// Output (Prettier 1.13)
export class ClassExample {
"a-prop": boolean;
}
// Output (Prettier 1.14)
export class ClassExample {
"a-prop"?: boolean;
}
#4762 by @ikatyang)
Throw error on multiple super classes in class (Classes are only allowed to have one parent class
but the TypeScript AST allows for multiple since the extends
clause
has the same structure internally as the implements
clause.
Previously, any extra super classes were silently dropped during printing,
which may have caused confusion after formatting.
In Prettier 1.14, they are now marked as syntax errors instead.
// Input
class Foo extends BarComponent, BazService, QuuxProvider {}
// Output (Prettier 1.13)
class Foo extends BarComponent {}
// Output (Prettier 1.14)
/*
SyntaxError: Classes can only extend a single class.
*/
#4885 by @ikatyang)
Support JSX spread child (Previously, the ...
in children spread in JSX expressions were wrongly removed.
We fixed this issue in Prettier 1.14.
// Input
const x = <div>{...[0]}</div>
// Output (Prettier 1.13)
const x = <div>{[0]}</div>;
// Output (Prettier 1.14)
const x = <div>{...[0]}</div>;
Flow
.js.flow
extension (#4777 by @ikatyang)
Support .js.flow
is the extension for Flow declaration files but previously we didn’t recognize it.
In Prettier 1.14, they should be picked up automatically
so you don’t need to add overrides for them in config files.
CSS/Less/SCSS
#4701 by @evilebottnawi)
Handle newline between front-matter and comment correctly (Multiple newlines between front matter and a CSS comment were replaced with a space in Prettier 1.13. In Prettier 1.14, we print a newline between them instead.
/* Input */
---
key: value
---
/* comment */
.class {
display: none;
}
/* Output (Prettier 1.13) */
---
key: value
---
/* comment */
.class {
display: none;
}
/* Output (Prettier 1.14) */
---
key: value
---
/* comment */
.class {
display: none;
}
#4733 by @davidgomes)
Support at-rule ends with right curly bracket (In the prior version, at-rules that ended with }
were not parsed correctly.
Prettier 1.14 now correctly recognizes and formats them.
/* Input */
@mixin placeholder {
&::placeholder {@content}
}
/* Output (Prettier 1.13) */
/*
SyntaxError: CssSyntaxError Unclosed block
*/
/* Output (Prettier 1.14) */
@mixin placeholder {
&::placeholder {
@content;
}
}
Markdown
#4740 by @ikatyang)
Preserve email autolink (Autolinks are formatted as their url in the prior version, which is fine.
But there’s a special case for email links that they’ll be resolved as mailto:
links.
In Prettier 1.14, email autolinks are preserved.
<!-- Input -->
<hello@example.com>
<!-- Output (Prettier 1.13) -->
<mailto:hello@example.com>
<!-- Output (Prettier 1.14) -->
<hello@example.com>
#4783 by @kachkaev)
Do not require space after markdown block language name (In Prettier 1.12, we added the support for fenced codeblock lang followed by attributes, which requires them to be separated by whitespaces. But this introduced the inconsistency for codeblock highlighting in Atom that codeblocks are highlighted but we do not format them. We updated our detection logic in Prettier 1.14 so they should behave the same now.
<!-- Input -->
```js{something=something}
const x = 1;
```
<!-- Output (Prettier 1.13) -->
```js{something=something}
const x = 1;
```
<!-- Output (Prettier 1.14) -->
```js{something=something}
const x = 1;
```
#4734 by @ikatyang)
Use language aliases to find parser for markdown codeblocks (Previously, we used the language name
and extensions
to determine which parser to use for codeblock formatting,
but we found that it’s impossible to format JSON with Comments
codeblocks and keep syntax highlighter working at the same time
since they share the same .json
extension with JSON
and the comment syntax highlighting is only available in JSON5
.
We added the support for using the language aliases
to find parser in Prettier 1.14
so you should be able to use jsonc
to format and trigger syntax highlighting for JSON with Comments
codeblocks.
<!-- Input -->
```jsonc
// comment
{"a":1}
```
<!-- Output (Prettier 1.13) -->
```jsonc
// comment
{"a":1}
```
<!-- Output (Prettier 1.14) -->
```jsonc
// comment
{ "a": 1 }
```
#4832 by @ikatyang)
Preserve entity for encoded character if its code point is greater than U+FFFF (The markdown parser we use (remark
) parses every encoded character into a single AST node
so that we’re able to restore the encoded character by detecting if the value in the AST node is in length of 1.
But there’s an exception that a single character can be in length of 2 if its code point is greater than 0xffff
since JavaScript uses UTF-16 (2 bytes) to encode strings.
Prettier 1.14 correctly recognizes these characters so they won’t be transformed into the literal character.
<!-- Input -->
😉
<!-- Output (Prettier 1.13) -->
😉
<!-- Output (Prettier 1.14) -->
😉
Vue
#4868 by @ikatyang)
Support range format for Vue files (Previously, range formatting was not available in Vue, but Prettier 1.14 adds support for it.
GraphQL
#4808 by @ikatyang)
Preserve linebreak in non-block stringValue (Non-block string values are only allowed to be in a single line
but Prettier 1.13 wrongly transformed the escaped \n
into a real newline.
Prettier 1.14 now correctly prints \n
.
# Input
{
foo(input: {multiline: "ab\ncd"}) { id }
}
# Output (Prettier 1.13)
{
foo(input: { multiline: "ab
cd" }) {
id
}
}
# Output (Prettier 1.14)
{
foo(input: { multiline: "ab\ncd" }) {
id
}
}