Js-beautify: Option to preserve or inline "short objects" on a single line

Created on 14 Aug 2013  ·  109Comments  ·  Source: beautify-web/js-beautify

Typically the JS Beautifier expands all JS object declarations into multiple lines, each line having a key value pair. However, this is overly verbose for many situations (e.g. short objects which could easily fit on a single line).

Additional details found here: https://github.com/einars/js-beautify/pull/55

enhancement

Most helpful comment

For people like me coming here looking for a way to make it work: it works and can be enabled with the options in .jsbeautifyrc

   "brace_style": "collapse-preserve-inline"

All 109 comments

+1 ... at least one propert object could stay on single line so c1[key] = { $exists: true }; would not change to

                c1[key] = {
                    $exists: true
                };

+1

Popular request. :smile:

The old pull request of for this was done before we had line wrapping. Having the line wrap should make it easier.

We do detect when we are inside an object declaration, so that's not bad, but we detect it late (see #200), so it may involve some back tracking to fix up an expanded object.

I am all for this but I have a question. What if an object literal has exactly one property which in itself is an object literal with exactly one property? This could be repeated several times. In the example I have below I would actually prefer the code to be formatted on one line. Others may disagree but I think it is an important aspect to consider in this.

This could be taken to extremes where the code must be wrapped due to line length but I do have cases in my code where:

//I prefer this...
{ foo : { bar : { baz : 42 } } }

//... over this.
{
    foo : {
        bar : {
            baz : 42
        }
    }
}

@TheLudd I totally agree and was going to suggest this myself. Possibly a depth option as well. There is a limit to how readable that is after some levels deep. I would say what you have there would be the max default.

@mokkabonna Good idea about the depth option. That eliminates some ambiguity of how code like this should be formatted. If it is doable...

If not depth, maybe limit it by length... say it wraps after 80 chars. Not as elegant as depth but whatever can be doable quickly.

+1

I prefer the idea of length. If it can all fit in the width of the window, let it.

Strong support for this. Added to v1.5.0.

:clap::clap::clap::clap:

Is it also gonna preserve single line statements like this?

if(someCondition) { return something; }

That is as spec/implementation decision. It seems possible, but might not be a good idea to join them together.

Agreed. Not sure how you want to track it though, maybe another issue "Preserve short expressions/statements on single line"?

Sure, and note that it is related to this issue.

FYI, This is basically another version #114 . One of the oldest open issues.

Any updates on this? js-beautify is one of the best formatters out there except for this remaining issue.

I think this is the single reason I'm not running js beautifier on save.

+1

As much as I want to do this in 1.5.0, I'm going to have to punt it to 1.5.2.

There are a a large number of changes already in 1.5.0, and this is a significant feature that is going to take some iterating and feedback to land cleanly.

It is certainly the highest priority enhancement for 1.5.2.

:+1: I see 1.5.1 was released yesterday. Did this make it in? If so, what's the option?

Updated my comment above.

Ok thanks. Will look for it in the next release then.

:+1:

+1

Hey, I just found out about jsbeautify and set it up with Sublime Text 3. It rocks!! And I, too, ran into this and searched the web, and found this discussion. Glad to hear it's coming in 1.5.2.

It's been almost 5 months now since the last comment about 1.5.2 ... what's the ETA? Would love to have var obj = { one: property } stay on one line :) :)

ETA is when someone does it. That will likely be me, some time in the next month.

Awesome!!! Great to know

On Sep 17, 2014, at 11:49 PM, Liam Newman [email protected] wrote:

ETA is when someone does it. That will likely be me, some time in the next month.


Reply to this email directly or view it on GitHub.

I'm going to have to push this to v1.6.0.

I have done significant work (as noted in #530) towards enabling this feature. but it is frankly still to big an undertaking to make it into this release.

Wow...

Just reading some of the ECMA script spec and open bugs in your github this
seems huge!

Luckily in my use case, I usually only need to beautify my JS once per file.

I created a second set of simple regex find and replace patterns that auto
run when I save my file, and I usually never need to run beautify again on
that file.

If I ever do, for some reason, it's only a few extra seconds to manually
restore broken up one-line ifs or object literals back to one line. (no I
don't have a regex find + replace for those, lol)

On Sunday, September 28, 2014, Liam Newman [email protected] wrote:

I'm going to have to push this to v1.6.0.

I have done significant work (as noted in #530
https://github.com/beautify-web/js-beautify/pull/530) towards enabling
this feature. but it is frankly still to big an undertaking to make it into
this release.


Reply to this email directly or view it on GitHub
https://github.com/beautify-web/js-beautify/issues/315#issuecomment-57132532
.

:+1: I'm very excited about this feature :)

+1 I wish it could be available!

+1 - Need this so we can beautify on save everywhere

+1

:+1:

+1 - also not using with pre-save because of this

:+1:

Also, Escodegen does this correctly, it's code might be the source of inspiration:

var esprima = require("esprima"),
    esgen = require("escodegen").generate;

console.log(esgen(esprima.parse("var a = {code: 'code'}")));
console.log(esgen(esprima.parse("var a = {code: 'code', more: 'code'}")));

@bitwiseman
This problem may not be solvable for an arbitrary amount of nesting (e.g., really large amount of nesting) since the language corresponding to this nesting is nonregular but perhaps you can assume a limit for practical purposes (e.g., at most level-10 nesting or using the file size to determine a reasonable nesting limit)

+1 for this request.

It is a way too verbose to split for example this

view.on('post', {action: 'removeTask'}, function(next) {

to multiple lines.

+1

Is there any new ETA?

:+1:

We need this!!

:+1:

:+1:

:+1:

+1

While this feature not implemented, I use regex in my own run script somewhere about here like pretty = pretty.replace(/{([^{}]*?)}/g, function(s, p) { return (s.length < 100 && !/;/.test(p)) ? s.replace(/\n\s*/g, ' ') : s })
May be it will useful somebody.

@aves84 can't get it to work.. But you made me take a look at the source code instead of just waiting around now so thank you very much :D

@schoening perhaps I'm confusing wrote, the line should be added after "beautify", not instead of. Now I tried to change this particular script:

var pretty = beautify[fileType](code, config);
if (fileType == 'js') pretty = pretty.replace(/{([^{}]*?)}/g, function(s, p) {
            return (s.length < 100 && !/;/.test(p)) ? s.replace(/\n\s*/g, ' ') : s
        });

And it works properly.

@aves84, nah that I did understand, it made sense. I am on Linux Mint and I am browsing this folder / changing this file:
/home/username/.config/sublime-text-3/Packages/HTML-CSS-JS Prettify/scripts/node_modules/js-beautify/js/lib/cli.js

Changing this function:

function makePretty( code, config, outfile, callback ) {
  try {
    var fileType = getOutputType( outfile, config.type );
    var pretty = beautify[ fileType ]( code, config );
    if ( fileType == 'js' ) pretty = pretty.replace( /{([^{}]*?)}/g, function ( s, p ) {
      return ( s.length < 100 && !/;/.test( p ) ) ? s.replace( /\n\s*/g, ' ' ) : s
    } );

    callback( null, pretty, outfile, config );
  } catch ( ex ) {
    callback( ex );
  }

}

And then when I try something like this still gets the object split up:

var foo = {
  bar: "Hello world!"
};

Sorry for all the questioning mate.

@schoening most likely the extension don't uses cli.js and replaces it with its own file with require('js-beautify'). In Brackets I made changes to ~/.config/Brackets/extensions/user/hirse.beautify/main.js
Or you can try edit https://github.com/beautify-web/js-beautify/blob/master/js/lib/beautify.js#L369 for example.

I think sublime uses the python version.

@mokkabonna - it depends. Some sublime plugins wrap node.js calls, other use python directly.

:+1: plusoneplusone

+1. Is there an such option for now?

:+1: looking forward to it, thanks.

:+1:

@FrankFang It was pushed back to 1.6.0 which hasn't landed yet
@aves84 Your trick breaks/collapses functions/ for-of-loops/if statements sometimes

for (var data of columnData) { ctx.drawImage(data.img, data.options.x, data.options.y) }

img.onerror = function() { reject() }

if (index >= rows.length) { return }

@dani-h Well, this method is far from ideal, it relies on the semicolon in the definition of short objects and code blocks: if there are no semicolons and the number of characters is less than 100, the line breaks are removed. It even will cause errors in code that uses javascript's automatic semicolon insertion.

:+1:

:+1: Looking forward to that.

+1 ... i'd love to see this make it in soon.

it's the only reason that we're not able to use this plugin at this point.

+1

+1

+1 on this, blocks me from using this. Even an option to just disable this would help!

+1 +1 +1

+1

+1 and a thanks for all your hard work on this!

+1 Right now, beautifying literally doubles my code into a horrible ugly mess because of this issue. It's quite a crippling bug in some circumstances. Especially since I use js-beautify as a psedo-linter (If indents aren't right, I missed a bracket somewhere.) My muscle memory turns my beautiful unit-tests into a 10 minute task of fixing all my object literals.

js-beautify -pX <filename> | perl -0777 -i -pe 's/\{\s*([^{}]{30,180}?)\s*\}/\{ $1 \}/mg'

this line of code will fold back the unfolded things between 30 to 180 characters length without embedded blocks. probably it can be useful for some people.

+1 and a thanks for all your hard work on this!

+1. Three lines instead of one is too much.

I hope this can be done. :+1:

It is the only behavior of js-beautify that makes me displeased. :sweat_smile:

@vekat - As you can see, you're not alone. :smile:

@nels-o - totally different thing, sorry. Template braces like {{ and }} are parsed completely differently than javascript braces. Besides which, when inlining objects they would look like { a: { b: {} } } }.

(WRT template bits such as {{}} and {{!}} ) Is it? If they're in script tags those seem to be formatted. For example this:

image

becomes this after running the prettifier.

image

Ah :) Thanks @bitwiseman

Perhaps what I should have said is, _if_ they were to be handled they _would_ be handled completely separately. :smile: Still, sorry.

+1. Any idea of an ETA? This is making me very sad :(

+1. Would love that feature too! Unfortunately I don't have time actually to help somehow :(

+1, we're all still patiently waiting. This will be an awesome addition

The change I made doesn't really understand "short" objects - it just tries to preserve the objects that the input provides that have no newlines in them. Once line-wrapping occurs, the object flips to "collapse" formatting. So, this is still an imperfect solution, but an improvement.

If this works as I understood, I think this is already a huge improvement to the current situation. In most cases, this is sufficient.

+1

+1 hope this is done soon

@NerdPad - it _is_ done.

Can we use it with Brackets? o_O

@C-Weinstein - Perhaps you could open a new issue with example of input and desired output?

For people like me coming here looking for a way to make it work: it works and can be enabled with the options in .jsbeautifyrc

   "brace_style": "collapse-preserve-inline"

Unfortunately, that didn't work :( But thanks for trying.

@Ceyaje - How didn't work? Where didn't it work? What were your inputs and outputs?

Input was

var q = { x: "a", b: "c" }

It "beautifies" to

var q = {
    x: "a",
    b: "c"
}

@Ceyaje you need set option "brace-style" to "collapse-preserve-inline"

@aves84 - thanks! Continuing discussion in #995.

@aves84 I did that. I was saying it was still happening, so I opened #995 but I'm using Brackets and wasn't aware that it was different code

@Kutsan - Please open a new issue.

I could not find expand-preserve-inline option with html file in atom. I write javascript in both html file and js file.

Place "preserve-inline" after the setting you want to use (collapse, expand, etc.)

"brace_style": "collapse,preserve-inline"

https://i.gyazo.com/2831254cc47d08c879c7d36a7f1a30d0.png

The above happens, however my brace style is collapse-preserve-inline. I read the full thread, I don't believe I'm doing anything incorrectly. Already restarted Atom, just in case, nothing.

Any update on this? collapse-preserve-inline still expands the arrow function onto multiple lines.

@grandslammer - Please take a look at open issues that include the word "arrow". If you don't see an issue that covers what you're talking about, please open a new issue.

I'm sorry: Original topic is "Option to preserve or inline "short objects" on a single line #315?
this discussion has drifted many way, can PLEASE ANYONE point the correct settings for latest version of js-beautify to achieve requested formatting ? Thanx

@ainthek it's "brace_style": "collapse,preserve-inline"

How about the settings in vs code latest version to fix this issue?

In vs code 1.20.1 , i cannot get the style "brace_style": "expand,preserve-inline", to work.

Input :

const
    {
        dialog
    } = require("electron").remote;

Output (After selecting this area and clicking F1 ---> Beautify Selection) : NO CHANGE :(

Expected Output : const {dialog} = require("electron").remote;

P.S ----> the distorted input was obtained after Beautifying the whole file. Nobody writes code in that distorted way :P

For vscode, adding below in user settings worked for me:
"beautify.config": { "brace_style": "collapse,preserve-inline" }

Thank you for the support guys.

@sulkhanp - Please file an issue describing the behavior.

@vipingoel 's solution works!
Why is this option only works in vscode user preference, not in my .jsbeautifyrc file?

"brace_style": "expand,preserve-inline" doesn't work.

expect behavior:

  let $w = $(window),  w = $w.width(),  h = $w.height();
  constructor()
  {
    this.setupData(); this.setupMenus(); this.setupUser(); this.setupUI();
  }

current behavior:

    let $w = $(window),
      w = $w.width(),
      h = $w.height();

  constructor()
  {
    this.setupData();
    this.setupMenus();
    this.setupUser();
    this.setupUI();
  }

@SiJinmin these are not short objects and therefore not related to this issue.

@vipingoel It works. I'm really happy. Thanks!!!

Was this page helpful?
0 / 5 - 0 ratings