Live data from Hacker News

A Prettier JavaScript Formatter

jlongster.com

121–130 of 159 posts

Re: A Prettier JavaScript Formatter

#121
post #117

Earlier quoted context omitted.

> Why does the formatter need to solve this and not the editor? The editor has more information available to it, like the present screen space. Because making the line wrapping nice requires deep syntax-aware editor integration. Most languages try to be at least somewhat plain-text-editor-friendly.

> Because making the line wrapping nice requires deep syntax-aware editor integration. Why does it need to be syntax aware?

Think what happens when you break a line comment (or a string, in languages where it can't span several lines). And that's an easy example at that.

Re: A Prettier JavaScript Formatter

#122
post #14

Nice attempt, but currently wrong. For example, it pretty-formats this code: function makeComponent() { return /*test*/ { a: 1 }; } into function makeComponent() { return /*test*/ { a: 1 }; } From my own experience writing a formatter, comments are very difficult (if one wants to preserve them). I guess the author should reparse the generated code to ensure the AST hasn't changed.

I know this isn't really practical, but as a rule you shouldn't mix comments and code. Comments should be above any function definitions for this and many other obvious reasons. Removing inline comments seems like a reasonable default for a project like this, since those adopting it have already ceded some amount of control over the way their code is structured.

Re: A Prettier JavaScript Formatter

#123
post #121
post #117

Earlier quoted context omitted.

> Because making the line wrapping nice requires deep syntax-aware editor integration. Why does it need to be syntax aware?

Think what happens when you break a line comment (or a string, in languages where it can't span several lines). And that's an easy example at that.

What happens? Nothing as far as I'm aware. The code is still one line.

Re: A Prettier JavaScript Formatter

#124

After using Elm and the elm-format package in Emacs for the last few weeks I can say that not having to format the source and just letting your editor do it for you on save or via a command is so very nice. This is a trend that I feel is going to catch on across any language that can support it. It makes trivial decisions and arguments about formatting a thing of the past.

Gofmt was the catalyst for me. I do it with StandardJS in Visual Studio Code on save automatically, I won't waste my time manually formatting code - or caring about it - again. Personal code formatting preferences is a problem. Devs should just let go of it, once it applies automatically your preferences quickly change. You can even wire up GitHub etc repos to automatically reject pull requests that add pointless for…

Can you point me to more information regarding Github and rejecting pull requests that are strictly formatting changes? Sounds interesting...

Re: A Prettier JavaScript Formatter

#125
post #68

Earlier quoted context omitted.

i hate the output of elm-format, though :( it's very wasteful of vertical space.

Tangential question: Why do Haskell and Elm format lists like this? type alias Circle = { x : Float , y : Float , radius : Float } ...and not like this: type alias Circle = { x : Float, y : Float, radius : Float } ...? The first makes me shudder with revulsion every time I see it --- that's not where commas go , dammit --- and there must be a reason, which I've never been able to figure out. The Elm style guide menti…

Putting he comma at the start of the line allows for deleting any line without having to edit another (unless it's the first in which case the missing brace is more obvious IMHO.

The trailing comma is more easily missed I'd say.

Re: A Prettier JavaScript Formatter

#126
post #14

Nice attempt, but currently wrong. For example, it pretty-formats this code: function makeComponent() { return /*test*/ { a: 1 }; } into function makeComponent() { return /*test*/ { a: 1 }; } From my own experience writing a formatter, comments are very difficult (if one wants to preserve them). I guess the author should reparse the generated code to ensure the AST hasn't changed.

I've found another issue where it just removes comments entirely inside an otherwise empty block. function doSomething() : int { return myPromise .then(() => { // ...do thing /* what */ }) .catch(() => { // ..do other thing /* the heck */ }); } becomes function doSomething(): int { return myPromise .then(() => {}) .catch(() => {}); } Still a very nice pretty printer, though.

I used Recast on a codebase at work to migrate to a new code style, and I ran into a long tail of issues with preserving comments that looked like they would require some significant work to fix. I know the author of Recast (Hi Ben) and corresponded with him a little bit about it at the time.

Re: A Prettier JavaScript Formatter

#128

My team recently ganged up on me to tell me my line spacing was f*cked. Upon reflection, it seems that as I'm writing code I group lines into 'working well - one line, 'not sure - two lines', 'probably will change - lots of space', 'hey look at me! - off by itself'. Apparently, this unconcious invisible system drives others crazy. Developers are so picky! ;-) We've actually got a bunch of automatic eslint rules, but…

There's a eslint rule for multiple blank lines

Re: A Prettier JavaScript Formatter

#129
gofmt — the official formatter of the Go language — made a very wise choice for its formatting strategy. I think it's something other tools can learn from.

gofmt will fix indentation, spacing, and so on, but it will generally preserve structure. For example, this:

  a:=Foo{value:42}
becomes, of course:

  a := Foo{value: 42}
But! This:

  a:=Foo{
  value:42,
  }
becomes:

  a := Foo{
    value: 42,
  }
That's because gofmt can't really pretend to know that it knows better than the developer here. Sometimes code does need to be loose (like in a DSL or a big declaration, or a test (which must be readable), or similar). Sometimes it should be compact.

This means you never have to fight gofmt. Never once have I disagreed with its decisions.

gofmt works this way because its ruleset isn't exhaustive; it says that, yes, an indent must happen after a hanging "{", but the ruleset doesn't say that a line break must happen. If there's a line break, let's stick with it.

Prettier seems to have a strict normalization approach: AST goes in, canonical form goes out. For example, I tried this fictional piece of code:

    performAction({
      type: "thing",
      value: 42,
      owner: user, 
      bucket: root,
      path: p
    });
It's turned into a much less readable blob because it happens to fit on a single line:

    performAction({type: "thing", value: 42, owner: user, bucket: root, path: p});
Unfortunately, in every instance where I indent the code in this manner, it's for a specific reason. I wanted it on separate lines; the fact that it happens to fit on a single line doesn't matter at all. Prettier overruled my carefully indented code.

I often format code in a specific way for regularity: Every chunk in a block should have the same format, because each chunk is an instance of the same pattern. For example, I might have something like:

  const RULES = [
    {
      type: "boost",
      fn: node => increaseImportance(node),
      weight: 0.5,
      dependencies: ["priority", "rotation"]
    },
    {
      type: "eliminate",
      fn: node => nil
    },
    // ... lots of rules ...
  ]
Prettier's output generates inconsistency:

    const RULES = [
      {
        type: "boost",
        fn: node => increaseImportance(node),
        weight: 0.5,
        dependencies: ["priority", "rotation"]
      },
      {type: "eliminate", fn: node => nil}
    ];
To quote the immortal Trump: No way!

Maybe one could use some advanced heuristics to find an optimal balance between width vs. indentation vs. compactness; for example, in the above array, a clever formatter could see that it's an array of object literals, which means that it should prioritize regularity over compactness. If it's an array of something simple (like numbers, but not numbers with trailing comments), it can go compact. Maybe.

I don't use Prettier at the moment, but I know the strictness would drive me nuts. I predict that Prettier is going to cause a lot of frustration and heated discussion as a result of the one-size-fits-all approach. I don't think a canonical form for everything even makes sense; people need regularity (and no surprises), but not at the cost of readability.

Post reply on HN