From a420d9cdc73738a38e380671364d05f1c829bb12 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Wed, 6 Sep 2023 13:57:50 +0300 Subject: [PATCH] Add prettier search --- Cargo.lock | 3 ++ crates/prettier/Cargo.toml | 3 ++ crates/prettier/src/prettier.rs | 67 +++++++++++++++++++++++++++++---- 3 files changed, 66 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a0daee9305..9761e040d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5526,6 +5526,9 @@ dependencies = [ "futures 0.3.28", "gpui", "language", + "serde", + "serde_derive", + "serde_json", ] [[package]] diff --git a/crates/prettier/Cargo.toml b/crates/prettier/Cargo.toml index 821cde7b3a..77a845b5b3 100644 --- a/crates/prettier/Cargo.toml +++ b/crates/prettier/Cargo.toml @@ -11,6 +11,9 @@ language = { path = "../language" } gpui = { path = "../gpui" } fs = { path = "../fs" } +serde.workspace = true +serde_derive.workspace = true +serde_json.workspace = true anyhow.workspace = true futures.workspace = true diff --git a/crates/prettier/src/prettier.rs b/crates/prettier/src/prettier.rs index a38f8f8651..ca53bb7a03 100644 --- a/crates/prettier/src/prettier.rs +++ b/crates/prettier/src/prettier.rs @@ -1,4 +1,4 @@ -use std::collections::VecDeque; +use std::collections::{HashMap, VecDeque}; pub use std::path::{Path, PathBuf}; pub use std::sync::Arc; @@ -40,7 +40,7 @@ impl Prettier { starting_path: Option, fs: Arc, ) -> anyhow::Result { - let paths_to_check = match starting_path { + let paths_to_check = match starting_path.as_ref() { Some(starting_path) => { let worktree_root = starting_path .worktree_root_path @@ -131,12 +131,16 @@ impl Prettier { None => Vec::new(), }; - if dbg!(paths_to_check).is_empty() { - // TODO kb return the default prettier, how, without state? - } else { - // TODO kb now check all paths to check for prettier + match find_closest_prettier_path(paths_to_check, fs.as_ref()) + .await + .with_context(|| format!("Finding prettier starting with {starting_path:?}"))? + { + Some(prettier_path) => Ok(prettier_path), + None => { + // TODO kb return the default prettier, how, without state? + Ok(PathBuf::new()) + } } - Ok(PathBuf::new()) } pub async fn start(prettier_path: &Path, node: Arc) -> anyhow::Result { @@ -151,3 +155,52 @@ impl Prettier { todo!() } } + +const PRETTIER_PACKAGE_NAME: &str = "prettier"; +async fn find_closest_prettier_path( + paths_to_check: Vec, + fs: &dyn Fs, +) -> anyhow::Result> { + for path in paths_to_check { + let possible_package_json = path.join("package.json"); + if let Some(package_json_metadata) = fs + .metadata(&path) + .await + .with_context(|| format!("Fetching metadata for {possible_package_json:?}"))? + { + if !package_json_metadata.is_dir && !package_json_metadata.is_symlink { + let package_json_contents = fs + .load(&possible_package_json) + .await + .with_context(|| format!("reading {possible_package_json:?} file contents"))?; + if let Ok(json_contents) = serde_json::from_str::>( + &package_json_contents, + ) { + if let Some(serde_json::Value::Object(o)) = json_contents.get("dependencies") { + if o.contains_key(PRETTIER_PACKAGE_NAME) { + return Ok(Some(path)); + } + } + if let Some(serde_json::Value::Object(o)) = json_contents.get("devDependencies") + { + if o.contains_key(PRETTIER_PACKAGE_NAME) { + return Ok(Some(path)); + } + } + } + } + } + + let possible_node_modules_location = path.join("node_modules").join(PRETTIER_PACKAGE_NAME); + if let Some(node_modules_location_metadata) = fs + .metadata(&path) + .await + .with_context(|| format!("fetching metadata for {possible_node_modules_location:?}"))? + { + if node_modules_location_metadata.is_dir { + return Ok(Some(path)); + } + } + } + Ok(None) +}