mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-06 17:34:25 +00:00
fix(formatter): do not indent logical chains whose right sides all inline (#27667)
```js
// Before
const one = $abilities ?? [
"foo",
"bar",
"veryVeryVeryVeryVeryVeryVeryVeryVeryLongKey",
];
const two = $abilities ?? ["foo"] ?? [
"foo",
"bar",
"veryVeryVeryVeryVeryVeryVeryVeryVeryLongKey",
];
// After
const one = $abilities ?? [
"foo",
"bar",
"veryVeryVeryVeryVeryVeryVeryVeryVeryLongKey",
];
const two = $abilities ?? ["foo"] ?? [
"foo",
"bar",
"veryVeryVeryVeryVeryVeryVeryVeryVeryLongKey",
];
```
This commit is contained in:
1 parent
a07a0fbb8f
commit
644ca1c04f
4 files changed
+108
-6
No files matched your search
@@ -865,3 +865,34 @@ const get = (key: K) => (({ a: 1, b: 2 }) as const)[key];
|
||||
When an ancestor gets its own parens, a leading `{`/`function`/`class`/`let[` inside it needs none.
|
||||
Prettier already does this after `export default` (`` export default (function () {} + foo)`` ``) and for a sequence arrow body (`() => ({}, 1)`),
|
||||
but not at statement start or for other arrow bodies, e.g. the object lookup idiom above.
|
||||
|
||||
## inline-logical-chain-indent
|
||||
|
||||
- Why: uniform-rule (same construct, same output: a single-link inline chain `a ?? [...]`; prettier/prettier#5183, prettier/prettier#19792)
|
||||
- Pin: `tests/fixtures/js/logicals/inline-logical-chain-indent.js`
|
||||
|
||||
```js
|
||||
// input
|
||||
const x = $abilities ?? ["foo", "bar", "bar"] ?? ["foo", "bar", "bar", "veryVeryVeryVeryVeryVeryVeryVeryVeryLongKey"];
|
||||
|
||||
// ours
|
||||
const x = $abilities ?? ["foo", "bar", "bar"] ?? [
|
||||
"foo",
|
||||
"bar",
|
||||
"bar",
|
||||
"veryVeryVeryVeryVeryVeryVeryVeryVeryLongKey",
|
||||
];
|
||||
|
||||
// prettier
|
||||
const x = $abilities ?? ["foo", "bar", "bar"] ?? [
|
||||
"foo",
|
||||
"bar",
|
||||
"bar",
|
||||
"veryVeryVeryVeryVeryVeryVeryVeryVeryLongKey",
|
||||
];
|
||||
```
|
||||
|
||||
When every right side of a logical chain is an inlined object/array/JSX literal, the chain never breaks at an operator.
|
||||
Prettier prints a single-link chain without an indent, but a flattened one indents its tail, which only shifts the last literal.
|
||||
A chain with a non-inlined right side breaks at the operators and keeps the indent.
|
||||
Prettier `main` drops the indent since #19792; the pin (3.9.10) still indents.
|
||||
@@ -239,18 +239,23 @@ impl<'a> Format<'a, JsFormatContext<'a>> for BinaryLikeExpression<'a, '_> {
|
||||
);
|
||||
}
|
||||
|
||||
// Check other conditions that require knowing if the expression is flattened
|
||||
let inline_logical_expression = self.should_inline_logical_expression();
|
||||
let should_indent_if_inlines = should_indent_if_parent_inlines(self.parent());
|
||||
|
||||
// We need to know if it's flattened to make this decision, so we must build parts
|
||||
// is_inside_condition is always false here (we returned early if true)
|
||||
let parts = split_into_left_and_right_sides(*self, false);
|
||||
let flattened = parts.len() > 2;
|
||||
// Every operator of the flattened chain inlines its right side (`a ?? [..] ?? [..]`),
|
||||
// so the chain never breaks at an operator and an indent would only shift the last literal.
|
||||
// See DIVERGENCES.md#inline-logical-chain-indent
|
||||
let inline_chain = inline_logical_expression
|
||||
&& parts.iter().all(|part| match part {
|
||||
BinaryLeftOrRightSide::Left { .. } => true,
|
||||
BinaryLeftOrRightSide::Right { parent, .. } => {
|
||||
parent.should_inline_logical_expression()
|
||||
}
|
||||
});
|
||||
|
||||
if (inline_logical_expression && !flattened)
|
||||
|| (!inline_logical_expression && should_indent_if_inlines)
|
||||
{
|
||||
if inline_chain || (!inline_logical_expression && should_indent_if_inlines) {
|
||||
return write!(
|
||||
f,
|
||||
[group(&format_once(|f| {
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
const x = $abilities ?? ["foo", "bar", "bar"] ?? ["foo", "bar", "bar", "veryVeryVeryVeryVeryVeryVeryVeryVeryLongKey"];
|
||||
|
||||
const y = $abilities ?? { a: 1, b: 2 } ?? { a: 1, b: 2, c: 3, veryVeryVeryVeryVeryVeryVeryVeryVeryLongKey: true };
|
||||
|
||||
// Not every right side inlines, the chain breaks at an operator and keeps the indent
|
||||
const z = $abilities ?? foo ?? ["foo", "bar", "bar", "veryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongKey"];
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
---
|
||||
source: crates/oxc_formatter/tests/fixtures/mod.rs
|
||||
---
|
||||
==================== Input ====================
|
||||
const x = $abilities ?? ["foo", "bar", "bar"] ?? ["foo", "bar", "bar", "veryVeryVeryVeryVeryVeryVeryVeryVeryLongKey"];
|
||||
|
||||
const y = $abilities ?? { a: 1, b: 2 } ?? { a: 1, b: 2, c: 3, veryVeryVeryVeryVeryVeryVeryVeryVeryLongKey: true };
|
||||
|
||||
// Not every right side inlines, the chain breaks at an operator and keeps the indent
|
||||
const z = $abilities ?? foo ?? ["foo", "bar", "bar", "veryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongKey"];
|
||||
|
||||
==================== Output ====================
|
||||
------------------
|
||||
{ printWidth: 80 }
|
||||
------------------
|
||||
const x = $abilities ?? ["foo", "bar", "bar"] ?? [
|
||||
"foo",
|
||||
"bar",
|
||||
"bar",
|
||||
"veryVeryVeryVeryVeryVeryVeryVeryVeryLongKey",
|
||||
];
|
||||
|
||||
const y = $abilities ?? { a: 1, b: 2 } ?? {
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 3,
|
||||
veryVeryVeryVeryVeryVeryVeryVeryVeryLongKey: true,
|
||||
};
|
||||
|
||||
// Not every right side inlines, the chain breaks at an operator and keeps the indent
|
||||
const z = $abilities ??
|
||||
foo ?? [
|
||||
"foo",
|
||||
"bar",
|
||||
"bar",
|
||||
"veryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongKey",
|
||||
];
|
||||
|
||||
-------------------
|
||||
{ printWidth: 100 }
|
||||
-------------------
|
||||
const x = $abilities ?? ["foo", "bar", "bar"] ?? [
|
||||
"foo",
|
||||
"bar",
|
||||
"bar",
|
||||
"veryVeryVeryVeryVeryVeryVeryVeryVeryLongKey",
|
||||
];
|
||||
|
||||
const y = $abilities ?? { a: 1, b: 2 } ?? {
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 3,
|
||||
veryVeryVeryVeryVeryVeryVeryVeryVeryLongKey: true,
|
||||
};
|
||||
|
||||
// Not every right side inlines, the chain breaks at an operator and keeps the indent
|
||||
const z = $abilities ??
|
||||
foo ?? ["foo", "bar", "bar", "veryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongKey"];
|
||||
|
||||
===================== End =====================
|
||||
Reference in new issue
Block a user