Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions crates/oxc_language_server/fixtures/formatter/basic/basic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
class C1 {
#name: string;

public get name() {
return this.#name;
}

private set name(name: string) {
this.#name = name;
}
}

class C2 {
#name: string;

private set name(name: string) {
this.#name = name;
}

public get name() {
return this.#name;
}
}

const c1 = new C1();
const c2 = new C2();


// no error
c1.name;

// no error
c2.name;
2 changes: 2 additions & 0 deletions crates/oxc_language_server/src/formatter/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
pub mod options;
pub mod server_formatter;
#[cfg(test)]
mod tester;
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ fn compute_minimal_text_edit<'a>(
#[cfg(test)]
mod tests {
use super::compute_minimal_text_edit;
use crate::formatter::{options::FormatOptions, tester::Tester};

#[test]
#[should_panic(expected = "assertion failed")]
Expand Down Expand Up @@ -188,4 +189,10 @@ mod tests {
let (start, end, replacement) = compute_minimal_text_edit(&src, &formatted);
assert_eq!((start, end, replacement), (0, 0, "b"));
}

#[test]
fn test_formatter() {
Tester::new("fixtures/formatter/basic", Some(FormatOptions { experimental: true }))
.format_and_snapshot_single_file("basic.ts");
}
}
91 changes: 91 additions & 0 deletions crates/oxc_language_server/src/formatter/tester.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use std::{fmt::Write, path::PathBuf};

use tower_lsp_server::{
UriExt,
lsp_types::{TextEdit, Uri},
};

use crate::{formatter::options::FormatOptions, options::Options, worker::WorkspaceWorker};

/// Given a file path relative to the crate root directory, return the absolute path of the file.
pub fn get_file_path(relative_file_path: &str) -> PathBuf {
std::env::current_dir().expect("could not get current dir").join(relative_file_path)
}

/// Given a file path relative to the crate root directory, return the URI of the file.
pub fn get_file_uri(relative_file_path: &str) -> Uri {
Uri::from_file_path(get_file_path(relative_file_path))
.expect("failed to convert file path to URL")
}

fn get_snapshot_from_text_edits(edits: &[TextEdit]) -> String {
edits
.iter()
.map(|edit| format!("{:#?},\n\n{:?}", edit.range, edit.new_text))
.collect::<Vec<_>>()
.join("\n")
}

/// Testing struct for the [formatter server][crate::formatter::server_formatter::ServerFormatter].
pub struct Tester<'t> {
relative_root_dir: &'t str,
options: Option<FormatOptions>,
}

impl Tester<'_> {
pub fn new(relative_root_dir: &'static str, options: Option<FormatOptions>) -> Self {
Self { relative_root_dir, options }
}

async fn create_workspace_worker(&self) -> WorkspaceWorker {
let absolute_path = std::env::current_dir()
.expect("could not get current dir")
.join(self.relative_root_dir);
let uri = Uri::from_file_path(absolute_path).expect("could not convert current dir to uri");
let worker = WorkspaceWorker::new(uri);
let option =
&Options { format: self.options.clone().unwrap_or_default(), ..Default::default() };
worker.start_worker(option).await;

worker
}

pub fn format_and_snapshot_single_file(&self, relative_file_path: &str) {
self.format_and_snapshot_multiple_file(&[relative_file_path]);
}

#[expect(clippy::disallowed_methods)]
pub fn format_and_snapshot_multiple_file(&self, relative_file_paths: &[&str]) {
let mut snapshot_result = String::new();
for relative_file_path in relative_file_paths {
let uri = get_file_uri(&format!("{}/{}", self.relative_root_dir, relative_file_path));
let formatted = tokio::runtime::Runtime::new().unwrap().block_on(async {
self.create_workspace_worker().await.format_file(&uri, None).await
});

let snapshot = if let Some(formatted) = formatted {
get_snapshot_from_text_edits(&formatted)
} else {
"File is ignored".to_string()
};

let _ = write!(
snapshot_result,
"########## \nfile: {}/{relative_file_path}\n----------\n{snapshot}\n",
self.relative_root_dir
);
}

let snapshot_name = self.relative_root_dir.replace('/', "_");
let mut settings = insta::Settings::clone_current();
settings.set_snapshot_path(
std::env::current_dir().expect("could not get current dir").join("src/snapshots"),
);
settings.set_prepend_module_to_snapshot(false);
settings.set_omit_expression(true);
settings.set_snapshot_suffix(relative_file_paths.join("_").replace('\\', "/"));
settings.bind(|| {
insta::assert_snapshot!(snapshot_name, snapshot_result);
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
source: crates/oxc_language_server/src/formatter/tester.rs
---
##########
file: fixtures/formatter/basic/basic.ts
----------
Range {
start: Position {
line: 1,
character: 2,
},
end: Position {
line: 26,
character: 0,
},
},

"#name: string;\n\n public get name() {\n return this.#name;\n }\n\n private set name(name: string) {\n this.#name = name;\n }\n}\n\nclass C2 {\n #name: string;\n\n private set name(name: string) {\n this.#name = name;\n }\n\n public get name() {\n return this.#name;\n }\n}\n\nconst c1 = new C1();\nconst c2 = new C2();"
Loading