Skip to content

Commit 26955eb

Browse files
committed
refactor(language_server): pass serde_json::Value to WorkspaceWorker configuration changes
1 parent 56c6627 commit 26955eb

File tree

8 files changed

+150
-207
lines changed

8 files changed

+150
-207
lines changed

crates/oxc_language_server/src/backend.rs

Lines changed: 16 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use crate::{
2424
commands::{FIX_ALL_COMMAND_ID, FixAllCommandArgs},
2525
file_system::LSPFileSystem,
2626
linter::options::Run,
27-
options::{Options, WorkspaceOption},
27+
options::WorkspaceOption,
2828
worker::WorkspaceWorker,
2929
};
3030

@@ -73,23 +73,22 @@ impl LanguageServer for Backend {
7373
async fn initialize(&self, params: InitializeParams) -> Result<InitializeResult> {
7474
let server_version = env!("CARGO_PKG_VERSION");
7575
// initialization_options can be anything, so we are requesting `workspace/configuration` when no initialize options are provided
76-
let options = params.initialization_options.and_then(|mut value| {
76+
let options = params.initialization_options.and_then(|value| {
7777
// the client supports the new settings object
7878
if let Ok(new_settings) = serde_json::from_value::<Vec<WorkspaceOption>>(value.clone())
7979
{
8080
// ToDo: validate they have the same length as params.workspace_folders
8181
return Some(new_settings);
8282
}
8383

84-
let deprecated_settings =
85-
serde_json::from_value::<Options>(value.get_mut("settings")?.take()).ok();
84+
let deprecated_settings = value.get("settings");
8685

8786
// the client has deprecated settings and has a deprecated root uri.
8887
// handle all things like the old way
8988
if deprecated_settings.is_some() && params.root_uri.is_some() {
9089
return Some(vec![WorkspaceOption {
9190
workspace_uri: params.root_uri.clone().unwrap(),
92-
options: deprecated_settings.unwrap(),
91+
options: deprecated_settings.unwrap().clone(),
9392
}]);
9493
}
9594

@@ -186,13 +185,11 @@ impl LanguageServer for Backend {
186185
self.request_workspace_configuration(needed_configurations.keys().collect()).await
187186
} else {
188187
// every worker should be initialized already in `initialize` request
189-
vec![Some(Options::default()); needed_configurations.len()]
188+
vec![serde_json::Value::Null; needed_configurations.len()]
190189
};
191-
let default_options = Options::default();
192190

193191
for (index, worker) in needed_configurations.values().enumerate() {
194-
let configuration =
195-
configurations.get(index).unwrap_or(&None).as_ref().unwrap_or(&default_options);
192+
let configuration = configurations.get(index).unwrap_or(&serde_json::Value::Null);
196193

197194
worker.start_worker(configuration).await;
198195
}
@@ -262,14 +259,12 @@ impl LanguageServer for Backend {
262259
.ok()
263260
.or_else(|| {
264261
// fallback to old configuration
265-
let options = serde_json::from_value::<Options>(params.settings).ok()?;
266-
267262
// for all workers (default only one)
268263
let options = workers
269264
.iter()
270265
.map(|worker| WorkspaceOption {
271266
workspace_uri: worker.get_root_uri().clone(),
272-
options: options.clone(),
267+
options: params.settings.clone(),
273268
})
274269
.collect();
275270

@@ -295,12 +290,9 @@ impl LanguageServer for Backend {
295290
configs
296291
.iter()
297292
.enumerate()
298-
// filter out results where the client did not return a configuration
299-
.filter_map(|(index, config)| {
300-
config.as_ref().map(|options| WorkspaceOption {
301-
workspace_uri: workers[index].get_root_uri().clone(),
302-
options: options.clone(),
303-
})
293+
.map(|(index, config)| WorkspaceOption {
294+
workspace_uri: workers[index].get_root_uri().clone(),
295+
options: config.clone(),
304296
})
305297
.collect::<Vec<_>>()
306298
} else {
@@ -423,8 +415,6 @@ impl LanguageServer for Backend {
423415

424416
self.publish_all_diagnostics(&cleared_diagnostics).await;
425417

426-
let default_options = Options::default();
427-
428418
// client support `workspace/configuration` request
429419
if self.capabilities.get().is_some_and(|capabilities| capabilities.workspace_configuration)
430420
{
@@ -437,9 +427,7 @@ impl LanguageServer for Backend {
437427
for (index, folder) in params.event.added.iter().enumerate() {
438428
let worker = WorkspaceWorker::new(folder.uri.clone());
439429
// get the configuration from the response and init the linter
440-
let options = configurations.get(index).unwrap_or(&None);
441-
let options = options.as_ref().unwrap_or(&default_options);
442-
430+
let options = configurations.get(index).unwrap_or(&serde_json::Value::Null);
443431
worker.start_worker(options).await;
444432

445433
added_registrations.extend(worker.init_watchers().await);
@@ -450,7 +438,7 @@ impl LanguageServer for Backend {
450438
for folder in params.event.added {
451439
let worker = WorkspaceWorker::new(folder.uri);
452440
// use default options
453-
worker.start_worker(&default_options).await;
441+
worker.start_worker(&serde_json::Value::Null).await;
454442
workers.push(worker);
455443
}
456444
}
@@ -675,7 +663,7 @@ impl Backend {
675663
/// Request the workspace configuration from the client
676664
/// and return the options for each workspace folder.
677665
/// The check if the client support workspace configuration, should be done before.
678-
async fn request_workspace_configuration(&self, uris: Vec<&Uri>) -> Vec<Option<Options>> {
666+
async fn request_workspace_configuration(&self, uris: Vec<&Uri>) -> Vec<serde_json::Value> {
679667
let length = uris.len();
680668
let config_items = uris
681669
.into_iter()
@@ -688,20 +676,15 @@ impl Backend {
688676
let Ok(configs) = self.client.configuration(config_items).await else {
689677
debug!("failed to get configuration");
690678
// return none for each workspace folder
691-
return vec![None; length];
679+
return vec![serde_json::Value::Null; length];
692680
};
693681

694-
let mut options = vec![];
695-
for config in configs {
696-
options.push(serde_json::from_value::<Options>(config).ok());
697-
}
698-
699682
debug_assert!(
700-
options.len() == length,
683+
configs.len() == length,
701684
"the number of configuration items should be the same as the number of workspace folders"
702685
);
703686

704-
options
687+
configs
705688
}
706689

707690
/// Clears all diagnostics for workspace folders

crates/oxc_language_server/src/formatter/server_formatter.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,10 @@ fn compute_minimal_text_edit<'a>(
181181

182182
#[cfg(test)]
183183
mod tests {
184+
use serde_json::json;
185+
184186
use super::compute_minimal_text_edit;
185-
use crate::formatter::{options::FormatOptions, tester::Tester};
187+
use crate::formatter::tester::Tester;
186188

187189
#[test]
188190
#[should_panic(expected = "assertion failed")]
@@ -269,7 +271,9 @@ mod tests {
269271
fn test_formatter() {
270272
Tester::new(
271273
"fixtures/formatter/basic",
272-
Some(FormatOptions { experimental: true, ..Default::default() }),
274+
json!({
275+
"fmt.experimental": true
276+
}),
273277
)
274278
.format_and_snapshot_single_file("basic.ts");
275279
}
@@ -278,7 +282,9 @@ mod tests {
278282
fn test_root_config_detection() {
279283
Tester::new(
280284
"fixtures/formatter/root_config",
281-
Some(FormatOptions { experimental: true, ..Default::default() }),
285+
json!({
286+
"fmt.experimental": true
287+
}),
282288
)
283289
.format_and_snapshot_single_file("semicolons-as-needed.ts");
284290
}
@@ -287,9 +293,9 @@ mod tests {
287293
fn test_custom_config_path() {
288294
Tester::new(
289295
"fixtures/formatter/custom_config_path",
290-
Some(FormatOptions {
291-
experimental: true,
292-
config_path: Some("./format.json".to_string()),
296+
json!({
297+
"fmt.experimental": true,
298+
"fmt.configPath": "./format.json",
293299
}),
294300
)
295301
.format_and_snapshot_single_file("semicolons-as-needed.ts");

crates/oxc_language_server/src/formatter/tester.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use tower_lsp_server::{
55
lsp_types::{TextEdit, Uri},
66
};
77

8-
use crate::{formatter::options::FormatOptions, options::Options, worker::WorkspaceWorker};
8+
use crate::worker::WorkspaceWorker;
99

1010
/// Given a file path relative to the crate root directory, return the absolute path of the file.
1111
pub fn get_file_path(relative_file_path: &str) -> PathBuf {
@@ -45,11 +45,11 @@ fn get_snapshot_from_text_edits(edits: &[TextEdit]) -> String {
4545
/// Testing struct for the [formatter server][crate::formatter::server_formatter::ServerFormatter].
4646
pub struct Tester<'t> {
4747
relative_root_dir: &'t str,
48-
options: Option<FormatOptions>,
48+
options: serde_json::Value,
4949
}
5050

5151
impl Tester<'_> {
52-
pub fn new(relative_root_dir: &'static str, options: Option<FormatOptions>) -> Self {
52+
pub fn new(relative_root_dir: &'static str, options: serde_json::Value) -> Self {
5353
Self { relative_root_dir, options }
5454
}
5555

@@ -59,9 +59,7 @@ impl Tester<'_> {
5959
.join(self.relative_root_dir);
6060
let uri = Uri::from_file_path(absolute_path).expect("could not convert current dir to uri");
6161
let worker = WorkspaceWorker::new(uri);
62-
let option =
63-
&Options { format: self.options.clone().unwrap_or_default(), ..Default::default() };
64-
worker.start_worker(option).await;
62+
worker.start_worker(&self.options).await;
6563

6664
worker
6765
}

crates/oxc_language_server/src/linter/options.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ pub enum Run {
2525
#[serde(rename_all = "camelCase")]
2626
pub struct LintOptions {
2727
pub run: Run, // TODO: the client wants maybe only the formatter, make it optional
28+
#[serde(skip_serializing_if = "Option::is_none")]
2829
pub config_path: Option<String>,
30+
#[serde(skip_serializing_if = "Option::is_none")]
2931
pub ts_config_path: Option<String>,
3032
pub unused_disable_directives: UnusedDisableDirectives,
3133
pub type_aware: bool,

0 commit comments

Comments
 (0)