Skip to content

Releases: prettier/prettier

1.3.0

02 May 22:32
Compare
Choose a tag to compare

Facebook Adoption Update

The reason why I (@vjeux) embarked on this journey working on prettier has always been to get the entire Facebook codebase converted over. I would like to give an update on how it is going and what is the process to get there.

The first projects to adopt prettier were Jest, React and immutable-js. Those are small codebases in the order of hundreds of files that have their own infrastructure. There are a handful of people working on them full time.

Then, Oculus and Nuclide converted their codebase over. The scale is bigger with a few thousands of files and tens of full time contributors but looks pretty similar to the first projects. The conversions went in one big codemod and that's it.

Now, the entire Facebook codebase is way bigger than this and it's not feasible to just convert everything in one go and to convince everyone that their entire codebase is going to be reformatted under their feet. So we need to find a more incremental approach.

Scaling adoption

Running prettier on a piece of code is a pretty expensive operation, it makes your pull request look bad because of a lot of unrelated changes and it causes merge conflicts for all the outstanding pull requests. So once a file has been formatted, you should do everything to make sure it remains formatted.

  • When pretty-printing a file, add @format to the first block comment like @flow.
  • Have a lint rule with autofix that checks if the file is correctly pretty printed when @format is present.
    • When running Nuclide, it's going to show as an inline warning and have a fix button.
    • When sending a pull request, it's going to show the lint failing with a [Yn] prompt that you can just press enter.
  • Update the default code templates to add @format to the header.
  • When you run code formatting via cmd-shift-c inside of Nuclide, automatically insert the @format header.
  • Disable all the stylistic rules like max-len when @format is in the header.
  • Have script to run prettier through an entire folder with everything configured as a one line operation.
  • Have a good guide to help people that want to convert their codebase over with instructions and best practices.
  • When pushing a new release of prettier, also run it through all the files with @format in order to avoid getting warnings afterwards.
  • Add tracking for the number of files with @format over time.

We finally got all those things wired up 1.5 weeks ago and the reception has been insane. Many people from various teams converted their codebase to prettier on their own. As of today, 15% of Facebook codebase has been converted over!

When I started working on prettier, I had a hunch that people were hungry for tools to solve formatting. But I had no idea that once the tooling was in place, people would rush to convert their codebase over! This is great confirmation that this project is useful to people and not just a gimmicky tool.

TypeScript Support Progress

@despairblue, @azz and @JamesHenry have been hard at work around getting TypeScript supported by prettier as it's the top requested feature. 2000 out of 11000 files in the TypeScript test suite are not yet properly printed. You can follow progress on #1480 and do not hesitate to help out!

Flow

Add trailing commas on flow generics (#1381)

The --trailing-comma=all option is supposed to add trailing commas everywhere possible, but as an oversight we forgot to do it for flow generics.

// Before
type Errors = Immutable.Map<
  Ahohohhohohohohohohohohohohooh,
  Fbt | Immutable.Map<ErrorIndex, Fbt>
>;

// After
type Errors = Immutable.Map<
  Ahohohhohohohohohohohohohohooh,
  Fbt | Immutable.Map<ErrorIndex, Fbt>,
>;

Inline nullable in flow generics (#1426)

The phase after printing things correctly is to tweak the output to make it closer to the way people write code in practice. Inlining optional flow types is a small thing that makes a difference.

// Before
type Cursor = Promise<
  ?{
    newCursor?: number,
    formatted: string,
  }
>;

// After
type Cursor = Promise<?{
  newCursor?: number,
  formatted: string,
}>;

Allow flow declarations to break on StringLiteralTypeAnnotations (#1437)

We can always find more places to add breaks when things don't fit 80 columns. This time it's around declaring a type as a constant string.

// Before
export type AdamPlacementValidationSingleErrorKey = 'SOME_FANCY_TARGETS.GLOBAL_TARGET';

// After
export type AdamPlacementValidationSingleErrorKey =
  'SOME_FANCY_TARGETS.GLOBAL_TARGET';

Add space around = for flow generics default arguments (#1476)

Another example of small thing where we can improve the display of flow code. For function default arguments we put a space around = but didn't around flow generics.

// Before
class PolyDefault<T=string> {}

// After
class PolyDefault<T = string> {}

Don't break for unparenthesised single argument flow function (#1452)

I'm trying to figure out something to write here, but ... it just looks weird!

// Before
const selectorByPath:
  Path
 => SomethingSelector<
  SomethingUEditorContextType,
  SomethingUEditorContextType,
  SomethingBulkValue<string>
> = memoizeWithArgs(/* ... */)

// After
const selectorByPath: Path => SomethingSelector<
  SomethingUEditorContextType,
  SomethingUEditorContextType,
  SomethingBulkValue<string>
> = memoizeWithArgs(/* ... */);

Fix optional flow parenthesis (#1357)

We were a bit too lenient around parenthesis for optional flow types. In one case in the entire Facebook codebase, it generated code with different semantics. As part of this fix, we hardened the list of types that can be written without parenthesis.

// Before
type X = ?(number, number) => number => void;

// After
type X = (?(number, number) => number) => void;

Skip trailing commas with FlowShorthandWithOneArg (#1364)

It is a parse error to add a trailing comma without parenthesis for arguments of arrow function types. We found one case in Facebook codebase when this happened, it's a very rare occurrence.

// Before
type IdeConnectionFactory =
  child_process$ChildProcess,
  => FlowIDEConnection = defaultIDEConnectionFactory;

// After
type IdeConnectionFactory =
  child_process$ChildProcess
  => FlowIDEConnection = defaultIDEConnectionFactory;

Reorder flow object props (#1451)

This one is an example where the way the AST is structured is not our favor. Instead of having a list of elements inside of a type, the AST is structured in a way where normal keys and array keys each have their own group. In order to restore the initial order, we're now reading from the original source :(

// Before
type Foo = {
  [key: string]: void,
  alpha: "hello",
  beta: 10
};

// After
type Foo = {
  alpha: 'hello',
  [key: string]: void,
  beta: 10
}

Template Literal

Proper indentation for template literals (#1385)

A long standing issue with template literals and prettier is around the indentation of code inside of ${}. It used to be the indentation of the backtick but turned out to give poor results. Instead people tend to use the indent of the ${. We changed this behavior and it magically made GraphQL queries look pretty!

// Before
Relay.createContainer({
  nodes: ({ solution_type, time_frame }) => Relay.QL`
    fragment {
      __typename
      ${OptimalSolutionsSection.getFragment("node", {
    solution_type,
    time_frame
  })}
    }
  `
})
// After
Relay.createContainer({
  nodes: ({ solution_type, time_frame }) => Relay.QL`
    fragment {
      __typename
      ${OptimalSolutionsSection.getFragment("node", {
        solution_type,
        time_frame
      })}
    }
  `
})

Do not indent calls with a single template literal argument (#873)

Template literals are very hard to deal with for a pretty printer because the spaces inside are meaningful so you can't re-indent them. We didn't know what to do for a call with a single template literal so we didn't do anything, but we kept receiving reports of people saying that prettier indented it the wrong way, so we are now inlining them. Fingers crossed it is going to cover most use cases.

// Before
insertRule(
  `*, *:before, *:after {
    box-sizing: inherit;
  }`
);

// After
insertRule(`*, *:before, *:after {
  box-sizing: inherit;
}`);

Fix windows line ending on template literals (#1439)

We manipulate line endings in a lot of places in prettier and took great care of handling both \n and \r\n except for template literals where we forgot. Now this is fixed!

// Before
const aLongString = `

Line 1

Line 2

Line 3

`;

// After
const aLongString = `
Line 1
Line 2
Line 3
`;

Inline template literals as arrow body (#1485)

We already inline template literals that are tagged (eg graphql`query` ) but didn't for plain template literals. For the anecdote, it turns out the code was supposed to support it but it was using TemplateElement instead of TemplateLiteral :(

// Before
const inlineStore = preloadedState =>
  `
  <script>
    window.preloadedState = ${JSON.stringify(preloadedState).replace(/</g, '\\u003c')}
  </script>
`

// After
const inlineStore = preloadedState => `
  <script>
    window.preloadedState = ${JSON.stringify(preloadedState).replace(/</g, '\\u003c')}
  </script>
`

Ternaries

Add parenthesis for unusual nested ternaries (#1386)

While working on printing nested ternaries, everyo...

Read more

1.2.0

19 Apr 18:36
Compare
Choose a tag to compare

1.0 is not the end of prettier, we're going to continue to work on the long tail of formatting issues in order to make it an awesome JavaScript code formatter. You should expect minor version releases like this one to change small things and edge cases but nothing major or controversial.

Format

Do not print the sub-tree when using prettier-ignore (#1286)

Bail when traversing === groups (#1294)

A regression was introduced in 1.0 where deeply nested functions like this would trigger an exponential behavior and no longer complete in a reasonable time. We introduced a mitigation such that it's not instant but at least completes in a reasonable amount of time.

someObject.someFunction().then(function () {
    return someObject.someFunction().then(function () {
        return someObject.someFunction().then(function () {
            return someObject.someFunction().then(function () {
                return someObject.someFunction().then(function () {
                });
            });
        });
    });
});

Break if () if conditional inside breaks (#1344)

prettier was sometimes breaking inside of an if condition as it didn't fit 80 columns but would print all the conditions in a single line. This was very weird looking. Now if the if break, prettier will also break the conditions.

// Before
if (
  this.hasPlugin("dynamicImports") && this.lookahead().type === tt.parenLeft
) {

// After
if (
  this.hasPlugin("dynamicImports") &&
  this.lookahead().type === tt.parenLeft
) {

Avoid breaking arguments for last arg expansion (#1305)

A long-standing issue around last argument expansion and complex arguments has been fixed, it no longer looks crazy bad.

// Before
manageChildren: jest.fn(function manageChildren(parentTag, moveFromIndices = [
], moveToIndices = [], addChildReactTags = [], addAtIndices = [
], removeAtIndices = []) {

// After
manageChildren: jest.fn(function manageChildren(
  parentTag,
  moveFromIndices = [],
  moveToIndices = [],
  addChildReactTags = [],
  addAtIndices = [],
  removeAtIndices = []
) {

Add parentheses for assignment as body of arrow (#1326)

We're fine tuning when to add parenthesis in order to improve understanding of the code. This time, we're adding it to assignment inside of arrow functions. Please open up issues if you think that there should be parenthesis and prettier doesn't put them.

// Before
() => foo = bar + 2;

// After
() => (foo = bar + 2);

Improve regex printing (#1341)

Flow and Babylon were inconsistent in how they printed escapes and flags. Now the escapes are untouched compared to the original ones and the flags are sorted.

// Before
/[\/]\/\u0aBc/mgi;

// After
/[/]\/\u0aBc/gim;

Fix arrow function parenthesis with comments in flow (#1339)

With the Flow parser, prettier didn't add parenthesis for single argument functions with a comment.

// Before
call(/*object*/ row => {});

// After
call((/*object*/ row) => {});

Don't inline paren at right of arguments (#1345)

We incorrectly put a comment at the right of arguments inside of the argument list.

// Before
f(/* ... */) {}

// After
f() /* ... */ {}

Fix template literal comments (#1296)

Comments inside of template literals would crash in some conditions and be inserted in the wrong ${}, no more :)

// Before
stdin: TypeError: Cannot read property 'comments' of undefined

// After
`
(?:${escapeChar}[\\S\\s]|(?:(?!${// Using `XRegExp.union` safely rewrites backreferences in `left` and `right`.
// Intentionally not passing `basicFlags` to `XRegExp.union` since any syntax
// transformation resulting from those flags was already applied to `left` and
// `right` when they were passed through the XRegExp constructor above.
XRegExp.union([left, right], '', {conjunction: 'or'}).source})[^${escapeChar}])+)+
`

Fix isPreviousLineEmpty on Windows (#1263)

Empty lines were not properly preserved for switch case on windows.

// Before
switch (a) {
  case x:

  case y:
    call();
}

// After
switch (a) {
  case x:
  case y:
    call();
}

CLI

Skip globbing filenames with node-glob when the filename is not a glob (#1307)

If you run prettier file.js and file.js doesn't exist, it's going to throw an exception instead of silently doing nothing.

Write out change CLI changes synchronously (#1292)

There was a race condition when you did ctrl-c to stop the process where it could delete files. Now we write files synchronously so it doesn't anymore.

1.0.0

28 May 03:53
Compare
Choose a tag to compare