1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use crate::prelude::*;
use biome_formatter::{write, CstFormatContext};
use biome_js_syntax::AnyJsNamedImport;
use biome_js_syntax::AnyJsNamedImportSpecifier;
use biome_js_syntax::JsImportNamedClause;
use biome_js_syntax::JsImportNamedClauseFields;
use biome_js_syntax::JsNamedImportSpecifiersFields;
#[derive(Debug, Clone, Default)]
pub(crate) struct FormatJsImportNamedClause;
impl FormatNodeRule<JsImportNamedClause> for FormatJsImportNamedClause {
fn fmt_fields(&self, node: &JsImportNamedClause, f: &mut JsFormatter) -> FormatResult<()> {
let JsImportNamedClauseFields {
type_token,
default_specifier,
named_import,
from_token,
source,
assertion,
} = node.as_fields();
if let Some(type_token) = type_token {
write!(f, [type_token.format(), space()])?;
}
let is_default_specifier_empty = default_specifier.is_none();
if let Some(default_specifier) = default_specifier {
write!(f, [default_specifier.format(), space()])?;
}
let named_import = named_import?;
// can_break implementation, return `format_element` instead of boolean to reduce enum conversion overhead.
// if `can_break` is true we just use the previous format strategy, otherwise we use the new format strategy.
// reference https://github.com/prettier/prettier/blob/5b113e71b1808d6916f446c3aa49c3c53e3bdb98/src/language-js/print/module.js#L173
// https://github.com/prettier/prettier/blob/5b113e71b1808d6916f446c3aa49c3c53e3bdb98/src/language-js/print/module.js#L184-L209v,
// `standaloneSpecifiers` corresponding our `JsDefaultImportSpecifier` + part of `JsNamespaceImportSpecifier`,
// `groupedSpecifiers` corresponding our `JsNamedImportSpecifiers`
// Here we use an opposite way of thinking, we only thinking about the way that can not break
// That's to say
// 1. `default_specifier` need to be none.
// 2. length of `JsNamedImportSpecifiers` at least is one
// 3. Surrounding of the only `JsNamedImportSpecifiers` should not have any comments
if !is_default_specifier_empty {
// `can_break` is true.
write![f, [named_import.format()]]
} else {
match named_import {
AnyJsNamedImport::JsNamedImportSpecifiers(ref specifiers)
if specifiers.specifiers().len() == 1
&& !f.context().comments().is_suppressed(specifiers.syntax()) =>
{
// SAFETY: we know that the `specifiers.specifiers().len() == 1`, so unwrap `iter().next()` is safe.
let first_specifier = specifiers.specifiers().elements().next().unwrap();
match (first_specifier.node(), first_specifier.trailing_separator()) {
(
Ok(AnyJsNamedImportSpecifier::JsShorthandNamedImportSpecifier(
specifier,
)),
Ok(separator),
) => {
if f.comments().has_comments(specifier.syntax()) {
write!(f, [named_import.format()])
} else {
let JsNamedImportSpecifiersFields {
l_curly_token,
specifiers: _,
r_curly_token,
} = specifiers.as_fields();
write!(f, [l_curly_token.format(), space(), specifier.format(),])?;
if let Some(separator) = separator {
format_removed(separator).fmt(f)?;
}
write!(f, [space(), r_curly_token.format()])
}
}
(
Ok(AnyJsNamedImportSpecifier::JsNamedImportSpecifier(specifier)),
Ok(separator),
) => {
if f.comments().has_comments(specifier.syntax()) {
write!(f, [named_import.format()])
} else {
let JsNamedImportSpecifiersFields {
l_curly_token,
specifiers: _,
r_curly_token,
} = specifiers.as_fields();
write!(f, [l_curly_token.format(), space(), specifier.format(),])?;
if let Some(separator) = separator {
format_removed(separator).fmt(f)?;
}
write!(f, [space(), r_curly_token.format()])
}
}
_ => write![f, [named_import.format()]],
}
}
_ => write![f, [named_import.format()]],
}
}?;
write![f, [space(), from_token.format(), space(), source.format(),]]?;
if let Some(assertion) = assertion {
write!(f, [space(), assertion.format()])?;
}
Ok(())
}
}