prettier/website/blog/2018-07-29-1.14.0.md

26 KiB
Raw Blame History

author authorURL title
Ika (@ikatyang) https://github.com/ikatyang 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

Support YAML (#4563, #4742, #4773, #4854 by @ikatyang)

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, well hard-wrap prose at 80-characters if it doesnt 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 its 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 its my very good honour to meet you and you may call me V.  

Note: the proseWrap option is set to preserve by default so youll have to specify always or never to enable this feature.

Ignore a portion of the file

If for some reason you dont 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

Format YAML front matter (#4773 by @ikatyang)

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

Support requirePragma/insertPragma in every language (#4688, #4699, #4713 by @ikatyang)

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

Never inline decorators unless theyre lone parameter decorators (#4830 by @suchipi)

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

Handle JSX whitespace separately from fbt whitespace (#4717 by @karl)

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

Break JSX in arrow functions in JSX expressions (#4601 by @duailibe)

In previous versions, JSX in arrow functions in JSX expressions followed the general fit-or-break rule, but its 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

Support for TypeScript 3.0 (#4625, #4757 by @ikatyang)

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

Do not put values on a separate line from the key (#4852 by @ikatyang)

Putting long values on new rows is the core feature of Prettier, but we found that it doesnt improve readability for objects with long string values inside JSON files. Prettier 1.14 will not move an objects 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

Only align lists if theyre already aligned (#4893 by @ikatyang)

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:

  • Theyre already aligned.
  • Therere at least two spaces in front of the first list item.
  • Theres 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

Performance improvement on big files (#4790, #4848 by @sompylasar)

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 JavaScripts 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 strings 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 dont need to perform unnecessary string replacement. This results in a 20% speed-up on large files.

Other changes

API/CLI

Support relative paths for plugins and pluginSearchDirs in config files (#4667 by @ikatyang)

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 didnt work in config files. In Prettier 1.14, relative paths for pluginSearchDirs and plugins in config files are now supported.

Do not throw error if prettier installed in a directory not named prettier (#4706 by @asottile)

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

Support filepath in browser (#4721 by @ikatyang)

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!

Expose isPreviousLineEmpty to plugins (#4748 by @warrenseine)

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

Support BigInt literals (#4697 by @ikatyang)

BigInt literals are now supported in the default babylon parser.

const bigInt = 1n;

Support throw expressions (#4695 by @VojtechStep)

Throw expressions are now supported in the default babylon parser.

const assert = x => x || throw new Error('...');

Always expand the first argument if the second argument is also a call expression (#4657 by @duailibe)

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

Add parens for await in bind (#4778 by @ikatyang)

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

Allow top level super and await (#4823 by @ikatyang)

super and await are not allowed to be in places other than classes and async functions, respectively, but our range format option didnt quite work properly when selecting the contents of a function. Prettier 1.14 allows them to be everywhere.

super();

await doSomething();

Blacklist this and super in functional composition heuristics (#4836 by @princed)

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

Support import.meta (#4762 by @ikatyang)

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

Optional property with StringLiteral key in class (#4762 by @ikatyang)

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

Throw error on multiple super classes in class (#4762 by @ikatyang)

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

Support JSX spread child (#4885 by @ikatyang)

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

Support .js.flow extension (#4777 by @ikatyang)

.js.flow is the extension for Flow declaration files but previously we didnt recognize it. In Prettier 1.14, they should be picked up automatically so you dont need to add overrides for them in config files.

CSS/Less/SCSS

Handle newline between front-matter and comment correctly (#4701 by @evilebottnawi)

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

Support at-rule ends with right curly bracket (#4733 by @davidgomes)

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

Autolinks are formatted as their url in the prior version, which is fine. But theres a special case for email links that theyll 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>

Do not require space after markdown block language name (#4783 by @kachkaev)

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

Use language aliases to find parser for markdown codeblocks (#4734 by @ikatyang)

Previously, we used the language name and extensions to determine which parser to use for codeblock formatting, but we found that its 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 }
```

Preserve entity for encoded character if its code point is greater than U+FFFF (#4832 by @ikatyang)

The markdown parser we use (remark) parses every encoded character into a single AST node so that were able to restore the encoded character by detecting if the value in the AST node is in length of 1. But theres 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 wont be transformed into the literal character.

<!-- Input -->
&#x1F609;

<!-- Output (Prettier 1.13) -->
😉

<!-- Output (Prettier 1.14) -->
&#x1F609;

Vue

Support range format for Vue files (#4868 by @ikatyang)

Previously, range formatting was not available in Vue, but Prettier 1.14 adds support for it.

GraphQL

Preserve linebreak in non-block stringValue (#4808 by @ikatyang)

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