Skip to content

Commit a99aef3

Browse files
committed
feat(formatter): complete printing ImportDeclaration
1 parent 1faa54c commit a99aef3

File tree

4 files changed

+234
-200
lines changed

4 files changed

+234
-200
lines changed

crates/oxc_formatter/src/formatter/comments/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,12 @@ impl<'a> Comments<'a> {
345345
);
346346

347347
let Some(following_node) = following_node else {
348+
if let SiblingNode::ImportDeclaration(import) = enclosing_node
349+
&& import.source.span.start > preceding_span.end
350+
{
351+
return self.comments_before(import.source.span.start);
352+
}
353+
348354
let enclosing_span = enclosing_node.span();
349355
return self.comments_before(enclosing_span.end);
350356
};
@@ -427,6 +433,13 @@ impl<'a> Comments<'a> {
427433
return &[];
428434
}
429435

436+
if matches!(
437+
enclosing_node,
438+
SiblingNode::ImportDeclaration(_) | SiblingNode::ExportAllDeclaration(_)
439+
) {
440+
return &comments[..comment_index];
441+
}
442+
430443
let mut gap_end = following_span.start;
431444
for cur_index in (0..comment_index).rev() {
432445
let comment = &comments[cur_index];
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
use oxc_allocator::Vec;
2+
use oxc_ast::ast::*;
3+
use oxc_span::GetSpan;
4+
use oxc_syntax::identifier::is_identifier_name;
5+
6+
use crate::{
7+
Format, FormatResult, FormatTrailingCommas, QuoteProperties, TrailingSeparator,
8+
formatter::{
9+
Formatter, prelude::*, separated::FormatSeparatedIter, trivia::FormatLeadingComments,
10+
},
11+
generated::ast_nodes::{AstNode, AstNodes},
12+
write,
13+
write::semicolon::OptionalSemicolon,
14+
};
15+
16+
use super::FormatWrite;
17+
18+
impl<'a> FormatWrite<'a> for AstNode<'a, ImportExpression<'a>> {
19+
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
20+
write!(f, ["import"])?;
21+
if let Some(phase) = &self.phase() {
22+
write!(f, [".", phase.as_str()])?;
23+
}
24+
write!(f, ["(", self.source()])?;
25+
if let Some(options) = &self.options() {
26+
write!(f, [",", space(), options])?;
27+
}
28+
write!(f, ")")
29+
}
30+
}
31+
32+
impl<'a> Format<'a> for ImportOrExportKind {
33+
fn fmt(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
34+
if self.is_type() { write!(f, ["type", space()]) } else { Ok(()) }
35+
}
36+
}
37+
38+
impl<'a> FormatWrite<'a> for AstNode<'a, ImportDeclaration<'a>> {
39+
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
40+
write!(f, ["import", space(), self.import_kind])?;
41+
42+
if let Some(specifiers) = self.specifiers() {
43+
write!(f, [specifiers, space(), "from", space()])?;
44+
}
45+
46+
write!(f, [self.source(), self.with_clause(), OptionalSemicolon])
47+
}
48+
}
49+
50+
impl<'a> Format<'a> for AstNode<'a, Vec<'a, ImportDeclarationSpecifier<'a>>> {
51+
fn fmt(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
52+
let mut specifiers_iter = self.iter().peekable();
53+
54+
while let Some(specifier) = specifiers_iter.peek() {
55+
match specifier.as_ref() {
56+
ImportDeclarationSpecifier::ImportDefaultSpecifier(_) => {
57+
write!(f, [specifiers_iter.next().unwrap()])?;
58+
}
59+
ImportDeclarationSpecifier::ImportNamespaceSpecifier(_) => {
60+
write!(f, [specifiers_iter.next().unwrap()])?;
61+
}
62+
ImportDeclarationSpecifier::ImportSpecifier(_) => {
63+
break;
64+
}
65+
}
66+
67+
if specifiers_iter.peek().is_some() {
68+
write!(f, [",", space()])?;
69+
} else {
70+
return Ok(());
71+
}
72+
}
73+
74+
let should_insert_space_around_brackets = f.options().bracket_spacing.value();
75+
76+
if self.is_empty() {
77+
write!(f, ["{", "}"])?;
78+
} else if self.len() == 1
79+
&& let Some(ImportDeclarationSpecifier::ImportSpecifier(specifier)) =
80+
specifiers_iter.peek().map(AsRef::as_ref)
81+
&& !f.comments().has_comments_before(specifier.local.span.start)
82+
{
83+
write!(
84+
f,
85+
[
86+
"{",
87+
maybe_space(should_insert_space_around_brackets),
88+
specifiers_iter.next().unwrap(),
89+
maybe_space(should_insert_space_around_brackets),
90+
"}",
91+
]
92+
)?;
93+
} else {
94+
write!(
95+
f,
96+
[
97+
"{",
98+
group(&soft_block_indent_with_maybe_space(
99+
&format_once(|f| {
100+
let trailing_separator =
101+
FormatTrailingCommas::ES5.trailing_separator(f.options());
102+
103+
f.join_with(&soft_line_break_or_space())
104+
.entries(
105+
FormatSeparatedIter::new(specifiers_iter, ",")
106+
.with_trailing_separator(trailing_separator),
107+
)
108+
.finish()
109+
}),
110+
should_insert_space_around_brackets
111+
)),
112+
"}"
113+
]
114+
)?;
115+
}
116+
117+
Ok(())
118+
}
119+
}
120+
121+
impl<'a> FormatWrite<'a> for AstNode<'a, ImportSpecifier<'a>> {
122+
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
123+
let comments = f.context().comments().comments_before(self.local.span.end);
124+
let mut len = comments.len();
125+
while len != 0 && comments[len - 1].is_block() {
126+
len -= 1;
127+
}
128+
write!(f, [FormatLeadingComments::Comments(&comments[..len]), self.import_kind()])?;
129+
if self.local.span == self.imported.span() {
130+
write!(f, [self.local()])?;
131+
} else {
132+
write!(f, [self.imported(), space(), "as", space(), self.local()])?;
133+
}
134+
Ok(())
135+
}
136+
}
137+
138+
impl<'a> FormatWrite<'a> for AstNode<'a, ImportDefaultSpecifier<'a>> {
139+
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
140+
self.local().fmt(f)
141+
}
142+
}
143+
144+
impl<'a> FormatWrite<'a> for AstNode<'a, ImportNamespaceSpecifier<'a>> {
145+
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
146+
write!(f, ["*", space(), "as", space(), self.local()])
147+
}
148+
}
149+
150+
impl<'a> FormatWrite<'a> for AstNode<'a, WithClause<'a>> {
151+
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
152+
let should_insert_space_around_brackets = f.options().bracket_spacing.value();
153+
let format_comment = format_with(|f| {
154+
if self.with_entries().is_empty() {
155+
let comments = f.context().comments().comments_before(self.span.end);
156+
write!(f, [space(), FormatLeadingComments::Comments(comments)])?;
157+
}
158+
Ok(())
159+
});
160+
write!(
161+
f,
162+
[
163+
space(),
164+
format_comment,
165+
match self.keyword() {
166+
WithClauseKeyword::With => "with",
167+
WithClauseKeyword::Assert => "assert",
168+
},
169+
space(),
170+
self.with_entries(),
171+
]
172+
)
173+
}
174+
}
175+
176+
impl<'a> Format<'a> for AstNode<'a, Vec<'a, ImportAttribute<'a>>> {
177+
fn fmt(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
178+
write!(f, "{")?;
179+
if !self.is_empty() {
180+
let maybe_space = maybe_space(f.options().bracket_spacing.value());
181+
write!(f, [maybe_space])?;
182+
183+
f.join_with(space())
184+
.entries(
185+
FormatSeparatedIter::new(self.iter(), ",")
186+
.with_trailing_separator(TrailingSeparator::Disallowed),
187+
)
188+
.finish()?;
189+
190+
write!(f, [maybe_space])?;
191+
}
192+
write!(f, "}")
193+
}
194+
}
195+
196+
impl<'a> FormatWrite<'a> for AstNode<'a, ImportAttribute<'a>> {
197+
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
198+
if let AstNodes::StringLiteral(s) = self.key().as_ast_nodes() {
199+
if f.options().quote_properties == QuoteProperties::AsNeeded
200+
&& is_identifier_name(s.value().as_str())
201+
{
202+
dynamic_text(s.value().as_str()).fmt(f)?;
203+
} else {
204+
s.fmt(f)?;
205+
}
206+
} else {
207+
write!(f, self.key())?;
208+
}
209+
write!(f, [":", space(), self.value()])
210+
}
211+
}

0 commit comments

Comments
 (0)