JavaScript¶
Files ending in .js, .mjs, .cjs and .jsx are formatted by the
JavaScript pack (rainbow_fmt.languages.javascript, grammar
tree-sitter-javascript).
The defaults follow Prettier's rules, with the core's 4-space indentation
and without semicolons; byte-identical Prettier output is not a goal, and
where users differ there is an option.
const total=items.filter(item=>item.active).map(item=>item.price).reduce((a,b)=>a+b,0);
if(total>limit){notify({user,total,message:"over the limit"})}
becomes
const total = items
.filter(item => item.active)
.map(item => item.price)
.reduce((a, b) => a + b, 0)
if (total > limit) {
notify({ user, total, message: "over the limit" })
}
Prettier's own style is indent_size = 2:
[language.javascript]
semicolons = "always" # Prettier's default
[core]
indent_size = 2
([core] applies to all languages; use an [[override]] for
*.js files to change it for JavaScript only, see
configuration.md.)
What changes and what does not¶
The pack changes layout only. Strings, template literals, regular expressions, numbers and comment texts are printed as written, and parentheses are never added or removed. What it may add or remove are statement-final semicolons, empty statements, semicolons between class members and trailing commas; the verifier checks that nothing else changed.
- Indentation comes from the tree (
core.indent_style,core.indent_size); a non-empty block is always broken,} else {,} catch (e) {and} while (x)join the closing brace. - Spacing within a line: one space around binary and assignment
operators,
=>,?and:, after commas, keywords and:of object members; none inside brackets and parentheses, around.and?., before the(of calls and parameters (function () {}andasync () =>excepted), after unary operators (typeof,void,deleteexcepted) and.... Braces of objects, patterns and import/export lists get spaces inside (bracket_spacing). - Brackets are printed flat if they fit, otherwise one item per line
with a trailing comma (
shared.trailing_comma, whose default is"multiline"for JavaScript; never after a rest element). An object written with a line break after{stays broken (object_wrap); an array of two or more arrays or objects (a matrix) is always broken; an array of numbers is filled. - Call arguments: a function, arrow function or object as the last
argument hugs the parentheses (
it("works", () => {…})), as does a function as the first of two arguments (setTimeout(() => {…}, 1000)). A lone object pattern parameter hugs its parentheses too. - Expressions break when too long: after the operators of a binary
expression at its lowest precedence level (indented inside arguments),
after
=for a binary or string value, before?and:of a conditional, after=>of an arrow function whose body is not a block or object, and before each.of a member chain with two or more.call()s after its head. A chain also breaks when a call other than the last spans lines (a function argument). - Declarations with several declarators and any initializer put one
declarator per line (
let a = 1,/b). - Blank lines are kept, at most
core.max_blank_lines; none at the start or end of a block or the file. - Comments: a comment after code stays on its line, one space after
it; a comment on its own line is indented to its block; a comment
inside brackets stays with its item and forces the brackets to break.
A block comment whose lines all start with
*(JSDoc) is re-indented. - Decorators of a class go on their own lines; those of a class member stay where they were written (same line or own line).
- Inline directives:
// rainbow: off,// rainbow: skip-next,// rainbow: set …(also as/* … */), Prettier's// prettier-ignore(configuration.md). - JSX elements are printed exactly as written (their lines are not re-indented).
Semicolons¶
language.javascript.semicolons:
"as_needed"(default): statement-final semicolons and empty statements are removed. A statement that would continue the previous line gets a leading;: one starting with(,[,`,+,-,/(a regular expression) or<(JSX):
let a = 1
;[b, c] = [c, b]
So does a statement starting with a name like in1, in_x or in$,
which the grammar would read as the operator in after a line break.
A class field keeps its ; where the next member would join it: before
a member named in or instanceof, a computed field or a computed or
generator method, and after a field named static, get or set
without a value (Prettier's rules).
- "always": every statement that may end with ; ends with one, and so
does every class field.
- "preserve": semicolons as written. A ; at the start of a line after
a statement is that statement's semicolon, so it moves to the end of the
previous line.
The body of if (x);, for (;;); and while (x); is an empty statement
and always kept.
Options¶
| Key | Values | Default |
|---|---|---|
language.javascript.semicolons |
"as_needed", "always", "preserve" (see above) |
"as_needed" |
language.javascript.object_wrap |
"preserve": an object written with a line break between { and its first member stays broken; "fit": objects break only when too long |
"preserve" |
language.javascript.bracket_spacing |
true: { a }; false: {a} (objects, patterns, import/export lists) |
true |
language.javascript.return_semicolons |
"as_statements": as semicolons; "unless_last": with semicolons = "as_needed", a return followed by another statement in its block (or an if (…) return x followed by one) ends with ;, the last return of a block does not |
"as_statements" |
language.javascript.bracket_hug |
true: an array whose items are all non-empty objects hugs them ([{ … }, { … }]) when it does not fit on one line |
false |
language.javascript.binary_operator_break |
"after" or "before" the operators of a broken expression |
"after" |
shared.trailing_comma |
"never", "multiline" |
"multiline" for JavaScript |
Differences from Prettier¶
- Parentheses are never added:
a && b || c,a + b % candnew Foostay as written, arrow parameters stayx =>or(x) =>, and a longreturnor ternary is broken without wrapping it in parentheses. Nor are they removed ((a)()gets a;guard where Prettier printsa()). - Quotes and numbers are printed as written (
'a',0XFF,.5). - JSX is printed as written, not re-laid out or wrapped in parentheses.
- A member chain that fits stays on one line (Prettier breaks chains of
three or more calls with function arguments). "Fits" means the whole
chain, or its text up to a function argument at its end; a chain whose
object argument is kept broken by
object_wrapis broken before each.(Prettier keepsx.a().b().c({on one line). - A destructuring pattern that fits stays on one line (Prettier breaks object patterns with nested object patterns).
Limitations¶
- No quote normalization and no JSX layout. TypeScript has its own pack
(
typescript.md). - The grammar (tree-sitter-javascript 0.25) does not parse import
assertions (
import a from "./a.json" assert { type: "json" }, the syntax thatwithreplaced), nor an arrow function with a block body followed by[on the next line; such files are reported as syntax errors and left unchanged. - The lines of JSX and multi-line template literals keep their indentation, so they may be indented differently from the code around them after re-indentation.
- Speed: about 1 s to format and 2 s to verify 100 KiB of ordinary code; minified bundles are about three times slower per byte (a 700 KiB bundle takes over a minute). Exclude generated bundles from formatting.