prettier: Inconsistency breaking assignments

For example,

aParticularlyLongAndObnoxiousNameForIllustrativePurposes = 
  anotherVeryLongNameForIllustrativePurposes;

formats as

aParticularlyLongAndObnoxiousNameForIllustrativePurposes = anotherVeryLongNameForIllustrativePurposes;

Similarly there is no break after the = in

aParticularlyLongAndObnoxiousNameForIllustrativePurposes =
  'a very long string for illustrative purposes'.length;

or

aParticularlyLongAndObnoxiousNameForIllustrativePurposes =
  anotherVeryLongNameForIllustrativePurposes();

although there is in

aParticularlyLongAndObnoxiousNameForIllustrativePurposes =
  anotherVeryLongNameForIllustrativePurposes.length;

and

aParticularlyLongAndObnoxiousNameForIllustrativePurposes =
  anotherVeryLongNameForIllustrativePurposes + 1;

I’d expect every one of these to break after the =, since otherwise line length exceeds 80 characters. (Though I thought it used to… is this an intentional, or a regression?)

Here’s a link containing all of these cases.

This also applies to variable declarations.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 25
  • Comments: 42 (15 by maintainers)

Commits related to this issue

Most upvoted comments

In general, I think any linebreak after an = or => should be a last resort - and that any other formatting, if possible, would be preferred.

@bradennapier if you have a proposal for a consistent way of fixing it, I think everyone would be interested!

sooooo is this broken forever? lol it makes projects unusable with prettier. i have print width to 80 and eslint max-len is at 100 and its not breaking a row that is 150 characters long…

Here is another case imo:

Prettier 1.13.7 Playground link

--parser typescript
--print-width 120
--tab-width 4

Input:

class foo {
  bar() {
  	const median = dates.length % 2 ? dates[half].getTime() : (dates[half - 1].getTime() + dates[half].getTime()) / 2.0;    
  }
}

Output:

class foo {
    bar() {
        const median =
            dates.length % 2 ? dates[half].getTime() : (dates[half - 1].getTime() + dates[half].getTime()) / 2.0;
    }
}

Expected behavior:

class foo {
    bar() {
        const median = dates.length % 2
            ? dates[half].getTime() 
            : (dates[half - 1].getTime() + dates[half].getTime()) / 2.0;
    }
}

2.3

Personally for a = b, I think you should almost never break a = b unless you can also break b… Though it may depend on the length of a.

for example, I find this to be a pretty useless change:

let string = 'something';
if (someCondition) {
    string = 'some really long string that goes over the line width limit and breaks up the line';
}

=>

let string = 'something';
if (someCondition) {
    string =
        'some really long string that goes over the line width limit and breaks up the line';
}

The shortness of a makes putting b on the next line look awkward and imbalanced. And as said earlier, this happens all the time in object property initialization and json files as well.

Towards actually fixing this - I think something like fill might be the right thing to do? (Assuming I am remembering how fill works.) As in, fill(group(left, '='), right).

The desired behavior would be:

  • If it’s impossible to fit the first atom (i.e. non-breakable component) of the RHS on the same line as LHS + =, break after the = before breaking the RHS.
  • If the RHS breaks but the above does not hold, don’t break after the =.
  • If the LHS + = does not fit on one line, break the LHS if possible, and otherwise just allow the line length to be exceeded. Do not break immediately before the = under any circumstances.

I think this handles most of the cases in this thread correctly, except the OP’s case in #2184.

Possibly there are some cases where you wouldn’t want to use fill and instead just allow breaking after the =, like x = a.b.

I found at least 3 cases which still having issues, I hope these can be also fixed. Appreciate for your help.

Sample code below can be found in the playground.

// Not breaks here
export class LongLongLongLongLongLongLongComponentA extends LongLongLongLongLongLongLongComponentB {
  
  @Effect()
  // Not breaks here
  selectSomethingQueryParam$: Observable<SelectSomeAction> = this.selectFirstSomething$.pipe(
    switchMap(() =>
      this.store$.pipe(
        select(getSomethingParamState),
        filterUndefined(),
        distinctUntilChanged(),
        skip(1),
        takeUntil(this.someElementStream$)
      )
    ),
    map(someElementId => new SelectSomeAction(someElementId))
  );
  
    constructor(
      @Inject(MAT_DIALOG_DATA)
      // Not breaks here
      public data: sharedModels.TheCoolestShinyComponentDialogData<sharedModels.MyFavouriteModel>,
      public dialogRef: MatDialogRef<TheCoolestShinyComponentDialogComponent>
    ) {}
  
}



@lydell I am sorry, I don’t mean any disrespect. Prettier is an amazing tool and this is the first issue I had with it. I am maintaining couple of OSS libraries myself so I know well how ungrateful “job” it can be. Even if I had some time to spare for helping out here, I would have no idea where to start as I am unfamiliar with how the whole thing works.

it’s a difficult problem and nobody has done the work trying to fix it yet

Based on the comment above it felt like it has a fairly straightforward solution. Apologies, if it’s not the case.

@FredyC Hi!

It’s kinda ridiculous of having this issue for 2 years now and waiting for the “brilliant” solution when at least “average” one already exists.

Why do you say this? Have we said something like that?

This issue is still open because it’s a difficult problem and nobody has done the work trying to fix it yet (other than posting suggestions in this thread). Prettier is run by volunteers, so people work on whatever they feel like.

A PR that improves the situation would be very much appreciated, even if it does not cover all cases.

It also happens in a jsx arrow function, something like this where i’d instead expect:

<div
  onClick={somethingLong => somethingLonger(
    abc,
    def,
    ghi
  )}
/>;

@RenaldasK We recommend using tslint-config-prettier to turn off all rules that conflict with Prettier.

@pbarbiero I think this error is the same as #1893