use crate::prelude::*;
use crate::AsFormat;
use crate::context::trailing_comma::FormatTrailingComma;
use biome_formatter::write;
use biome_js_syntax::{
AnyJsArrayAssignmentPatternElement, AnyJsArrayBindingPatternElement, AnyJsArrayElement,
JsLanguage,
};
use biome_rowan::{AstNode, AstSeparatedList};
pub(crate) fn write_array_node<N, I>(node: &N, f: &mut JsFormatter) -> FormatResult<()>
where
N: AstSeparatedList<Language = JsLanguage, Node = I>,
I: ArrayNodeElement + AsFormat<JsFormatContext>,
{
let trailing_separator = FormatTrailingComma::ES5.trailing_separator(f.options());
let mut join = f.join_nodes_with_soft_line();
let last_index = node.len().saturating_sub(1);
for (index, element) in node.elements().enumerate() {
let node = element.node()?;
let separator_mode = node.separator_mode();
let is_disallow = matches!(separator_mode, TrailingSeparatorMode::Disallow);
let is_force = matches!(separator_mode, TrailingSeparatorMode::Force);
join.entry(
node.syntax(),
&format_with(|f| {
write!(f, [group(&node.format())])?;
if is_disallow {
if let Some(separator) = element.trailing_separator()? {
write!(f, [format_removed(separator)])?;
}
} else if is_force || index != last_index {
match element.trailing_separator()? {
Some(trailing) => write!(f, [trailing.format()])?,
None => text(",").fmt(f)?,
};
} else if let Some(separator) = element.trailing_separator()? {
match trailing_separator {
TrailingSeparator::Omit => {
write!(f, [format_removed(separator)])?;
}
_ => {
write!(f, [format_only_if_breaks(separator, &separator.format())])?;
}
}
} else {
write!(f, [FormatTrailingComma::ES5])?;
};
Ok(())
}),
);
}
join.finish()
}
pub(crate) enum TrailingSeparatorMode {
Disallow,
Auto,
Force,
}
pub(crate) trait ArrayNodeElement: AstNode<Language = JsLanguage> {
fn separator_mode(&self) -> TrailingSeparatorMode;
}
impl ArrayNodeElement for AnyJsArrayElement {
fn separator_mode(&self) -> TrailingSeparatorMode {
match self {
Self::JsArrayHole(_) => TrailingSeparatorMode::Force,
_ => TrailingSeparatorMode::Auto,
}
}
}
impl ArrayNodeElement for AnyJsArrayAssignmentPatternElement {
fn separator_mode(&self) -> TrailingSeparatorMode {
match self {
Self::JsArrayHole(_) => TrailingSeparatorMode::Force,
Self::JsArrayAssignmentPatternRestElement(_) => TrailingSeparatorMode::Disallow,
_ => TrailingSeparatorMode::Auto,
}
}
}
impl ArrayNodeElement for AnyJsArrayBindingPatternElement {
fn separator_mode(&self) -> TrailingSeparatorMode {
match self {
Self::JsArrayHole(_) => TrailingSeparatorMode::Force,
Self::JsArrayBindingPatternRestElement(_) => TrailingSeparatorMode::Disallow,
_ => TrailingSeparatorMode::Auto,
}
}
}