prettier: No line breaks for very long arrays?

Just wanted to kick off a discussion about how Prettier prints long arrays. 😊 I think in some cases it might make sense to have Prettier format a little differently.

Let’s take the following as an example:

const userIds = [
  941,
  722,
  312,
  933,
  841,
  166,
  843,
  978,
  436,
  687,
  269,
  573,
  913,
  873,
  748,
  354,
  153,
  181,
  947,
  563,
  324,
  952,
  885,
  911,
  698,
  248,
  764,
  431,
  811,
  344,
  855,
  430,
  396,
  981,
  594,
  131,
  489,
  552,
  116,
  833,
  521,
  252,
  503,
  540,
  893,
  736,
  969,
  145,
  925,
  417,
  344,
  108,
  161,
  777,
  971,
  159,
  158,
  908,
  511,
  876,
  768,
  284,
  640,
  309,
  651,
  292,
  898,
  284,
  201,
  506,
  654,
  840,
  334,
  246,
  376,
  398,
  714,
  134,
  435,
  181,
  980,
  594,
  396,
  100,
  743,
  812,
  583,
  622,
  800,
  310,
  111,
  537,
  751,
  920,
  872,
  700,
  702,
  655,
  515,
  298
];

Lately, I find myself inserting // prettier-ignore above arrays like this and adjusting the formatting manually to something like this:

// prettier-ignore
const userIds = [
  941, 722, 312, 933, 841, 166, 843, 978, 436, 687, 269, 573, 913, 873, 748,
  354, 153, 181, 947, 563, 324, 952, 885, 911, 698, 248, 764, 431, 811, 344,
  855, 430, 396, 981, 594, 131, 489, 552, 116, 833, 521, 252, 503, 540, 893,
  736, 969, 145, 925, 417, 344, 108, 161, 777, 971, 159, 158, 908, 511, 876,
  768, 284, 640, 309, 651, 292, 898, 284, 201, 506, 654, 840, 334, 246, 376,
  398, 714, 134, 435, 181, 980, 594, 396, 100, 743, 812, 583, 622, 800, 310,
  111, 537, 751, 920, 872, 700, 702, 655, 515, 298
];

I think that in cases like this, it doesn’t really help to have each item on a new line. It just makes the code harder to scroll through and harder to read. Line breaks definitely make sense for shorter arrays, but there could be some sort of a thresh-hold after which we could format differently.

What do you think?

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 54
  • Comments: 41 (16 by maintainers)

Most upvoted comments

@j-f1

I am into Competitive programming. I have solved 316 questions by now, check here - https://leetcode.com/pgmreddy/ Almost every question (more than 290+ questions) has large data input as test case. This is MUST simply because - Algorithms crack when we give large inputs, they segfault due to not enough memory, perform too slow in speed – These algo issues can only be seen with large inputs – Large inputs vary from 100 elements (combinatoric problems like factorial are even less like 15), but most of the most are a minimum of a 50,000 elements.

  • Why do we need to store large test cases?
  • Because algorithm changes - For example, I tried X algorithm passes all inputs less than 15, then I put in 1000 elements, it passes, (here 1 full day might be gone), now I put 50,000 to 100,000 elements easily, to see its performance in extremes it fails. Now I need to store these failed input some where. If I start creating external files, I am going to die, I have to maintain many. I have 1 array for all tests, the last test is the large output. Night comes in, I sleep. Next day, I change the algorithm because large input failed, now, it’s possible that new algo does not work for small inputs, when it does, I have to run large inputs too. Now while doing all these, I don’t care about tests (once written, I wont touch, they only grow, never reduce), I only care about algorithms, I might add some more large test cases now. HERE is the problem, I have to scroll all the way down. between tests without prettier-ignore. With prettier-ignore I can’t scroll the input to the end of the Editor, Editors hang / go very very slow, you can check the Notepad++, some editors only show “
” which is useless. Only the 3rd solution which is format by line-width helps here, a few pages scroll will give what are some end values at test case, overall summary what is the input is.

I strive hard that my solution passes on 1st attempt, I have not got a single error in last 54 problems submitted. If we want to be the best, we need to use the best tools, prettier is best tool, but with time data grows, prettier needs to catch up as we grow with time. Otherwise prettier won’t be in the good looks of best so we must improve the prettier to continue to be the best.

I am algorithm guy, so I can write in bits and pieces of code for this part of change. Though I can’t go thru a lengthy process, I can write an algo quickly, send a code review on a branch, etc. However, the owners need to guide and take ownership of review, improvements. If we have doubt, let it be an experimental feature. A feature that can be enabled via settings. We can have "array width" only for line, this is even better. Someone can always match "line width" to "array width" I am in, always. I love the tool.

  • How often? - Easily, 95+ % of the time. This is an everyday problem.
  • How many people may get affected? Coming from a competitive programming website 80 K to 2 M, per day. Why? JavaScript is # 1 now - https://redmonk.com/sogrady/2020/07/27/language-rankings-6-20/
  • prettier-ignore wont make sense, editors hang, crash, put a “
”, scrolling issues, other
  • Separate data file wont help, there will be too many files, multiple per problem to say the least, tests will be scattered, it is similar to another DLL hell, and others.

Let’s work together, have “array width” like “line width”, it a real problem, everyday. I am in to contribute, see above.

Given that these occur very rarely in any given codebase, I wonder if the implementation cost for this is worth the savings of one line before the array.

If you have many large arrays in your codebase, why not extract them to a config file?

What about:

// prettier-mode matrix
const userIds = [
  7234932941, 7234932722, 7234932312, 7234932933, 7234932841, 7234932166,
  7234932843, 7234932978, 7234932436, 7234932687, 7234932269, 7234932573,
  7234932913, 7234932873, 7234932748, 7234932354, 7234932153, 7234932181,
  7234932947, 7234932563, 7234932324, 7234932952, 7234932885, 7234932911,
  7234932698, 7234932248, 7234932764, 7234932431, 7234932811, 7234932344,
  7234932855, 7234932430, 7234932396, 7234932981, 7234932594, 7234932131,
  7234932489, 7234932552, 7234932116, 7234932833, 7234932521, 7234932252,
  7234932503, 7234932540, 7234932893, 7234932736, 7234932969, 7234932145,
  7234932925, 7234932417, 7234932344, 7234932108, 7234932161, 7234932777,
  7234932971, 7234932159, 7234932158, 7234932908, 7234932511, 7234932876,
  7234932768, 7234932284, 7234932640, 7234932309, 7234932651, 7234932292,
  7234932898, 7234932284, 7234932201, 7234932506, 7234932654, 7234932840,
  7234932334, 7234932246, 7234932376, 7234932398, 7234932714, 7234932134,
  7234932435, 7234932181, 7234932980, 7234932594, 7234932396, 7234932100,
  7234932743, 7234932812, 7234932583, 7234932622, 7234932800, 7234932310,
  7234932111, 7234932537, 7234932751, 7234932920, 7234932872, 7234932700,
  7234932702, 7234932655, 7234932515, 7234932298
];

Just idea.

Proposal: Arrays containing only numbers (< X characters) or only strings (length <= 3) will wrap as shown in your second example

Thanks. I hope you are saying about below command of yours, from all the chat msgs above. ( If so, all good, let below command be last msg of this thread for easy retrieval, thank you for your contribution @thorn0 )

npm install thorn0/prettier#num-arrays

Well, these are common in my unittest code. In fact, these cases also reproduce on short arrays:

expect([0, 1, false, 2, '', 3, NaN]::it.compact()::it.toArray()).toEqual([
  1,
  2,
  3
])

expect([1, [2, [3, [4]], 5]]::it.flatDeep()::it.toArray()).toEqual([
  1,
  2,
  3,
  4,
  5
])

These arrays are short, but because printWidth is exceeded, the arrays are printed splitting every item per line, which looks ugly.

I proposal that if an array itself does not exceed printWidth, it can be printed on the next line like this:

expect([0, 1, false, 2, '', 3, NaN]::it.compact()::it.toArray()).toEqual(
  [1, 2, 3]
)

expect([1, [2, [3, [4]], 5]]::it.flatDeep()::it.toArray()).toEqual(
  [1, 2, 3, 4, 5]
)

@manoharreddyporeddy Nope, no ETA. As I wrote, if you urgently need it, Prettier supports direct installation of forks from GitHub.

@thorn0 that never even crossed my mind.

Brilliant! Thanks

@breck7 It’s unlikely we’ll do that for strings
 but can’t you use numbers instead of strings in that code ("#130d34" vs 0x130d34)? 😉

@breck7 See #10106. BTW you can install it directly from Git: npm install thorn0/prettier#num-arrays

Among all the proposals from this discussion, https://github.com/prettier/prettier/issues/4210#issuecomment-376500821 seems to be the best tradeoff. A PR implementing it is very likely to be accepted.

I love the “// prettier-mode matrix” suggestion from @evilebottnawi

We hit this issue in dozens of files across a pretty clean codebase. Would be great to have an option like that.

A test case example (can’t put each test case into another config)

What is wrong?

let test_case = [
	[
		66,
		57,
		45,
		47,
		33,
		53,
		82,
		81,
		76,
		78,
		10,
		78,
		15,
		98,
		24,
		29,
		32,
		27,
		28,
		76,
		41,
		65,
		84,
		35,
		97,
		90,
		75,
		24,
		88,
		45,
		23,
		75,
		63,
		86,
		24,
		39,
		9,
		51,
		33,
		40,
		58,
		17,
		49,
		86,
		63,
		59,
		97,
		91,
		98,
		99,
		5,
		69,
		51,
		44,
		34,
		69,
		17,
		91,
		27,
		83,
		26,
		34,
		93,
		29,
		66,
		88,
		49,
		33,
		49,
		73,
		9,
		81,
		4,
		36,
		5,
		14,
		43,
		31,
		86,
		27,
		39,
		75,
		98,
		99,
		55,
		19,
		39,
		21,
		85,
		86,
		46,
		82,
		11,
		44,
		48,
		77,
		35,
		48,
		78,
		97,
	],
	[
		41,
		83,
		31,
		62,
		15,
		70,
		10,
		90,
		21,
		48,
		39,
		76,
		14,
		48,
		63,
		62,
		16,
		17,
		61,
		97,
		86,
		80,
		34,
		27,
		39,
		53,
		90,
		80,
		56,
		71,
		31,
		22,
		29,
		7,
		71,
		90,
		65,
		17,
		48,
		85,
		14,
		94,
		16,
		32,
		4,
		96,
		49,
		97,
		53,
		87,
		54,
		2,
		78,
		37,
		21,
		3,
		97,
		62,
		93,
		62,
		11,
		27,
		14,
		29,
		64,
		44,
		11,
		5,
		39,
		43,
		94,
		52,
		0,
		4,
		86,
		58,
		63,
		42,
		97,
		54,
		2,
		1,
		53,
		17,
		92,
		79,
		52,
		47,
		81,
		93,
		34,
		17,
		93,
		20,
		61,
		68,
		58,
		49,
		27,
		45,
	],
	3,
];

How it looks with prettier-ignore

let test_case = [
	// prettier-ignore
	[66,57,45,47,33,53,82,81,76,78,10,78,15,98,24,29,32,27,28,76,41,65,84,35,97,90,75,24,88,45,23,75,63,86,24,39,9,51,33,40,58,17,49,86,63,59,97,91,98,99,5,69,51,44,34,69,17,91,27,83,26,34,93,29,66,88,49,33,49,73,9,81,4,36,5,14,43,31,86,27,39,75,98,99,55,19,39,21,85,86,46,82,11,44,48,77,35,48,78,97],
	// prettier-ignore
	[41,83,31,62,15,70,10,90,21,48,39,76,14,48,63,62,16,17,61,97,86,80,34,27,39,53,90,80,56,71,31,22,29,7,71,90,65,17,48,85,14,94,16,32,4,96,49,97,53,87,54,2,78,37,21,3,97,62,93,62,11,27,14,29,64,44,11,5,39,43,94,52,0,4,86,58,63,42,97,54,2,1,53,17,92,79,52,47,81,93,34,17,93,20,61,68,58,49,27,45],
	3,
];

What I right?

// Format by line width (say, 80 chars)
//	then wrap to next line

let test_case = [
	[
		66,57,45,47,33,53,82,81,76,78,10,78,15,98,24,29,32,27,28,76,41,65,84,35,
		97,90,75,24,88,45,23,75,63,86,24,39,9,51,33,40,58,17,49,86,63,59,97,91,
		98,99,5,69,51,44,34,69,17,91,27,83,26,34,93,29,66,88,49,33,49,73,9,81,4,
		36,5,14,43,31,86,27,39,75,98,99,55,19,39,21,85,86,46,82,11,44,48,77,35,
		48,78,97
	],
	[
		41,83,31,62,15,70,10,90,21,48,39,76,14,48,63,62,16,17,61,97,86,80,34,27,
		39,53,90,80,56,71,31,22,29,7,71,90,65,17,48,85,14,94,16,32,4,96,49,97,
		53,87,54,2,78,37,21,3,97,62,93,62,11,27,14,29,64,44,11,5,39,43,94,52,0,
		4,86,58,63,42,97,54,2,1,53,17,92,79,52,47,81,93,34,17,93,20,61,68,58,49,
		27,45
	]
];

The 80-character print width is not just about screen width — it’s also about how prose is often formatted in columns 60-70 characters wide (like the New York Times and these comment fields). While 80 chars has historical precedent, it can also be justified by adding space for several characters of indentation while still leaving a readable width for the actual code.

That’s cool. But it doesn’t explain why we can’t configure it for arrays, or specifically for JSON as mentioned.

@j-f1 we should maybe check the length of the items and compare it to the preferred line length set by the user. I can imagine that sometimes printing each item on a new line is the only option:

lineLength: 10

const userIds = [
  1111, // max 1 item per line
  2222,
  3333,
  4444
];

lineLength: 15

const userIds = [
  1111, 2222, // max 2 items per line
  3333, 4444
];

Also not sure about what types of elements to support but I guess starting off with numbers and strings is pretty safe.

Thank you for movement on this. Any ETA on how soon this will be ready?

Most importantly and urgently, this kind of option would allow me to replace thousands of lines of code with a semantically identical couple hundred lines.

That would work wonders for my code golf scores.

Updated Playground link as well as code diff in this comment, I want config to setup the way it is visible in the left in playground / Input below.

Playground link

Input:

const {
      greeting, greeted, silent, onMouseOver,
      onKeyPress, onKeyRelease, onVerify,
      onSubmit,
    } = props;

Output

const {
    greeting,
    greeted,
    silent,
    onMouseOver,
    onKeyPress,
    onKeyRelease,
    onVerify,
    onSubmit,
  } = props;

Input:

import {
  Image, Menu, Header, Icon, Segment, Tab, 
  Label, Button, Modal, Card, Grid, Table,
  Input, Radio
} from 'semantic-ui-react';

Output

import {
  Image,
  Menu,
  Header,
  Icon,
  Segment,
  Tab,
  Label,
  Button,
  Modal,
  Card,
  Grid,
  Table,
  Input,
  Radio,
} from "semantic-ui-react";

Input:

const myArray = [
      'first','second','third','fourth',
      'fifth', 'sixth', 'seventh'
    ];

Output

const myArray = [
    "first",
    "second",
    "third",
    "fourth",
    "fifth",
    "sixth",
    "seventh",
  ];

Input:

const newFunction = (
      first, second, third, fourth,
      'fifth', 'sixth', 'seventh', 'eighth'
    ) => {};

Output

const newFunction = (
    first,
    second,
    third,
    fourth,
    "fifth",
    "sixth",
    "seventh",
    "eighth"
  ) => {};

That’s not really arrays, but point taken. You might also be interested in #5995

Searching for this issue everywhere. I am facing the same issue, not just for arrays but for objects too like below

Expected:

const {
  1, 2, 3, 4, 5, 
  6, 7, 8, 9, 10
} = someInput;

Actual:

const {
 1, 
 2,
 3,
 4,
 5, 
 6,
 7, 
 8, 
 9, 
 10
} = someInput;

Looking for an option like: breakByMatrix: true so that when the array limit exceeds printWidth it shall make a break there and continue in the second line till reaching printWidth and so on. So that for large arrays/parameters, every line consists of utmost params of printWidth

The 80-character print width is not just about screen width — it’s also about how prose is often formatted in columns 60-70 characters wide (like the New York Times and these comment fields). While 80 chars has historical precedent, it can also be justified by adding space for several characters of indentation while still leaving a readable width for the actual code.

I was hunting for this issue 😃

I think it’s super important to have an arrayWidth option operate independently of the printWidth value. As suggested elsewhere in this thread, it’s not always feasible to place an ignore declaration (aka, JSON files).

This new option would allow printWidth to still control the total container width, but arrays can be broken up into newlines every arrayWidth characters.

Here are two common examples that I run into that make Prettier (including 2.0) hard on the eyes:

  1. config objects within JavaScript: playground
  2. lerna.json and tsconfig.json

This is because the second array probably goes past the printWidth, so it’s broken onto multiple lines.

Thanks, that was it. Sorry, I combed the docs before posting but I must have missed this
even though it’s the first listed option đŸ„‡