diff --git a/Cargo.lock b/Cargo.lock index 59008fad76d3..3dc7556e0e67 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -797,8 +797,8 @@ dependencies = [ "biome_js_parser", "biome_js_semantic", "biome_js_syntax", + "biome_package", "biome_plugin_loader", - "biome_project", "biome_rowan", "biome_string_case", "biome_suppression", @@ -1114,7 +1114,7 @@ dependencies = [ "biome_json_formatter", "biome_json_parser", "biome_json_syntax", - "biome_project", + "biome_package", "biome_rowan", "biome_test_utils", "camino", @@ -1123,6 +1123,26 @@ dependencies = [ "tests_macros", ] +[[package]] +name = "biome_package" +version = "0.5.7" +dependencies = [ + "biome_console", + "biome_deserialize", + "biome_deserialize_macros", + "biome_diagnostics", + "biome_json_parser", + "biome_json_syntax", + "biome_parser", + "biome_rowan", + "biome_text_size", + "insta", + "node-semver", + "rustc-hash 2.1.0", + "serde", + "tests_macros", +] + [[package]] name = "biome_parser" version = "0.5.7" @@ -1157,26 +1177,6 @@ dependencies = [ "serde", ] -[[package]] -name = "biome_project" -version = "0.5.7" -dependencies = [ - "biome_console", - "biome_deserialize", - "biome_deserialize_macros", - "biome_diagnostics", - "biome_json_parser", - "biome_json_syntax", - "biome_parser", - "biome_rowan", - "biome_text_size", - "insta", - "node-semver", - "rustc-hash 2.1.0", - "serde", - "tests_macros", -] - [[package]] name = "biome_rowan" version = "0.5.7" @@ -1232,8 +1232,8 @@ dependencies = [ "biome_json_formatter", "biome_json_parser", "biome_json_syntax", + "biome_package", "biome_parser", - "biome_project", "biome_rowan", "biome_string_case", "biome_text_edit", @@ -1290,7 +1290,7 @@ dependencies = [ "biome_diagnostics", "biome_formatter", "biome_json_parser", - "biome_project", + "biome_package", "biome_rowan", "biome_service", "camino", diff --git a/Cargo.toml b/Cargo.toml index 3ca05029c80d..668a6c094bb1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -154,8 +154,8 @@ biome_yaml_parser = { version = "0.0.1", path = "./crates/biome_yaml_ biome_yaml_syntax = { version = "0.0.1", path = "./crates/biome_yaml_syntax" } biome_markup = { version = "0.5.7", path = "./crates/biome_markup" } +biome_package = { version = "0.5.7", path = "./crates/biome_package" } biome_parser = { version = "0.5.7", path = "./crates/biome_parser" } -biome_project = { version = "0.5.7", path = "./crates/biome_project" } biome_rowan = { version = "0.5.7", path = "./crates/biome_rowan" } biome_string_case = { version = "0.5.7", path = "./crates/biome_string_case" } biome_suppression = { version = "0.5.7", path = "./crates/biome_suppression" } diff --git a/crates/biome_cli/src/commands/mod.rs b/crates/biome_cli/src/commands/mod.rs index b274698543c5..71491edeaf65 100644 --- a/crates/biome_cli/src/commands/mod.rs +++ b/crates/biome_cli/src/commands/mod.rs @@ -635,20 +635,6 @@ pub(crate) fn validate_configuration_diagnostics( Ok(()) } -fn resolve_manifest(fs: &dyn FileSystem) -> Result, WorkspaceError> { - let result = fs.auto_search( - &fs.working_directory().unwrap_or_default(), - &["package.json"], - false, - )?; - - if let Some(result) = result { - return Ok(Some((BiomePath::new(result.file_path), result.content))); - } - - Ok(None) -} - fn get_files_to_process_with_cli_options( since: Option<&str>, changed: bool, @@ -774,7 +760,6 @@ pub(crate) trait CommandRunner: Sized { /// - Configure the VCS integration /// - Computes the paths to traverse/handle. This changes based on the VCS arguments that were passed. /// - Register a project folder using the working directory. - /// - Resolves the closets manifest AKA `package.json` and registers it. /// - Updates the settings that belong to the project registered fn configure_workspace( &mut self, @@ -807,11 +792,6 @@ pub(crate) trait CommandRunner: Sized { open_uninitialized: true, })?; - let manifest_data = resolve_manifest(fs)?; - - if let Some((path, content)) = manifest_data { - workspace.set_manifest_for_project((project_key, path, content).into())?; - } workspace.update_settings(UpdateSettingsParams { project_key, workspace_directory: configuration_path.map(BiomePath::from), diff --git a/crates/biome_fs/src/interner.rs b/crates/biome_fs/src/interner.rs index 030170ace7cf..bb4dbb1f1bd9 100644 --- a/crates/biome_fs/src/interner.rs +++ b/crates/biome_fs/src/interner.rs @@ -3,11 +3,13 @@ use crossbeam::channel::{unbounded, Receiver, Sender}; use papaya::HashSet; use rustc_hash::FxBuildHasher; +pub type PathInternerSet = HashSet; + /// File paths interner cache /// /// The path interner stores an instance of [PathBuf] pub struct PathInterner { - storage: HashSet, + storage: PathInternerSet, handler: Sender, } @@ -32,4 +34,8 @@ impl PathInterner { } result } + + pub fn into_paths(self) -> PathInternerSet { + self.storage + } } diff --git a/crates/biome_fs/src/lib.rs b/crates/biome_fs/src/lib.rs index 9d14396bfc21..b1ead3c80fdf 100644 --- a/crates/biome_fs/src/lib.rs +++ b/crates/biome_fs/src/lib.rs @@ -9,5 +9,5 @@ pub use fs::{ FileSystemExt, FsErrorKind, MemoryFileSystem, OpenOptions, OsFileSystem, TraversalContext, TraversalScope, }; -pub use interner::PathInterner; +pub use interner::{PathInterner, PathInternerSet}; pub use path::BiomePath; diff --git a/crates/biome_js_analyze/Cargo.toml b/crates/biome_js_analyze/Cargo.toml index 0f7c88b603ca..29b3db59022b 100644 --- a/crates/biome_js_analyze/Cargo.toml +++ b/crates/biome_js_analyze/Cargo.toml @@ -23,7 +23,7 @@ biome_glob = { workspace = true, features = ["biome_deserialize", biome_js_factory = { workspace = true } biome_js_semantic = { workspace = true } biome_js_syntax = { workspace = true } -biome_project = { workspace = true } +biome_package = { workspace = true } biome_rowan = { workspace = true } biome_string_case = { workspace = true } biome_suppression = { workspace = true } diff --git a/crates/biome_js_analyze/src/lib.rs b/crates/biome_js_analyze/src/lib.rs index 0709bc656dd7..c2f6446cdb44 100644 --- a/crates/biome_js_analyze/src/lib.rs +++ b/crates/biome_js_analyze/src/lib.rs @@ -9,7 +9,7 @@ use biome_analyze::{ use biome_aria::AriaRoles; use biome_diagnostics::Error as DiagnosticError; use biome_js_syntax::{JsFileSource, JsLanguage}; -use biome_project::PackageJson; +use biome_package::PackageJson; use biome_rowan::TextRange; use biome_suppression::{parse_suppression_comment, SuppressionDiagnostic}; use std::ops::Deref; @@ -164,7 +164,7 @@ mod tests { use biome_diagnostics::{print_diagnostic_to_string, Diagnostic, DiagnosticExt, Severity}; use biome_js_parser::{parse, JsParserOptions}; use biome_js_syntax::{JsFileSource, TextRange, TextSize}; - use biome_project::{Dependencies, PackageJson}; + use biome_package::{Dependencies, PackageJson}; use std::slice; use crate::{analyze, AnalysisFilter, ControlFlow}; diff --git a/crates/biome_js_analyze/src/services/manifest.rs b/crates/biome_js_analyze/src/services/manifest.rs index c471d8da1064..ba39c5a78ca5 100644 --- a/crates/biome_js_analyze/src/services/manifest.rs +++ b/crates/biome_js_analyze/src/services/manifest.rs @@ -3,7 +3,7 @@ use biome_analyze::{ RuleKey, ServiceBag, SyntaxVisitor, }; use biome_js_syntax::{AnyJsRoot, JsLanguage, JsSyntaxNode}; -use biome_project::PackageJson; +use biome_package::PackageJson; use biome_rowan::AstNode; use std::sync::Arc; diff --git a/crates/biome_js_analyze/tests/spec_tests.rs b/crates/biome_js_analyze/tests/spec_tests.rs index e3db091f9b6a..f62324e256d5 100644 --- a/crates/biome_js_analyze/tests/spec_tests.rs +++ b/crates/biome_js_analyze/tests/spec_tests.rs @@ -6,8 +6,8 @@ use biome_diagnostics::{DiagnosticExt, Severity}; use biome_fs::OsFileSystem; use biome_js_parser::{parse, JsParserOptions}; use biome_js_syntax::{JsFileSource, JsLanguage, ModuleKind}; +use biome_package::PackageType; use biome_plugin_loader::AnalyzerGritPlugin; -use biome_project::PackageType; use biome_rowan::AstNode; use biome_test_utils::{ assert_errors_are_absent, code_fix_to_string, create_analyzer_options, diagnostic_to_string, diff --git a/crates/biome_lsp/src/server.rs b/crates/biome_lsp/src/server.rs index e3769240c4b2..af3c7748d193 100644 --- a/crates/biome_lsp/src/server.rs +++ b/crates/biome_lsp/src/server.rs @@ -284,7 +284,6 @@ impl LanguageServer for LSPServer { futures::join!( self.session.load_extension_settings(), self.session.load_workspace_settings(), - self.session.load_manifest() ); let msg = format!("Server initialized with PID: {}", std::process::id()); @@ -323,14 +322,13 @@ impl LanguageServer for LSPServer { Ok(file_path) => { let base_path = self.session.base_path(); if let Some(base_path) = base_path { - let possible_rome_json = file_path.strip_prefix(&base_path); - if let Ok(watched_file) = possible_rome_json { + let possible_biome_json = file_path.strip_prefix(&base_path); + if let Ok(watched_file) = possible_biome_json { if ConfigName::file_names() .contains(&&*watched_file.display().to_string()) || watched_file.ends_with(".editorconfig") { self.session.load_workspace_settings().await; - self.session.load_manifest().await; self.setup_capabilities().await; self.session.update_all_diagnostics().await; // for now we are only interested to the configuration file, @@ -403,10 +401,17 @@ impl LanguageServer for LSPServer { match result { Ok(project_key) => { - self.session.insert_project(project_path, project_key); + self.session + .insert_project(project_path.clone(), project_key); + + self.session + .scan_project_folder(project_key, project_path) + .await; + + self.session.update_all_diagnostics().await; } Err(err) => { - error!("Failed to add project to the workspace: {}", err); + error!("Failed to add project to the workspace: {err}"); self.session .client .log_message(MessageType::ERROR, err) @@ -622,7 +627,6 @@ impl ServerFactory { workspace_method!(builder, scan_project_folder); workspace_method!(builder, close_project); workspace_method!(builder, open_file); - workspace_method!(builder, set_manifest_for_project); workspace_method!(builder, get_syntax_tree); workspace_method!(builder, get_control_flow_graph); workspace_method!(builder, get_formatter_ir); diff --git a/crates/biome_lsp/src/session.rs b/crates/biome_lsp/src/session.rs index c691fbd1fac6..7c4bb633d235 100644 --- a/crates/biome_lsp/src/session.rs +++ b/crates/biome_lsp/src/session.rs @@ -16,9 +16,10 @@ use biome_service::configuration::{ }; use biome_service::file_handlers::{AstroFileHandler, SvelteFileHandler, VueFileHandler}; use biome_service::projects::ProjectKey; +use biome_service::workspace::ScanProjectFolderParams; use biome_service::workspace::{ FeaturesBuilder, GetFileContentParams, OpenProjectParams, PullDiagnosticsParams, - SetManifestForProjectParams, SupportsFeatureParams, + SupportsFeatureParams, }; use biome_service::workspace::{RageEntry, RageParams, RageResult, UpdateSettingsParams}; use biome_service::Workspace; @@ -37,6 +38,7 @@ use std::sync::Arc; use std::sync::RwLock; use tokio::sync::Notify; use tokio::sync::OnceCell; +use tokio::task::spawn_blocking; use tower_lsp::lsp_types; use tower_lsp::lsp_types::{Diagnostic, Url}; use tower_lsp::lsp_types::{MessageType, Registration}; @@ -87,7 +89,6 @@ pub(crate) struct Session { pub(crate) cancellation: Arc, pub(crate) config_path: Option, - pub(crate) manifest_path: Option, } /// The parameters provided by the client in the "initialize" request @@ -182,7 +183,6 @@ impl Session { extension_settings: config, cancellation, config_path: None, - manifest_path: None, notified_broken_configuration: AtomicBool::new(false), } } @@ -472,7 +472,7 @@ impl Session { /// This function attempts to read the `biome.json` configuration file from /// the root URI and update the workspace settings accordingly #[tracing::instrument(level = "trace", skip(self))] - pub(crate) async fn load_workspace_settings(&self) { + pub(crate) async fn load_workspace_settings(self: &Arc) { // Providing a custom configuration path will not allow to support workspaces if let Some(config_path) = &self.config_path { let base_path = ConfigurationPathHint::FromUser(config_path.clone()); @@ -514,158 +514,133 @@ impl Session { } } + pub(crate) async fn scan_project_folder( + self: &Arc, + project_key: ProjectKey, + project_path: BiomePath, + ) { + let session = self.clone(); + let _ = spawn_blocking(move || { + let result = session + .workspace + .scan_project_folder(ScanProjectFolderParams { + project_key, + path: Some(project_path), + }); + if let Err(err) = result { + error!("Failed to scan project: {err}"); + } + }) + .await; + } + async fn load_biome_configuration_file( - &self, + self: &Arc, base_path: ConfigurationPathHint, ) -> ConfigurationStatus { - match load_configuration(self.workspace.fs(), base_path.clone()) { - Ok(loaded_configuration) => { - if loaded_configuration.has_errors() { - error!("Couldn't load the configuration file, reasons:"); - for diagnostic in loaded_configuration.as_diagnostics_iter() { - let message = PrintDescription(diagnostic).to_string(); - self.client.log_message(MessageType::ERROR, message).await; - } - ConfigurationStatus::Error - } else { - let LoadedConfiguration { - configuration: fs_configuration, - directory_path: configuration_path, - .. - } = loaded_configuration; - info!("Configuration loaded successfully from disk."); - info!("Update workspace settings."); - - let fs = self.workspace.fs(); - let should_use_editorconfig = - fs_configuration.use_editorconfig().unwrap_or_default(); - let mut configuration = if should_use_editorconfig { - let (editorconfig, editorconfig_diagnostics) = { - let search_path = configuration_path - .clone() - .unwrap_or_else(|| fs.working_directory().unwrap_or_default()); - match load_editorconfig(fs, search_path) { - Ok(result) => result, - Err(error) => { - error!( - "Failed load the `.editorconfig` file. Reason: {}", - error - ); - self.client.log_message(MessageType::ERROR, &error).await; - return ConfigurationStatus::Error; - } - } - }; - for diagnostic in editorconfig_diagnostics { - let message = PrintDescription(&diagnostic).to_string(); - self.client.log_message(MessageType::ERROR, message).await; - } - editorconfig.unwrap_or_default() - } else { - Default::default() - }; - - configuration.merge_with(fs_configuration); - - let result = - configuration.retrieve_gitignore_matches(fs, configuration_path.as_deref()); - - match result { - Ok((vcs_base_path, gitignore_matches)) => { - let register_result = match &base_path { - ConfigurationPathHint::FromLsp(path) - | ConfigurationPathHint::FromWorkspace(path) => { - self.workspace.open_project(OpenProjectParams { - path: path.as_path().into(), - open_uninitialized: true, - }) - } - _ => self.workspace.open_project(OpenProjectParams { - path: fs - .working_directory() - .map(BiomePath::from) - .unwrap_or_default(), - open_uninitialized: true, - }), - }; - let project_key = match register_result { - Ok(result) => result, - Err(error) => { - error!("Failed to register the project folder: {error}"); - self.client.log_message(MessageType::ERROR, &error).await; - return ConfigurationStatus::Error; - } - }; - - let result = self.workspace.update_settings(UpdateSettingsParams { - project_key, - workspace_directory: configuration_path.map(BiomePath::from), - configuration, - vcs_base_path: vcs_base_path.map(BiomePath::from), - gitignore_matches, - }); - - if let Err(error) = result { - error!("Failed to set workspace settings: {}", error); - self.client.log_message(MessageType::ERROR, &error).await; - ConfigurationStatus::Error - } else { - ConfigurationStatus::Loaded - } - } - Err(err) => { - error!("Couldn't load the configuration file, reason:\n {}", err); - self.client.log_message(MessageType::ERROR, &err).await; - ConfigurationStatus::Error - } - } - } - } - + let loaded_configuration = match load_configuration(self.workspace.fs(), base_path.clone()) + { + Ok(loaded_configuration) => loaded_configuration, Err(err) => { - error!("Couldn't load the configuration file, reason:\n {}", err); + error!("Couldn't load the configuration file, reason:\n {err}"); self.client.log_message(MessageType::ERROR, &err).await; - ConfigurationStatus::Error + return ConfigurationStatus::Error; } + }; + + if loaded_configuration.has_errors() { + error!("Couldn't load the configuration file, reasons:"); + for diagnostic in loaded_configuration.as_diagnostics_iter() { + let message = PrintDescription(diagnostic).to_string(); + self.client.log_message(MessageType::ERROR, message).await; + } + return ConfigurationStatus::Error; } - } - #[tracing::instrument(level = "trace", skip(self))] - pub(crate) async fn load_manifest(&self) { - let Some(base_path) = self - .manifest_path - .as_deref() - .map(Utf8PathBuf::from) - .or(self.base_path()) - else { - return; - }; + info!("Configuration loaded successfully from disk."); + info!("Update workspace settings."); + + let LoadedConfiguration { + configuration: fs_configuration, + directory_path: configuration_path, + .. + } = loaded_configuration; let fs = self.workspace.fs(); - match fs.auto_search(&base_path, &["package.json"], false) { - Ok(Some(result)) => { - let biome_path = BiomePath::new(result.file_path); - let Some(project_key) = self.project_for_path(&biome_path) else { - error!("Cannot determine project for package.json file at {biome_path:?}"); - return; - }; - - let result = self - .workspace - .set_manifest_for_project(SetManifestForProjectParams { - project_key, - manifest_path: biome_path.clone(), - content: result.content, - version: 0, - }); - if let Err(err) = result { - error!("{err}"); + let should_use_editorconfig = fs_configuration.use_editorconfig().unwrap_or_default(); + let mut configuration = if should_use_editorconfig { + let (editorconfig, editorconfig_diagnostics) = { + let search_path = configuration_path + .clone() + .unwrap_or_else(|| fs.working_directory().unwrap_or_default()); + match load_editorconfig(fs, search_path) { + Ok(result) => result, + Err(error) => { + error!("Failed load the `.editorconfig` file. Reason: {error}"); + self.client.log_message(MessageType::ERROR, &error).await; + return ConfigurationStatus::Error; + } } + }; + for diagnostic in editorconfig_diagnostics { + let message = PrintDescription(&diagnostic).to_string(); + self.client.log_message(MessageType::ERROR, message).await; } - Ok(None) => {} + editorconfig.unwrap_or_default() + } else { + Default::default() + }; + + configuration.merge_with(fs_configuration); + + let result = configuration.retrieve_gitignore_matches(fs, configuration_path.as_deref()); + let (vcs_base_path, gitignore_matches) = match result { + Ok(result) => result, Err(err) => { - error!("Couldn't load the package.json file, reason:\n {err}"); + error!("Couldn't load the configuration file, reason:\n {err}"); + self.client.log_message(MessageType::ERROR, &err).await; + return ConfigurationStatus::Error; } + }; + + let path = match &base_path { + ConfigurationPathHint::FromLsp(path) | ConfigurationPathHint::FromWorkspace(path) => { + path.as_path().into() + } + _ => fs + .working_directory() + .map(BiomePath::from) + .unwrap_or_default(), + }; + let register_result = self.workspace.open_project(OpenProjectParams { + path: path.clone(), + open_uninitialized: true, + }); + let project_key = match register_result { + Ok(result) => result, + Err(error) => { + error!("Failed to register the project folder: {error}"); + self.client.log_message(MessageType::ERROR, &error).await; + return ConfigurationStatus::Error; + } + }; + + let result = self.workspace.update_settings(UpdateSettingsParams { + project_key, + workspace_directory: configuration_path.map(BiomePath::from), + configuration, + vcs_base_path: vcs_base_path.map(BiomePath::from), + gitignore_matches, + }); + + self.scan_project_folder(project_key, path).await; + + if let Err(error) = result { + error!("Failed to set workspace settings: {error}"); + self.client.log_message(MessageType::ERROR, &error).await; + ConfigurationStatus::Error + } else { + ConfigurationStatus::Loaded } } diff --git a/crates/biome_migrate/Cargo.toml b/crates/biome_migrate/Cargo.toml index efb25a92e84c..4584db5369a8 100644 --- a/crates/biome_migrate/Cargo.toml +++ b/crates/biome_migrate/Cargo.toml @@ -19,7 +19,7 @@ biome_console = { workspace = true } biome_diagnostics = { workspace = true } biome_json_factory = { workspace = true } biome_json_syntax = { workspace = true } -biome_project = { workspace = true } +biome_package = { workspace = true } biome_rowan = { workspace = true } camino = { workspace = true } rustc-hash = { workspace = true } diff --git a/crates/biome_migrate/src/version_services.rs b/crates/biome_migrate/src/version_services.rs index 34c3070aedee..d2c8a1bff785 100644 --- a/crates/biome_migrate/src/version_services.rs +++ b/crates/biome_migrate/src/version_services.rs @@ -12,11 +12,11 @@ pub(crate) struct VersionServices { } #[derive(Debug, Clone)] -pub(crate) struct TheVersion(pub(crate) biome_project::Version); +pub(crate) struct TheVersion(pub(crate) biome_package::Version); impl TheVersion { pub fn new(range: &str) -> Self { - Self(biome_project::Version::from(range)) + Self(biome_package::Version::from(range)) } } diff --git a/crates/biome_project/Cargo.toml b/crates/biome_package/Cargo.toml similarity index 92% rename from crates/biome_project/Cargo.toml rename to crates/biome_package/Cargo.toml index adf0ce85eade..9a6010a7c529 100644 --- a/crates/biome_project/Cargo.toml +++ b/crates/biome_package/Cargo.toml @@ -1,12 +1,12 @@ [package] authors.workspace = true categories.workspace = true -description = "Workspace project handler" +description = "Workspace package handler" edition.workspace = true homepage.workspace = true keywords.workspace = true license.workspace = true -name = "biome_project" +name = "biome_package" publish = true repository.workspace = true version = "0.5.7" diff --git a/crates/biome_project/src/diagnostics.rs b/crates/biome_package/src/diagnostics.rs similarity index 100% rename from crates/biome_project/src/diagnostics.rs rename to crates/biome_package/src/diagnostics.rs diff --git a/crates/biome_project/src/lib.rs b/crates/biome_package/src/lib.rs similarity index 73% rename from crates/biome_project/src/lib.rs rename to crates/biome_package/src/lib.rs index af54e20009dd..14432ceae4eb 100644 --- a/crates/biome_project/src/lib.rs +++ b/crates/biome_package/src/lib.rs @@ -1,6 +1,6 @@ mod diagnostics; mod license; -mod node_js_project; +mod node_js_package; pub use crate::diagnostics::{ProjectAnalyzeDiagnostic, ProjectDiagnostic}; use biome_deserialize::{DeserializationDiagnostic, Deserialized}; @@ -8,43 +8,39 @@ use biome_diagnostics::serde::Diagnostic; use biome_parser::diagnostic::ParseDiagnostic; use biome_rowan::Language; pub use license::generated::*; -pub use node_js_project::{Dependencies, NodeJsProject, PackageJson, PackageType, Version}; +pub use node_js_package::{Dependencies, NodeJsPackage, PackageJson, PackageType, Version}; use std::any::TypeId; use std::fmt::Debug; -use std::path::Path; pub(crate) type LanguageRoot = ::Root; -pub(crate) type ProjectRoot

= - <<

::Manifest as Manifest>::Language as Language>::Root; +pub(crate) type PackageRoot

= + <<

::Manifest as Manifest>::Language as Language>::Root; pub trait Manifest: Default + Debug { type Language: Language; - /// It loads the manifest of the project. It accepts the path where the manifest should be + /// It loads the manifest of the package. It accepts the path where the manifest should be fn deserialize_manifest(root: &LanguageRoot) -> Deserialized; } -/// An internal representation of a project. -pub trait Project { +/// An internal representation of a package. +pub trait Package { type Manifest: Manifest; - /// Use this function to prepare the project, like loading the manifest. - fn deserialize_manifest(&mut self, root: &ProjectRoot); - - /// The home directory of the project - fn project_path(&self) -> &Path; + /// Use this function to prepare the package, like loading the manifest. + fn deserialize_manifest(&mut self, root: &PackageRoot); fn manifest(&self) -> Option<&Self::Manifest> { None } - fn analyze(&self) -> ProjectAnalyzeResult; + fn analyze(&self) -> PackageAnalyzeResult; fn has_errors(&self) -> bool; } -pub struct ProjectAnalyzeResult { +pub struct PackageAnalyzeResult { pub diagnostics: Vec, } diff --git a/crates/biome_project/src/license/generated.rs b/crates/biome_package/src/license/generated.rs similarity index 100% rename from crates/biome_project/src/license/generated.rs rename to crates/biome_package/src/license/generated.rs diff --git a/crates/biome_project/src/license/mod.rs b/crates/biome_package/src/license/mod.rs similarity index 100% rename from crates/biome_project/src/license/mod.rs rename to crates/biome_package/src/license/mod.rs diff --git a/crates/biome_project/src/node_js_project/mod.rs b/crates/biome_package/src/node_js_package/mod.rs similarity index 77% rename from crates/biome_project/src/node_js_project/mod.rs rename to crates/biome_package/src/node_js_package/mod.rs index c6e36619de58..64f2ccfbfe40 100644 --- a/crates/biome_project/src/node_js_project/mod.rs +++ b/crates/biome_package/src/node_js_package/mod.rs @@ -1,17 +1,17 @@ mod package_json; mod tsconfig_json; -pub use crate::node_js_project::package_json::{Dependencies, PackageJson, PackageType, Version}; -use crate::node_js_project::tsconfig_json::TsConfigJson; -use crate::{Manifest, Project, ProjectAnalyzeDiagnostic, ProjectAnalyzeResult, LICENSE_LIST}; +pub use package_json::{Dependencies, PackageJson, PackageType, Version}; + use biome_rowan::Language; -use std::path::{Path, PathBuf}; + +use crate::{Manifest, Package, PackageAnalyzeResult, ProjectAnalyzeDiagnostic, LICENSE_LIST}; + +use tsconfig_json::TsConfigJson; #[derive(Default, Debug, Clone)] /// A Node.js project. -pub struct NodeJsProject { - /// The path where the project - pub manifest_path: PathBuf, +pub struct NodeJsPackage { /// The `package.json` manifest pub manifest: PackageJson, /// Diagnostics emitted during the operations @@ -20,7 +20,7 @@ pub struct NodeJsProject { pub tsconfig: TsConfigJson, } -impl NodeJsProject { +impl NodeJsPackage { pub fn deserialize_tsconfig(&mut self, content: &ProjectLanguageRoot) { let tsconfig = TsConfigJson::deserialize_manifest(content); let (tsconfig, deserialize_diagnostics) = tsconfig.consume(); @@ -34,7 +34,7 @@ impl NodeJsProject { pub(crate) type ProjectLanguageRoot = <::Language as Language>::Root; -impl Project for NodeJsProject { +impl Package for NodeJsPackage { type Manifest = PackageJson; fn deserialize_manifest(&mut self, content: &ProjectLanguageRoot) { @@ -47,15 +47,11 @@ impl Project for NodeJsProject { .collect(); } - fn project_path(&self) -> &Path { - self.manifest_path.as_path() - } - fn manifest(&self) -> Option<&Self::Manifest> { Some(&self.manifest) } - fn analyze(&self) -> ProjectAnalyzeResult { + fn analyze(&self) -> PackageAnalyzeResult { let mut diagnostics = vec![]; if let Some((license, range)) = &self.manifest.license { if !LICENSE_LIST.is_valid(license) { @@ -68,7 +64,7 @@ impl Project for NodeJsProject { } } - ProjectAnalyzeResult { diagnostics } + PackageAnalyzeResult { diagnostics } } fn has_errors(&self) -> bool { diff --git a/crates/biome_project/src/node_js_project/package_json.rs b/crates/biome_package/src/node_js_package/package_json.rs similarity index 100% rename from crates/biome_project/src/node_js_project/package_json.rs rename to crates/biome_package/src/node_js_package/package_json.rs diff --git a/crates/biome_project/src/node_js_project/tsconfig_json.rs b/crates/biome_package/src/node_js_package/tsconfig_json.rs similarity index 100% rename from crates/biome_project/src/node_js_project/tsconfig_json.rs rename to crates/biome_package/src/node_js_package/tsconfig_json.rs diff --git a/crates/biome_project/tests/manifest/invalid/license_invalid.json b/crates/biome_package/tests/manifest/invalid/license_invalid.json similarity index 100% rename from crates/biome_project/tests/manifest/invalid/license_invalid.json rename to crates/biome_package/tests/manifest/invalid/license_invalid.json diff --git a/crates/biome_project/tests/manifest/invalid/license_invalid.json.snap b/crates/biome_package/tests/manifest/invalid/license_invalid.json.snap similarity index 87% rename from crates/biome_project/tests/manifest/invalid/license_invalid.json.snap rename to crates/biome_package/tests/manifest/invalid/license_invalid.json.snap index 934785819bdc..3a1a24f89d7f 100644 --- a/crates/biome_project/tests/manifest/invalid/license_invalid.json.snap +++ b/crates/biome_package/tests/manifest/invalid/license_invalid.json.snap @@ -1,5 +1,5 @@ --- -source: crates/biome_project/tests/manifest_spec_tests.rs +source: crates/biome_package/tests/manifest_spec_tests.rs expression: license_invalid.json --- license_invalid.json:2:13 project ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ diff --git a/crates/biome_project/tests/manifest/invalid/license_not_string.json b/crates/biome_package/tests/manifest/invalid/license_not_string.json similarity index 100% rename from crates/biome_project/tests/manifest/invalid/license_not_string.json rename to crates/biome_package/tests/manifest/invalid/license_not_string.json diff --git a/crates/biome_project/tests/manifest/invalid/license_not_string.json.snap b/crates/biome_package/tests/manifest/invalid/license_not_string.json.snap similarity index 88% rename from crates/biome_project/tests/manifest/invalid/license_not_string.json.snap rename to crates/biome_package/tests/manifest/invalid/license_not_string.json.snap index e65a34ac5c75..266f2c581835 100644 --- a/crates/biome_project/tests/manifest/invalid/license_not_string.json.snap +++ b/crates/biome_package/tests/manifest/invalid/license_not_string.json.snap @@ -1,5 +1,5 @@ --- -source: crates/biome_project/tests/manifest_spec_tests.rs +source: crates/biome_package/tests/manifest_spec_tests.rs expression: license_not_string.json --- license_not_string.json:2:13 deserialize ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ diff --git a/crates/biome_project/tests/manifest/invalid/name.json b/crates/biome_package/tests/manifest/invalid/name.json similarity index 100% rename from crates/biome_project/tests/manifest/invalid/name.json rename to crates/biome_package/tests/manifest/invalid/name.json diff --git a/crates/biome_project/tests/manifest/invalid/name.json.snap b/crates/biome_package/tests/manifest/invalid/name.json.snap similarity index 88% rename from crates/biome_project/tests/manifest/invalid/name.json.snap rename to crates/biome_package/tests/manifest/invalid/name.json.snap index c9a33ef8baa7..a29f91db84d2 100644 --- a/crates/biome_project/tests/manifest/invalid/name.json.snap +++ b/crates/biome_package/tests/manifest/invalid/name.json.snap @@ -1,5 +1,5 @@ --- -source: crates/biome_project/tests/manifest_spec_tests.rs +source: crates/biome_package/tests/manifest_spec_tests.rs expression: name.json --- name.json:2:10 deserialize ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ diff --git a/crates/biome_project/tests/manifest/invalid/name.snap b/crates/biome_package/tests/manifest/invalid/name.snap similarity index 100% rename from crates/biome_project/tests/manifest/invalid/name.snap rename to crates/biome_package/tests/manifest/invalid/name.snap diff --git a/crates/biome_project/tests/manifest_spec_tests.rs b/crates/biome_package/tests/manifest_spec_tests.rs similarity index 93% rename from crates/biome_project/tests/manifest_spec_tests.rs rename to crates/biome_package/tests/manifest_spec_tests.rs index 468420cf7866..2b375a921633 100644 --- a/crates/biome_project/tests/manifest_spec_tests.rs +++ b/crates/biome_package/tests/manifest_spec_tests.rs @@ -1,6 +1,6 @@ use biome_diagnostics::{print_diagnostic_to_string, DiagnosticExt}; use biome_json_parser::{parse_json, JsonParserOptions}; -use biome_project::{NodeJsProject, Project}; +use biome_package::{NodeJsPackage, Package}; use std::ffi::OsStr; use std::fs::read_to_string; use std::path::Path; @@ -20,25 +20,25 @@ fn run_invalid_manifests(input: &'static str, _: &str, _: &str, _: &str) { let input_code = read_to_string(input_file) .unwrap_or_else(|err| panic!("failed to read {input_file:?}: {err:?}")); - let mut project = NodeJsProject::default(); + let mut package = NodeJsPackage::default(); match input_file.extension().map(OsStr::as_encoded_bytes) { Some(b"json") => { let parsed = parse_json(input_code.as_str(), JsonParserOptions::default()); - project.deserialize_manifest(&parsed.tree()); + package.deserialize_manifest(&parsed.tree()); } _ => { panic!("Extension not supported"); } }; - let result = project.analyze(); + let result = package.analyze(); assert!( - project.has_errors() || !result.diagnostics.is_empty(), + package.has_errors() || !result.diagnostics.is_empty(), "The file {input} should have diagnostics, but it doesn't have any" ); - let mut diagnostics_string = project + let mut diagnostics_string = package .diagnostics .into_iter() .map(|diagnostic| { @@ -74,7 +74,7 @@ fn run_invalid_tsconfig(input: &'static str, _: &str, _: &str, _: &str) { let input_code = read_to_string(input_file) .unwrap_or_else(|err| panic!("failed to read {input_file:?}: {err:?}")); - let mut project = NodeJsProject::default(); + let mut project = NodeJsPackage::default(); match input_file.extension().map(OsStr::as_encoded_bytes) { Some(b"json") => { let parsed = parse_json( @@ -131,7 +131,7 @@ fn run_valid_tsconfig(input: &'static str, _: &str, _: &str, _: &str) { let input_code = read_to_string(input_file) .unwrap_or_else(|err| panic!("failed to read {input_file:?}: {err:?}")); - let mut project = NodeJsProject::default(); + let mut project = NodeJsPackage::default(); match input_file.extension().map(OsStr::as_encoded_bytes) { Some(b"json") => { let parsed = parse_json( diff --git a/crates/biome_project/tests/tsconfig/invalid/tsconfig.invalid.baseUrl.json b/crates/biome_package/tests/tsconfig/invalid/tsconfig.invalid.baseUrl.json similarity index 100% rename from crates/biome_project/tests/tsconfig/invalid/tsconfig.invalid.baseUrl.json rename to crates/biome_package/tests/tsconfig/invalid/tsconfig.invalid.baseUrl.json diff --git a/crates/biome_project/tests/tsconfig/invalid/tsconfig.invalid.baseUrl.json.snap b/crates/biome_package/tests/tsconfig/invalid/tsconfig.invalid.baseUrl.json.snap similarity index 87% rename from crates/biome_project/tests/tsconfig/invalid/tsconfig.invalid.baseUrl.json.snap rename to crates/biome_package/tests/tsconfig/invalid/tsconfig.invalid.baseUrl.json.snap index 78e6cd7e72c7..7db400cfc322 100644 --- a/crates/biome_project/tests/tsconfig/invalid/tsconfig.invalid.baseUrl.json.snap +++ b/crates/biome_package/tests/tsconfig/invalid/tsconfig.invalid.baseUrl.json.snap @@ -1,5 +1,5 @@ --- -source: crates/biome_project/tests/manifest_spec_tests.rs +source: crates/biome_package/tests/manifest_spec_tests.rs expression: tsconfig.invalid.baseUrl.json --- tsconfig.invalid.baseUrl.json:2:14 deserialize ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ diff --git a/crates/biome_project/tests/tsconfig/valid/tsconfig.valid.baseUrl.json b/crates/biome_package/tests/tsconfig/valid/tsconfig.valid.baseUrl.json similarity index 100% rename from crates/biome_project/tests/tsconfig/valid/tsconfig.valid.baseUrl.json rename to crates/biome_package/tests/tsconfig/valid/tsconfig.valid.baseUrl.json diff --git a/crates/biome_project/tests/tsconfig/valid/tsconfig.valid.baseUrl.json.snap b/crates/biome_package/tests/tsconfig/valid/tsconfig.valid.baseUrl.json.snap similarity index 75% rename from crates/biome_project/tests/tsconfig/valid/tsconfig.valid.baseUrl.json.snap rename to crates/biome_package/tests/tsconfig/valid/tsconfig.valid.baseUrl.json.snap index 887d5fed0c03..e7e496329fa8 100644 --- a/crates/biome_project/tests/tsconfig/valid/tsconfig.valid.baseUrl.json.snap +++ b/crates/biome_package/tests/tsconfig/valid/tsconfig.valid.baseUrl.json.snap @@ -1,5 +1,5 @@ --- -source: crates/biome_project/tests/manifest_spec_tests.rs +source: crates/biome_package/tests/manifest_spec_tests.rs expression: tsconfig.valid.baseUrl.json --- ## Input diff --git a/crates/biome_project/tests/tsconfig/valid/tsconfig.valid.paths.json b/crates/biome_package/tests/tsconfig/valid/tsconfig.valid.paths.json similarity index 100% rename from crates/biome_project/tests/tsconfig/valid/tsconfig.valid.paths.json rename to crates/biome_package/tests/tsconfig/valid/tsconfig.valid.paths.json diff --git a/crates/biome_project/tests/tsconfig/valid/tsconfig.valid.paths.json.snap b/crates/biome_package/tests/tsconfig/valid/tsconfig.valid.paths.json.snap similarity index 85% rename from crates/biome_project/tests/tsconfig/valid/tsconfig.valid.paths.json.snap rename to crates/biome_package/tests/tsconfig/valid/tsconfig.valid.paths.json.snap index 59f5267e17b8..0d3d96f2a296 100644 --- a/crates/biome_project/tests/tsconfig/valid/tsconfig.valid.paths.json.snap +++ b/crates/biome_package/tests/tsconfig/valid/tsconfig.valid.paths.json.snap @@ -1,5 +1,5 @@ --- -source: crates/biome_project/tests/manifest_spec_tests.rs +source: crates/biome_package/tests/manifest_spec_tests.rs expression: tsconfig.valid.paths.json --- ## Input diff --git a/crates/biome_service/Cargo.toml b/crates/biome_service/Cargo.toml index 4549d0460273..a25238e95b0d 100644 --- a/crates/biome_service/Cargo.toml +++ b/crates/biome_service/Cargo.toml @@ -47,8 +47,8 @@ biome_json_analyze = { workspace = true } biome_json_formatter = { workspace = true, features = ["serde"] } biome_json_parser = { workspace = true } biome_json_syntax = { workspace = true } +biome_package = { workspace = true } biome_parser = { workspace = true } -biome_project = { workspace = true } biome_rowan = { workspace = true, features = ["serde"] } biome_string_case = { workspace = true } biome_text_edit = { workspace = true } diff --git a/crates/biome_service/src/file_handlers/mod.rs b/crates/biome_service/src/file_handlers/mod.rs index d12c4961035b..b3fe1fc21595 100644 --- a/crates/biome_service/src/file_handlers/mod.rs +++ b/crates/biome_service/src/file_handlers/mod.rs @@ -37,8 +37,8 @@ use biome_js_syntax::{ }; use biome_json_analyze::METADATA as json_metadata; use biome_json_syntax::{JsonFileSource, JsonLanguage}; +use biome_package::PackageJson; use biome_parser::AnyParse; -use biome_project::PackageJson; use biome_rowan::{FileSourceError, NodeCache}; use biome_string_case::StrLikeExtension; @@ -684,10 +684,10 @@ impl Features { /// Returns the [Capabilities] associated with a [BiomePath] pub(crate) fn get_capabilities( &self, - biome_path: &BiomePath, + path: &Utf8Path, language_hint: DocumentFileSource, ) -> Capabilities { - match DocumentFileSource::from_path(biome_path).or(language_hint) { + match DocumentFileSource::from_path(path).or(language_hint) { DocumentFileSource::Js(source) => match source.as_embedding_kind() { EmbeddingKind::Astro => self.astro.capabilities(), EmbeddingKind::Vue => self.vue.capabilities(), diff --git a/crates/biome_service/src/lib.rs b/crates/biome_service/src/lib.rs index 1ae2c352a94d..754fe6c435a4 100644 --- a/crates/biome_service/src/lib.rs +++ b/crates/biome_service/src/lib.rs @@ -2,6 +2,7 @@ pub mod documentation; pub mod file_handlers; pub mod matcher; +pub mod project_layout; pub mod projects; pub mod settings; pub mod workspace; diff --git a/crates/biome_service/src/project_layout.rs b/crates/biome_service/src/project_layout.rs new file mode 100644 index 000000000000..a9cfa3a8d06a --- /dev/null +++ b/crates/biome_service/src/project_layout.rs @@ -0,0 +1,106 @@ +use biome_package::{NodeJsPackage, Package, PackageJson}; +use biome_parser::AnyParse; +use camino::{Utf8Path, Utf8PathBuf}; +use papaya::HashMap; +use rustc_hash::FxBuildHasher; + +/// The layout used across all open projects. +/// +/// Projects are comprised of zero or more packages. This arrangement is +/// intended to reflect the common usage of monorepos, where a single repository +/// may host many packages, and each package is allowed to have its own +/// settings. +/// +/// For Biome, a project is where the **top-level** configuration file is, while +/// packages may have their own nested configuration files. +/// +/// As a data structure, the project layout is simply a flat mapping from paths +/// to package data. This means that in order to lookup the package that is +/// most relevant for a given file, we may need to do a dumb iteration over all +/// entries to find which is the closest match. This means performance becomes +/// O(N) with the number of open packages, so if this becomes a bottleneck, we +/// may want to reconsider this approach. For now though, it makes sense because +/// it makes it very easy for us to invalidate part of the layout when there are +/// file system changes. +#[derive(Debug, Default)] +pub struct ProjectLayout(HashMap); + +/// The information tracked for each package. +/// +/// Because Biome is intended to support multiple kinds of JavaScript projects, +/// the term "package" is somewhat loosely defined. It may be an NPM package, +/// a JSR package, or simply a directory with its own nested `biome.json`. +#[derive(Debug, Default)] +pub struct PackageData { + /// The settings of the package. + /// + /// Usually inferred from a configuration file, e.g. `biome.json`. + // TODO: Uncomment this. + // Probably best done when Ema has finished with https://github.com/biomejs/biome/pull/4845 + //settings: Settings, + + /// Optional Node.js-specific package information, if relevant for the + /// package. + node_package: Option, +} + +impl ProjectLayout { + pub fn get_node_manifest_for_path(&self, path: &Utf8Path) -> Option { + self.0 + .pin() + .iter() + .fold( + None::<(&Utf8PathBuf, PackageJson)>, + |result, (package_path, data)| { + let node_manifest = data + .node_package + .as_ref() + .map(|node_package| &node_package.manifest)?; + if path.strip_prefix(package_path).is_err() { + return None; + } + + result + .is_none_or(|(matched_package_path, _)| { + package_path.as_str().len() > matched_package_path.as_str().len() + }) + .then(|| (package_path, node_manifest.clone())) + }, + ) + .map(|(_, package_json)| package_json) + } + + pub fn insert_node_manifest(&self, path: Utf8PathBuf, manifest: AnyParse) { + self.0.pin().update_or_insert_with( + path, + |data| { + let mut node_js_package = NodeJsPackage { + manifest: Default::default(), + diagnostics: Default::default(), + tsconfig: data + .node_package + .as_ref() + .map(|package| package.tsconfig.clone()) + .unwrap_or_default(), + }; + node_js_package.deserialize_manifest(&manifest.tree()); + + PackageData { + node_package: Some(node_js_package), + } + }, + || { + let mut node_js_package = NodeJsPackage::default(); + node_js_package.deserialize_manifest(&manifest.tree()); + + PackageData { + node_package: Some(node_js_package), + } + }, + ); + } + + pub fn remove_package(&self, path: &Utf8Path) { + self.0.pin().remove(path); + } +} diff --git a/crates/biome_service/src/projects.rs b/crates/biome_service/src/projects.rs index 425643d148d4..c2662a2e9b14 100644 --- a/crates/biome_service/src/projects.rs +++ b/crates/biome_service/src/projects.rs @@ -1,8 +1,6 @@ use crate::is_dir; use crate::settings::{FilesSettings, Settings, DEFAULT_FILE_SIZE_LIMIT}; use crate::workspace::FeatureKind; -use biome_fs::BiomePath; -use biome_project::{NodeJsProject, PackageJson}; use camino::{Utf8Path, Utf8PathBuf}; use papaya::HashMap; use rustc_hash::FxBuildHasher; @@ -41,18 +39,13 @@ impl ProjectKey { #[derive(Debug, Default)] struct ProjectData { /// The root path of the project. This path should be **absolute**. - path: BiomePath, + path: Utf8PathBuf, - /// The settings of the project, usually inferred from the configuration - /// file e.g. `biome.json`. - settings: Settings, - - /// Optional Node.js-specific package information, if relevant for the - /// project. + /// The "root" settings of the project. /// - /// TODO: This should be moved into the upcoming `ProjectLayout` service - /// data. - package: Option, + /// Usually inferred from the **top-level** configuration file, + /// e.g. `biome.json`. + settings: Settings, } impl Projects { @@ -61,7 +54,6 @@ impl Projects { /// Returns the key of the newly inserted project, or returns an existing /// project key if a project with the given path already existed. pub fn insert_project(&self, path: Utf8PathBuf) -> ProjectKey { - let path = BiomePath::new(path); trace!("Insert workspace folder: {path:?}"); let data = self.0.pin(); @@ -77,7 +69,6 @@ impl Projects { ProjectData { path, settings: Settings::default(), - package: None, }, ); key @@ -114,44 +105,20 @@ impl Projects { let project_data = ProjectData { path: project_data.path.clone(), settings, - package: project_data.package.clone(), }; data.insert(project_key, project_data); } - pub fn get_manifest(&self, project_key: ProjectKey) -> Option { - self.0 - .pin() - .get(&project_key) - .and_then(|data| data.package.as_ref()) - .map(|project| project.manifest.clone()) - } - - pub fn get_project_path(&self, project_key: ProjectKey) -> Option { + pub fn get_project_path(&self, project_key: ProjectKey) -> Option { self.0.pin().get(&project_key).map(|data| data.path.clone()) } - pub fn insert_manifest(&self, project_key: ProjectKey, manifest: NodeJsProject) { - let data = self.0.pin(); - let Some(project_data) = data.get(&project_key) else { - return; - }; - - let project_data = ProjectData { - path: project_data.path.clone(), - settings: project_data.settings.clone(), - package: Some(manifest), - }; - - data.insert(project_key, project_data); - } - /// Checks whether the given `path` belongs to project with the given path /// and no other project. pub fn path_belongs_only_to_project_with_path( &self, - path: &BiomePath, + path: &Utf8Path, project_path: &Utf8Path, ) -> bool { let mut belongs_to_project = false; diff --git a/crates/biome_service/src/settings.rs b/crates/biome_service/src/settings.rs index 00cb198e05cb..8b0205dfefdb 100644 --- a/crates/biome_service/src/settings.rs +++ b/crates/biome_service/src/settings.rs @@ -61,7 +61,7 @@ pub struct Settings { } impl Settings { - /// The [PartialConfiguration] is merged into the project. + /// Merges the [PartialConfiguration] into the settings. #[tracing::instrument(level = "trace", skip(self))] pub fn merge_with_configuration( &mut self, diff --git a/crates/biome_service/src/workspace.rs b/crates/biome_service/src/workspace.rs index a06fcbe706e9..b94a7b307d96 100644 --- a/crates/biome_service/src/workspace.rs +++ b/crates/biome_service/src/workspace.rs @@ -542,27 +542,6 @@ pub enum FileContent { FromServer, } -#[derive(Debug, serde::Serialize, serde::Deserialize)] -#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] -#[serde(rename_all = "camelCase")] -pub struct SetManifestForProjectParams { - pub project_key: ProjectKey, - pub manifest_path: BiomePath, - pub content: String, - pub version: i32, -} - -impl From<(ProjectKey, BiomePath, String)> for SetManifestForProjectParams { - fn from((project_key, manifest_path, content): (ProjectKey, BiomePath, String)) -> Self { - Self { - project_key, - manifest_path, - content, - version: 0, - } - } -} - #[derive(Debug, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[serde(rename_all = "camelCase")] @@ -1032,16 +1011,6 @@ pub trait Workspace: Send + Sync + RefUnwindSafe { /// manage project settings on its own. fn update_settings(&self, params: UpdateSettingsParams) -> Result<(), WorkspaceError>; - /// Sets a new package manifest for the given project. - /// - /// This method should not be used in combination with - /// `scan_project_folder()`. When scanning is enabled, the server will - /// manage packages on its own. - fn set_manifest_for_project( - &self, - params: SetManifestForProjectParams, - ) -> Result<(), WorkspaceError>; - /// Closes the project with the given key. /// /// Any settings related to the project are unloaded, and any open files diff --git a/crates/biome_service/src/workspace/client.rs b/crates/biome_service/src/workspace/client.rs index 88ead7628625..c296de5c283c 100644 --- a/crates/biome_service/src/workspace/client.rs +++ b/crates/biome_service/src/workspace/client.rs @@ -1,7 +1,7 @@ use crate::workspace::{ CheckFileSizeParams, CheckFileSizeResult, CloseProjectParams, FileFeaturesResult, GetFileContentParams, IsPathIgnoredParams, OpenProjectParams, ProjectKey, RageParams, - RageResult, ServerInfo, SetManifestForProjectParams, + RageResult, ServerInfo, }; use crate::{TransportError, Workspace, WorkspaceError}; use biome_formatter::Printed; @@ -128,13 +128,6 @@ where self.request("biome/open_file", params) } - fn set_manifest_for_project( - &self, - params: SetManifestForProjectParams, - ) -> Result<(), WorkspaceError> { - self.request("biome/set_manifest_for_project", params) - } - fn open_project(&self, params: OpenProjectParams) -> Result { self.request("biome/open_project", params) } diff --git a/crates/biome_service/src/workspace/scanner.rs b/crates/biome_service/src/workspace/scanner.rs index 3a102c4ca4c1..164e7eed9232 100644 --- a/crates/biome_service/src/workspace/scanner.rs +++ b/crates/biome_service/src/workspace/scanner.rs @@ -9,7 +9,7 @@ use std::time::{Duration, Instant}; use biome_diagnostics::serde::Diagnostic; use biome_diagnostics::{Diagnostic as _, Error, Severity}; -use biome_fs::{BiomePath, PathInterner, TraversalContext, TraversalScope}; +use biome_fs::{BiomePath, PathInterner, PathInternerSet, TraversalContext, TraversalScope}; use crate::diagnostics::Panic; use crate::projects::ProjectKey; @@ -22,6 +22,9 @@ pub(crate) struct ScanResult { /// Diagnostics reported while scanning the project. pub diagnostics: Vec, + /// Set containing all scanned paths. + pub paths: PathInternerSet, + /// Duration of the full scan. pub duration: Duration, } @@ -38,7 +41,7 @@ pub(crate) fn scan( let collector = DiagnosticsCollector::new(); - let (duration, diagnostics) = thread::scope(|scope| { + let (duration, paths, diagnostics) = thread::scope(|scope| { let handler = thread::Builder::new() .name("biome::scanner".to_string()) .spawn_scoped(scope, || collector.run(diagnostics_receiver)) @@ -46,9 +49,9 @@ pub(crate) fn scan( // The traversal context is scoped to ensure all the channels it // contains are properly closed once scanning finishes. - let (duration, _evaluated_paths) = scan_folder( + let (duration, paths, _evaluated_paths) = scan_folder( folder, - &ScanContext { + ScanContext { workspace, project_key, interner, @@ -60,11 +63,12 @@ pub(crate) fn scan( // Wait for the collector thread to finish. let diagnostics = handler.join().unwrap(); - (duration, diagnostics) + (duration, paths, diagnostics) }); Ok(ScanResult { diagnostics, + paths, duration, }) } @@ -85,21 +89,26 @@ fn init_thread_pool() { /// Initiates the filesystem traversal tasks from the provided path and runs it to completion. /// /// Returns the duration of the process and the evaluated paths. -fn scan_folder(folder: &Utf8Path, ctx: &ScanContext) -> (Duration, BTreeSet) { +fn scan_folder( + folder: &Utf8Path, + ctx: ScanContext, +) -> (Duration, PathInternerSet, BTreeSet) { let start = Instant::now(); let fs = ctx.workspace.fs(); + let ctx_ref = &ctx; fs.traversal(Box::new(move |scope: &dyn TraversalScope| { - scope.evaluate(ctx, folder.to_path_buf()); + scope.evaluate(ctx_ref, folder.to_path_buf()); })); let paths = ctx.evaluated_paths(); fs.traversal(Box::new(|scope: &dyn TraversalScope| { for path in paths { - scope.handle(ctx, path.to_path_buf()); + scope.handle(ctx_ref, path.to_path_buf()); } })); - (start.elapsed(), ctx.evaluated_paths()) + let evaluated_paths = ctx.evaluated_paths(); + (start.elapsed(), ctx.interner.into_paths(), evaluated_paths) } struct DiagnosticsCollector { diff --git a/crates/biome_service/src/workspace/server.rs b/crates/biome_service/src/workspace/server.rs index ba4f0feda86b..9b2f27e4543d 100644 --- a/crates/biome_service/src/workspace/server.rs +++ b/crates/biome_service/src/workspace/server.rs @@ -7,13 +7,14 @@ use super::{ ParsePatternParams, ParsePatternResult, PatternId, ProjectKey, PullActionsParams, PullActionsResult, PullDiagnosticsParams, PullDiagnosticsResult, RenameResult, ScanProjectFolderParams, ScanProjectFolderResult, SearchPatternParams, SearchResults, - SetManifestForProjectParams, SupportsFeatureParams, UpdateSettingsParams, + SupportsFeatureParams, UpdateSettingsParams, }; use crate::diagnostics::FileTooLarge; use crate::file_handlers::{ Capabilities, CodeActionsParams, DocumentFileSource, FixAllParams, LintParams, ParseResult, }; use crate::is_dir; +use crate::project_layout::ProjectLayout; use crate::projects::Projects; use crate::workspace::{ FileFeaturesResult, GetFileContentParams, IsPathIgnoredParams, RageEntry, RageParams, @@ -29,13 +30,13 @@ use biome_diagnostics::{ serde::Diagnostic as SerdeDiagnostic, Diagnostic, DiagnosticExt, Severity, }; use biome_formatter::Printed; -use biome_fs::{BiomePath, ConfigName, FileSystem}; +use biome_fs::{BiomePath, ConfigName, FileSystem, PathInternerSet}; use biome_grit_patterns::{compile_pattern_with_options, CompilePatternOptions, GritQuery}; use biome_js_syntax::ModuleKind; -use biome_json_parser::{parse_json, JsonParserOptions}; +use biome_json_parser::JsonParserOptions; use biome_json_syntax::JsonFileSource; +use biome_package::{PackageJson, PackageType}; use biome_parser::AnyParse; -use biome_project::{NodeJsProject, PackageJson, PackageType, Project}; use biome_rowan::NodeCache; use camino::{Utf8Path, Utf8PathBuf}; use papaya::HashMap; @@ -43,17 +44,21 @@ use rustc_hash::{FxBuildHasher, FxHashMap}; use std::panic::RefUnwindSafe; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Mutex; -use tracing::{debug, info, info_span}; +use tracing::{debug, info, info_span, warn}; pub(super) struct WorkspaceServer { /// features available throughout the application features: Features, - /// global settings object for this workspace - settings: Projects, + /// Open projects, including their settings, nested packages, and other + /// metadata. + projects: Projects, + + /// The layout of projects and their internal packages. + project_layout: ProjectLayout, /// Stores the document (text content + version number) associated with a URL - documents: HashMap, + documents: HashMap, /// Stores the document sources used across the workspace file_sources: AppendOnlyVec, @@ -123,7 +128,8 @@ impl WorkspaceServer { pub(crate) fn new(fs: Box) -> Self { Self { features: Features::new(), - settings: Default::default(), + projects: Default::default(), + project_layout: Default::default(), documents: Default::default(), file_sources: AppendOnlyVec::default(), patterns: Default::default(), @@ -204,7 +210,7 @@ impl WorkspaceServer { } /// Retrieves the supported language of a file. - fn get_file_source(&self, path: &BiomePath) -> DocumentFileSource { + fn get_file_source(&self, path: &Utf8Path) -> DocumentFileSource { self.documents .pin() .get(path) @@ -217,7 +223,7 @@ impl WorkspaceServer { /// path. fn build_capability_error<'a>( &'a self, - path: &'a BiomePath, + path: &'a Utf8Path, // feature_name: &'a str, ) -> impl FnOnce() -> WorkspaceError + 'a { move || { @@ -232,18 +238,18 @@ impl WorkspaceServer { } } - /// Returns the manifest for the given project. - /// - /// TODO: This needs to be updated to support multiple packages within a - /// project. + /// Returns the parsed `package.json` for a given path. /// /// ## Errors /// /// - If no document is found in the workspace. Usually, you'll have to call /// [WorkspaceServer::set_manifest_for_project] to store said document. #[tracing::instrument(level = "trace", skip(self))] - fn get_manifest(&self, project_key: ProjectKey) -> Result, WorkspaceError> { - Ok(self.settings.get_manifest(project_key)) + fn get_node_manifest_for_path( + &self, + path: &Utf8Path, + ) -> Result, WorkspaceError> { + Ok(self.project_layout.get_node_manifest_for_path(path)) } /// Returns a previously inserted file source by index. @@ -291,8 +297,9 @@ impl WorkspaceServer { persist_node_cache, }: OpenFileParams, ) -> Result<(), WorkspaceError> { + let path: Utf8PathBuf = path.into(); let mut source = document_file_source.unwrap_or(DocumentFileSource::from_path(&path)); - let manifest = self.get_manifest(project_key)?; + let manifest = self.get_node_manifest_for_path(&path)?; if let DocumentFileSource::Js(js) = &mut source { if let Some(manifest) = manifest { @@ -310,7 +317,7 @@ impl WorkspaceServer { let mut index = self.insert_source(source); let size = content.as_bytes().len(); - let limit = self.settings.get_max_file_size(project_key); + let limit = self.projects.get_max_file_size(project_key); if size > limit { self.documents.pin().insert( path, @@ -336,7 +343,7 @@ impl WorkspaceServer { self.node_cache .lock() .unwrap() - .insert(path.to_path_buf(), node_cache); + .insert(path.clone(), node_cache); } { @@ -372,7 +379,7 @@ impl WorkspaceServer { // the document, which seems hardly worth it. // That said, I don't think this code is particularly pretty either // :sweat_smile: - if let Some(existing) = documents.get(&path) { + if let Some(existing) = documents.get(path.as_path()) { if existing.opened_by_scanner { document.opened_by_scanner = true; } @@ -409,23 +416,23 @@ impl WorkspaceServer { /// Retrieves the parser result for a given file. /// /// Returns an error if no file exists in the workspace with this path. - fn get_parse(&self, biome_path: &BiomePath) -> Result { + fn get_parse(&self, path: &Utf8Path) -> Result { let documents = self.documents.pin(); let syntax = documents - .get(biome_path) + .get(path) .map(|document| document.syntax.as_ref()) .ok_or_else(WorkspaceError::not_found)?; match syntax { Ok(syntax) => Ok(syntax.clone()), - Err(FileTooLarge { .. }) => Err(WorkspaceError::file_ignored(biome_path.to_string())), + Err(FileTooLarge { .. }) => Err(WorkspaceError::file_ignored(path.to_string())), } } fn parse( &self, project_key: ProjectKey, - biome_path: &BiomePath, + path: &Utf8Path, content: &str, file_source_index: usize, node_cache: &mut NodeCache, @@ -433,18 +440,18 @@ impl WorkspaceServer { let file_source = self .get_source(file_source_index) .ok_or_else(WorkspaceError::not_found)?; - let capabilities = self.features.get_capabilities(biome_path, file_source); + let capabilities = self.features.get_capabilities(path, file_source); let parse = capabilities .parser .parse - .ok_or_else(self.build_capability_error(biome_path))?; + .ok_or_else(self.build_capability_error(path))?; let parsed = parse( - biome_path, + &BiomePath::new(path), file_source, content, - self.settings.get_settings(project_key).as_ref(), + self.projects.get_settings(project_key).as_ref(), node_cache, ); Ok(parsed) @@ -460,7 +467,7 @@ impl WorkspaceServer { for feature in features.iter() { // a path is ignored if it's ignored by all features ignored &= self - .settings + .projects .is_ignored_by_feature_config(project_key, path, feature) } ignored @@ -475,7 +482,7 @@ impl WorkspaceServer { /// Check whether a file is ignored in the top-level config `files.ignore`/`files.include` fn is_ignored_by_top_level_config(&self, project_key: ProjectKey, path: &Utf8Path) -> bool { - let Some(files_settings) = self.settings.get_files_settings(project_key) else { + let Some(files_settings) = self.projects.get_files_settings(project_key) else { return false; }; @@ -499,6 +506,27 @@ impl WorkspaceServer { } }) } + + fn update_project_layout_for_paths(&self, paths: PathInternerSet) { + for path in paths.pin().iter() { + if let Err(error) = self.update_project_layout_for_path(path) { + warn!("Error while updating project layout: {error}"); + } + } + } + + fn update_project_layout_for_path(&self, path: &Utf8Path) -> Result<(), WorkspaceError> { + if path + .file_name() + .is_some_and(|filename| filename == "package.json") + { + let parsed = self.get_parse(path)?; + self.project_layout + .insert_node_manifest(path.to_path_buf(), parsed); + } + + Ok(()) + } } impl Workspace for WorkspaceServer { @@ -511,12 +539,12 @@ impl Workspace for WorkspaceServer { params: CheckFileSizeParams, ) -> Result { let documents = self.documents.pin(); - let Some(document) = documents.get(¶ms.path) else { + let Some(document) = documents.get(params.path.as_path()) else { return Err(WorkspaceError::not_found()); }; let file_size = document.content.as_bytes().len(); - let limit = self.settings.get_max_file_size(params.project_key); + let limit = self.projects.get_max_file_size(params.project_key); Ok(CheckFileSizeResult { file_size, limit }) } @@ -529,7 +557,7 @@ impl Workspace for WorkspaceServer { let capabilities = self.get_file_capabilities(¶ms.path); let language = DocumentFileSource::from_path(path); - let settings = self.settings.get_settings(project_key); + let settings = self.projects.get_settings(project_key); let mut file_features = FileFeaturesResult::new(); let file_name = path.file_name(); @@ -554,7 +582,7 @@ impl Workspace for WorkspaceServer { } else { for feature in params.features.iter() { if self - .settings + .projects .is_ignored_by_feature_config(project_key, path, feature) { file_features.ignored(feature); @@ -582,7 +610,7 @@ impl Workspace for WorkspaceServer { /// by another thread having previously panicked while holding the lock #[tracing::instrument(level = "trace", skip(self))] fn update_settings(&self, params: UpdateSettingsParams) -> Result<(), WorkspaceError> { - let Some(mut settings) = self.settings.get_settings(params.project_key) else { + let Some(mut settings) = self.projects.get_settings(params.project_key) else { return Err(WorkspaceError::no_project()); }; @@ -593,7 +621,7 @@ impl Workspace for WorkspaceServer { params.gitignore_matches.as_slice(), )?; - self.settings.set_settings(params.project_key, settings); + self.projects.set_settings(params.project_key, settings); Ok(()) } @@ -602,32 +630,6 @@ impl Workspace for WorkspaceServer { self.open_file_internal(false, params) } - fn set_manifest_for_project( - &self, - params: SetManifestForProjectParams, - ) -> Result<(), WorkspaceError> { - let index = self.insert_source(JsonFileSource::json().into()); - - let parsed = parse_json(params.content.as_str(), JsonParserOptions::default()); - - let mut node_js_project = NodeJsProject::default(); - node_js_project.deserialize_manifest(&parsed.tree()); - self.settings - .insert_manifest(params.project_key, node_js_project); - - self.documents.pin().insert( - params.manifest_path.clone(), - Document { - content: params.content, - version: params.version, - file_source_index: index, - syntax: Ok(parsed.into()), - opened_by_scanner: false, - }, - ); - Ok(()) - } - fn open_project(&self, params: OpenProjectParams) -> Result { let path = if params.open_uninitialized { let path = params.path.to_path_buf(); @@ -636,7 +638,7 @@ impl Workspace for WorkspaceServer { self.find_project_root(params.path)? }; - Ok(self.settings.insert_project(path)) + Ok(self.projects.insert_project(path)) } fn scan_project_folder( @@ -645,7 +647,8 @@ impl Workspace for WorkspaceServer { ) -> Result { let path = params .path - .or_else(|| self.settings.get_project_path(params.project_key)) + .map(Utf8PathBuf::from) + .or_else(|| self.projects.get_project_path(params.project_key)) .ok_or_else(WorkspaceError::no_project)?; // TODO: Need to register a file watcher. This should happen before we @@ -658,6 +661,8 @@ impl Workspace for WorkspaceServer { let result = scan(self, params.project_key, &path)?; + self.update_project_layout_for_paths(result.paths); + Ok(ScanProjectFolderResult { diagnostics: result.diagnostics, duration: result.duration, @@ -666,7 +671,7 @@ impl Workspace for WorkspaceServer { fn close_project(&self, params: CloseProjectParams) -> Result<(), WorkspaceError> { let project_path = self - .settings + .projects .get_project_path(params.project_key) .ok_or_else(WorkspaceError::no_project)?; @@ -677,7 +682,7 @@ impl Workspace for WorkspaceServer { for (path, document) in documents.iter() { if document.opened_by_scanner && self - .settings + .projects .path_belongs_only_to_project_with_path(path, &project_path) { documents.remove(path); @@ -686,7 +691,7 @@ impl Workspace for WorkspaceServer { } } - self.settings.remove_project(params.project_key); + self.projects.remove_project(params.project_key); Ok(()) } @@ -730,7 +735,7 @@ impl Workspace for WorkspaceServer { .debug .debug_formatter_ir .ok_or_else(self.build_capability_error(¶ms.path))?; - let settings = self.settings.get_settings(params.project_key); + let settings = self.projects.get_settings(params.project_key); let parse = self.get_parse(¶ms.path)?; if let Some(settings) = &settings { @@ -746,7 +751,7 @@ impl Workspace for WorkspaceServer { fn get_file_content(&self, params: GetFileContentParams) -> Result { self.documents .pin() - .get(¶ms.path) + .get(params.path.as_path()) .map(|document| document.content.clone()) .ok_or_else(WorkspaceError::not_found) } @@ -763,7 +768,7 @@ impl Workspace for WorkspaceServer { ) -> Result<(), WorkspaceError> { let documents = self.documents.pin(); let (index, opened_by_scanner) = documents - .get(&path) + .get(path.as_path()) .map(|document| { debug_assert!(version > document.version); (document.file_source_index, document.opened_by_scanner) @@ -800,7 +805,7 @@ impl Workspace for WorkspaceServer { } documents - .insert(path, document) + .insert(path.into(), document) .ok_or_else(WorkspaceError::not_found)?; Ok(()) } @@ -814,10 +819,10 @@ impl Workspace for WorkspaceServer { { let documents = self.documents.pin(); let document = documents - .get(¶ms.path) + .get(params.path.as_path()) .ok_or_else(WorkspaceError::not_found)?; if !document.opened_by_scanner { - documents.remove(¶ms.path); + documents.remove(params.path.as_path()); } } @@ -844,13 +849,13 @@ impl Workspace for WorkspaceServer { }: PullDiagnosticsParams, ) -> Result { let parse = self.get_parse(&path)?; - let manifest = self.get_manifest(project_key)?; + let manifest = self.get_node_manifest_for_path(&path)?; let (diagnostics, errors, skipped_diagnostics) = if let Some(lint) = self.get_file_capabilities(&path).analyzer.lint { info_span!("Pulling diagnostics", categories =? categories).in_scope(|| { let results = lint(LintParams { parse, - workspace: &self.settings.get_settings(project_key).into(), + workspace: &self.projects.get_settings(project_key).into(), max_diagnostics: max_diagnostics as u32, path: &path, only, @@ -914,12 +919,12 @@ impl Workspace for WorkspaceServer { .ok_or_else(self.build_capability_error(&path))?; let parse = self.get_parse(&path)?; - let manifest = self.get_manifest(project_key)?; + let manifest = self.get_node_manifest_for_path(&path)?; let language = self.get_file_source(&path); Ok(code_actions(CodeActionsParams { parse, range, - workspace: &self.settings.get_settings(project_key).into(), + workspace: &self.projects.get_settings(project_key).into(), path: &path, manifest, language, @@ -938,7 +943,7 @@ impl Workspace for WorkspaceServer { .formatter .format .ok_or_else(self.build_capability_error(¶ms.path))?; - let settings = self.settings.get_settings(params.project_key); + let settings = self.projects.get_settings(params.project_key); let parse = self.get_parse(¶ms.path)?; if let Some(settings) = &settings { @@ -956,7 +961,7 @@ impl Workspace for WorkspaceServer { .formatter .format_range .ok_or_else(self.build_capability_error(¶ms.path))?; - let settings = self.settings.get_settings(params.project_key); + let settings = self.projects.get_settings(params.project_key); let parse = self.get_parse(¶ms.path)?; if let Some(settings) = &settings { @@ -981,7 +986,7 @@ impl Workspace for WorkspaceServer { .format_on_type .ok_or_else(self.build_capability_error(¶ms.path))?; - let settings = self.settings.get_settings(params.project_key); + let settings = self.projects.get_settings(params.project_key); let parse = self.get_parse(¶ms.path)?; if let Some(settings) = &settings { if !settings.formatter().format_with_errors && parse.has_errors() { @@ -1021,12 +1026,12 @@ impl Workspace for WorkspaceServer { .ok_or_else(self.build_capability_error(&path))?; let parse = self.get_parse(&path)?; - let manifest = self.get_manifest(project_key)?; + let manifest = self.get_node_manifest_for_path(&path)?; let language = self.get_file_source(&path); fix_all(FixAllParams { parse, fix_file_mode, - workspace: self.settings.get_settings(project_key).into(), + workspace: self.projects.get_settings(project_key).into(), should_format, biome_path: &path, manifest, @@ -1092,7 +1097,7 @@ impl Workspace for WorkspaceServer { .search .search .ok_or_else(self.build_capability_error(&path))?; - let settings = self.settings.get_settings(project_key); + let settings = self.projects.get_settings(project_key); let parse = self.get_parse(&path)?; let document_file_source = self.get_file_source(&path); diff --git a/crates/biome_service/src/workspace_types.rs b/crates/biome_service/src/workspace_types.rs index 33e2f6fb85b6..9e505e46a5e1 100644 --- a/crates/biome_service/src/workspace_types.rs +++ b/crates/biome_service/src/workspace_types.rs @@ -451,12 +451,11 @@ macro_rules! workspace_method { } /// Returns a list of signature for all the methods in the [Workspace] trait -pub fn methods() -> [WorkspaceMethod; 22] { +pub fn methods() -> [WorkspaceMethod; 21] { [ workspace_method!(file_features), workspace_method!(update_settings), workspace_method!(open_project), - workspace_method!(set_manifest_for_project), workspace_method!(open_file), workspace_method!(change_file), workspace_method!(close_file), diff --git a/crates/biome_test_utils/Cargo.toml b/crates/biome_test_utils/Cargo.toml index 45063dedc335..6ac61a65b172 100644 --- a/crates/biome_test_utils/Cargo.toml +++ b/crates/biome_test_utils/Cargo.toml @@ -21,7 +21,7 @@ biome_deserialize = { workspace = true } biome_diagnostics = { workspace = true } biome_formatter = { workspace = true } biome_json_parser = { workspace = true } -biome_project = { workspace = true } +biome_package = { workspace = true } biome_rowan = { workspace = true } biome_service = { workspace = true } camino = { workspace = true } diff --git a/crates/biome_test_utils/src/lib.rs b/crates/biome_test_utils/src/lib.rs index 907a5f817d69..2c50e80b7d0a 100644 --- a/crates/biome_test_utils/src/lib.rs +++ b/crates/biome_test_utils/src/lib.rs @@ -6,7 +6,7 @@ use biome_console::markup; use biome_diagnostics::termcolor::Buffer; use biome_diagnostics::{DiagnosticExt, Error, PrintDiagnostic}; use biome_json_parser::{JsonParserOptions, ParseDiagnostic}; -use biome_project::PackageJson; +use biome_package::PackageJson; use biome_rowan::{SyntaxKind, SyntaxNode, SyntaxSlot}; use biome_service::configuration::to_analyzer_rules; use biome_service::file_handlers::DocumentFileSource; diff --git a/knope.toml b/knope.toml index f3a69658eb30..90da859221cc 100644 --- a/knope.toml +++ b/knope.toml @@ -164,9 +164,9 @@ versioned_files = ["crates/biome_markup/Cargo.toml"] [packages.biome_parser] changelog = "crates/biome_parser/CHANGELOG.md" versioned_files = ["crates/biome_parser/Cargo.toml"] -[packages.biome_project] -changelog = "crates/biome_project/CHANGELOG.md" -versioned_files = ["crates/biome_project/Cargo.toml"] +[packages.biome_package] +changelog = "crates/biome_package/CHANGELOG.md" +versioned_files = ["crates/biome_package/Cargo.toml"] [packages.biome_rowan] changelog = "crates/biome_rowan/CHANGELOG.md" versioned_files = ["crates/biome_rowan/Cargo.toml"] diff --git a/xtask/codegen/src/generate_license.rs b/xtask/codegen/src/generate_license.rs index 7f27d68e7f75..cac9cc31295f 100644 --- a/xtask/codegen/src/generate_license.rs +++ b/xtask/codegen/src/generate_license.rs @@ -35,7 +35,7 @@ pub(crate) fn generate_license(mode: Mode) -> Result<()> { let request = get(URL); let result = request.call()?; let license_list = result.into_json::()?; - let config_root = project_root().join("crates/biome_project/src/license"); + let config_root = project_root().join("crates/biome_package/src/license"); let tokens = create_data(license_list).expect("To write data into file");