Skip to content

Commit 95f229d

Browse files
committed
feat: ability to format an already parsed file
1 parent 1a44c3e commit 95f229d

7 files changed

Lines changed: 69 additions & 34 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ dprint-core = { version = "0.44.0", features = ["formatting"] }
2929
fnv = "1.0.7"
3030
serde = { version = "1.0.118", features = ["derive"] }
3131
serde_json = { version = "1.0", optional = true }
32-
swc_ast_view = { version = "0.25.0", package = "dprint-swc-ecma-ast-view" }
32+
swc_ast_view = { version = "0.27.1", package = "dprint-swc-ecma-ast-view" }
3333
swc_common = "0.11.4"
3434
swc_ecmascript = { version = "0.52.1", features = ["parser"] }
3535

src/format_text.rs

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@ use std::path::Path;
33
use dprint_core::formatting::*;
44
use dprint_core::types::ErrBox;
55
use dprint_core::configuration::{resolve_new_line_kind};
6+
use swc_ast_view::TokenAndSpan;
7+
use swc_common::comments::SingleThreadedCommentsMapInner;
68

79
use super::parsing::parse;
810
use super::swc::parse_swc_ast;
911
use super::configuration::Configuration;
1012

1113
/// Formats a file.
1214
///
13-
/// Returns the file text `Ok(formatted_text)` or an error when it failed to parse.
15+
/// Returns the file text or an error when it failed to parse.
1416
///
1517
/// # Example
1618
///
@@ -42,17 +44,51 @@ pub fn format_text(file_path: &Path, file_text: &str, config: &Configuration) ->
4244

4345
let parsed_source_file = parse_swc_ast(file_path, file_text)?;
4446
Ok(dprint_core::formatting::format(|| {
45-
let print_items = parse(&parsed_source_file, config);
47+
let print_items = parse(&SourceFileInfo {
48+
module: &parsed_source_file.module,
49+
info: &parsed_source_file.info,
50+
tokens: &parsed_source_file.tokens,
51+
leading_comments: &parsed_source_file.leading_comments,
52+
trailing_comments: &parsed_source_file.trailing_comments,
53+
}, config);
4654
// println!("{}", print_items.get_as_text());
4755
print_items
4856
}, config_to_print_options(file_text, config)))
4957
}
5058

59+
#[derive(Clone)]
60+
pub struct SourceFileInfo<'a> {
61+
pub module: &'a swc_ecmascript::ast::Module,
62+
pub info: &'a dyn swc_ast_view::SourceFile,
63+
pub tokens: &'a [TokenAndSpan],
64+
pub leading_comments: &'a SingleThreadedCommentsMapInner,
65+
pub trailing_comments: &'a SingleThreadedCommentsMapInner,
66+
}
67+
68+
/// Formats the already parsed file. This is useful as a performance optimization.
69+
pub fn format_parsed_file(info: &SourceFileInfo<'_>, config: &Configuration) -> Result<String, ErrBox> {
70+
if super::utils::file_text_has_ignore_comment(info.info.text(), &config.ignore_file_comment_text) {
71+
return Ok(info.info.text().to_string());
72+
}
73+
74+
Ok(dprint_core::formatting::format(|| {
75+
let print_items = parse(&info, config);
76+
// println!("{}", print_items.get_as_text());
77+
print_items
78+
}, config_to_print_options(info.info.text(), config)))
79+
}
80+
5181
#[cfg(feature = "tracing")]
5282
pub fn trace_file(file_path: &Path, file_text: &str, config: &Configuration) -> dprint_core::formatting::TracingResult {
5383
let parsed_source_file = parse_swc_ast(file_path, file_text).expect("Expected to parse to SWC AST.");
5484
dprint_core::formatting::trace_printing(
55-
|| parse(&parsed_source_file, config),
85+
|| parse(&SourceFileInfo {
86+
info: &parsed_source_file.info,
87+
module: &parsed_source_file.module,
88+
tokens: &parsed_source_file.tokens,
89+
leading_comments: &parsed_source_file.leading_comments,
90+
trailing_comments: &parsed_source_file.trailing_comments,
91+
}, config),
5692
config_to_print_options(file_text, config),
5793
)
5894
}

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ mod swc;
77
mod utils;
88

99
pub use format_text::format_text;
10+
pub use format_text::SourceFileInfo;
11+
pub use format_text::format_parsed_file;
1012

1113
#[cfg(feature = "tracing")]
1214
pub use format_text::trace_file;

src/parsing/context.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use dprint_core::formatting::{Info, ConditionReference};
2-
use swc_common::SourceFile;
32
use swc_ast_view::*;
43
use fnv::{FnvHashMap, FnvHashSet};
54

@@ -15,7 +14,6 @@ pub struct Context<'a> {
1514
pub current_node: Node<'a>,
1615
pub parent_stack: Stack<Node<'a>>,
1716
handled_comments: FnvHashSet<BytePos>,
18-
pub info: &'a SourceFile,
1917
stored_infos: FnvHashMap<(BytePos, BytePos), Info>,
2018
stored_info_ranges: FnvHashMap<(BytePos, BytePos), (Info, Info)>,
2119
pub end_statement_or_member_infos: Stack<Info>,
@@ -32,7 +30,6 @@ impl<'a> Context<'a> {
3230
config: &'a Configuration,
3331
tokens: &'a [TokenAndSpan],
3432
current_node: Node<'a>,
35-
info: &'a SourceFile,
3633
module: &'a Module,
3734
) -> Context<'a> {
3835
Context {
@@ -43,7 +40,6 @@ impl<'a> Context<'a> {
4340
current_node,
4441
parent_stack: Stack::new(),
4542
handled_comments: FnvHashSet::default(),
46-
info,
4743
stored_infos: FnvHashMap::default(),
4844
stored_info_ranges: FnvHashMap::default(),
4945
end_statement_or_member_infos: Stack::new(),

src/parsing/node_helpers.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use swc_ast_view::*;
33
pub fn is_first_node_on_line(node: &dyn Spanned, module: &Module) -> bool {
44
let start = node.lo().0 as usize;
55
let source_file = module.source_file.as_ref().unwrap();
6-
let source_file_text = source_file.src.as_bytes();
6+
let source_file_text = source_file.text().as_bytes();
77

88
for i in (0..start).rev() {
99
let c = source_file_text[i];
@@ -69,7 +69,7 @@ pub fn nodes_have_only_spaces_between(previous_node: &Node, next_node: &Node, mo
6969
&& next_node_text.starts_with(' ')
7070
} else {
7171
let source_file = module.source_file.as_ref().unwrap();
72-
crate::utils::is_not_empty_and_only_spaces(&source_file.src[previous_node.hi().0 as usize..next_node.lo().0 as usize])
72+
crate::utils::is_not_empty_and_only_spaces(&source_file.text()[previous_node.hi().0 as usize..next_node.lo().0 as usize])
7373
}
7474
}
7575

src/parsing/parser.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,30 @@ use dprint_core::formatting::*;
33
use dprint_core::formatting::{parser_helpers::*,condition_resolvers, conditions::*};
44
use swc_ast_view::*;
55

6-
use crate::configuration::*;
7-
use crate::swc::ParsedSourceFile;
6+
use crate::{SourceFileInfo, configuration::*};
87
use crate::utils;
98
use super::sorting::*;
109
use super::swc::*;
1110
use super::swc::{get_flattened_bin_expr};
1211
use super::*;
1312

14-
pub fn parse(source_file: &ParsedSourceFile, config: &Configuration) -> PrintItems {
13+
pub fn parse(info: &SourceFileInfo<'_>, config: &Configuration) -> PrintItems {
1514
let source_file_info = swc_ast_view::ModuleInfo {
16-
module: &source_file.module,
17-
source_file: Some(&source_file.info),
18-
tokens: Some(&source_file.tokens),
19-
comments: Some(&source_file.comments),
15+
module: info.module,
16+
source_file: Some(info.info),
17+
tokens: Some(info.tokens),
18+
comments: Some(Comments {
19+
leading: info.leading_comments,
20+
trailing: info.trailing_comments,
21+
}),
2022
};
2123

2224
swc_ast_view::with_ast_view_for_module(source_file_info, |module| {
2325
let module_node = Node::Module(module);
2426
let mut context = Context::new(
2527
config,
26-
&source_file.tokens,
28+
info.tokens,
2729
module_node,
28-
&source_file.info,
2930
module,
3031
);
3132
let mut items = parse_node(module_node, &mut context);

src/swc/parse_swc_ast.rs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
use std::path::Path;
2-
use swc_common::{
3-
FileName, comments::SingleThreadedComments, SourceFile, BytePos, Spanned
4-
};
2+
use std::rc::Rc;
3+
use swc_common::{BytePos, Spanned, comments::{SingleThreadedComments, SingleThreadedCommentsMapInner}};
54
use swc_ecmascript::parser::{Parser, StringInput, Syntax, error::{SyntaxError, Error as SwcError}, lexer::Lexer, Capturing, JscTarget, token::{TokenAndSpan}};
65
use dprint_core::types::{ErrBox, Error};
6+
use swc_ast_view::SourceFileTextInfo;
77

88
pub struct ParsedSourceFile {
99
pub module: swc_ecmascript::ast::Module,
10-
pub info: SourceFile,
10+
pub info: SourceFileTextInfo,
1111
pub tokens: Vec<TokenAndSpan>,
12-
pub comments: SingleThreadedComments,
12+
pub leading_comments: SingleThreadedCommentsMapInner,
13+
pub trailing_comments: SingleThreadedCommentsMapInner,
1314
}
1415

1516
pub fn parse_swc_ast(file_path: &Path, file_text: &str) -> Result<ParsedSourceFile, ErrBox> {
@@ -31,13 +32,8 @@ pub fn parse_swc_ast(file_path: &Path, file_text: &str) -> Result<ParsedSourceFi
3132
}
3233

3334
fn parse_inner(file_path: &Path, file_text: &str) -> Result<ParsedSourceFile, ErrBox> {
34-
let source_file = SourceFile::new(
35-
FileName::Custom(file_path.to_string_lossy().into()),
36-
false,
37-
FileName::Custom(file_path.to_string_lossy().into()),
38-
file_text.into(),
39-
BytePos(0),
40-
);
35+
let string_input = StringInput::new(file_text, BytePos(0), BytePos(file_text.len() as u32));
36+
let source_file_info = SourceFileTextInfo::new(BytePos(0), file_text.to_string());
4137

4238
let comments: SingleThreadedComments = Default::default();
4339
let (module, tokens) = {
@@ -52,7 +48,7 @@ fn parse_inner(file_path: &Path, file_text: &str) -> Result<ParsedSourceFile, Er
5248
let lexer = Lexer::new(
5349
Syntax::Typescript(ts_config),
5450
JscTarget::Es2019,
55-
StringInput::from(&source_file),
51+
string_input,
5652
Some(&comments)
5753
);
5854
let lexer = Capturing::new(lexer);
@@ -66,6 +62,9 @@ fn parse_inner(file_path: &Path, file_text: &str) -> Result<ParsedSourceFile, Er
6662
Ok(module) => Ok((module, tokens))
6763
}
6864
}?;
65+
let (leading, trailing) = comments.take_all();
66+
let leading_comments = Rc::try_unwrap(leading).unwrap().into_inner();
67+
let trailing_comments = Rc::try_unwrap(trailing).unwrap().into_inner();
6968

7069
// {
7170
// let (leading, trailing) = comments.borrow_all();
@@ -74,9 +73,10 @@ fn parse_inner(file_path: &Path, file_text: &str) -> Result<ParsedSourceFile, Er
7473
// }
7574

7675
return Ok(ParsedSourceFile {
77-
comments,
76+
leading_comments,
77+
trailing_comments,
7878
module,
79-
info: source_file,
79+
info: source_file_info,
8080
tokens,
8181
});
8282

0 commit comments

Comments
 (0)