-
-
Notifications
You must be signed in to change notification settings - Fork 980
feat(lsp): add quick fix to migrate the biome config #9908
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: next
Are you sure you want to change the base?
Changes from all commits
2989020
5fbebed
4e9119e
9aa78e3
5fe4f14
559b66f
f9c57ca
2cac6da
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@biomejs/biome": minor | ||
| --- | ||
|
|
||
| Added a migrate quick fix for `biome.json` and `biome.jsonc` in the Biome LSP. Editors can now offer the same native configuration migrations as `biome migrate`, including config structure and rule migration updates, directly from published configuration diagnostics. |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,7 +19,7 @@ use biome_service::file_handlers::vue::VueFileHandler; | |
| use biome_service::workspace::{ | ||
| CheckFileSizeParams, FeaturesBuilder, FileFeaturesResult, FixFileMode, FixFileParams, | ||
| GetFileContentParams, IgnoreKind, PathIsIgnoredParams, ProjectKey, PullActionsParams, | ||
| SupportsFeatureParams, | ||
| PullConfigurationActionsParams, SupportsFeatureParams, | ||
| }; | ||
| use biome_service::{WorkspaceError, extension_error}; | ||
| use serde_json::Value; | ||
|
|
@@ -34,6 +34,8 @@ use tracing::{debug, info}; | |
| const FIX_ALL_CATEGORY: ActionCategory = ActionCategory::Source(SourceActionKind::FixAll); | ||
| const ORGANIZE_IMPORTS_CATEGORY: ActionCategory = | ||
| ActionCategory::Source(SourceActionKind::OrganizeImports); | ||
| const CONFIG_MIGRATE_QUICKFIX_CATEGORY: ActionCategory = | ||
| ActionCategory::QuickFix(Cow::Borrowed("migrateConfiguration")); | ||
|
|
||
| fn fix_all_kind() -> CodeActionKind { | ||
| match FIX_ALL_CATEGORY.to_str() { | ||
|
|
@@ -91,10 +93,6 @@ pub(crate) fn code_actions( | |
| .build(), | ||
| })?; | ||
|
|
||
| if !file_features.supports_lint() && !file_features.supports_assist() { | ||
| info!("Linter and assist are disabled."); | ||
| return Ok(Some(Vec::new())); | ||
| } | ||
| let mut categories = RuleCategoriesBuilder::default(); | ||
| if file_features.supports_lint() { | ||
| categories = categories.with_lint(); | ||
|
|
@@ -115,6 +113,7 @@ pub(crate) fn code_actions( | |
| let mut has_organize_imports = false; | ||
| let mut filters = Vec::new(); | ||
| if let Some(filter) = ¶ms.context.only { | ||
| filters.reserve(filter.len()); | ||
| for kind in filter { | ||
| let kind = kind.as_str(); | ||
| if FIX_ALL_CATEGORY.matches(kind) { | ||
|
|
@@ -130,6 +129,20 @@ pub(crate) fn code_actions( | |
| let position_encoding = session.position_encoding(); | ||
|
|
||
| let diagnostics = params.context.diagnostics; | ||
| let migrate_configuration_action = config_migrate_code_action( | ||
| session, | ||
| &url, | ||
| &path, | ||
| &doc.line_index, | ||
| position_encoding, | ||
| &filters, | ||
| doc.project_key, | ||
| )?; | ||
| if !file_features.supports_lint() && !file_features.supports_assist() { | ||
| info!("Linter and assist are disabled."); | ||
| return Ok(migrate_configuration_action.map(|action| vec![action])); | ||
| } | ||
|
|
||
| let content = session.workspace.get_file_content(GetFileContentParams { | ||
| project_key: doc.project_key, | ||
| path: path.clone(), | ||
|
|
@@ -325,6 +338,7 @@ pub(crate) fn code_actions( | |
| Some(CodeActionOrCommand::CodeAction(lsp_action)) | ||
| }) | ||
| .chain(fix_all) | ||
| .chain(migrate_configuration_action) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This quick fix still gets filtered out in mixed-action files. After chaining 💡 Minimal fix- action.kind.as_ref() == Some(&fix_all_kind()) || action.diagnostics.is_some()
+ action.kind.as_ref() == Some(&fix_all_kind())
+ || action.kind.as_ref() == Some(&config_migrate_kind())
+ || action.diagnostics.is_some()🤖 Prompt for AI Agents |
||
| .collect(); | ||
|
|
||
| // If any actions is marked as fixing a diagnostic, hide other actions | ||
|
|
@@ -556,16 +570,6 @@ fn fix_all( | |
| })?; | ||
| let should_format = file_features.supports_format(); | ||
|
|
||
| if session.workspace.is_path_ignored(PathIsIgnoredParams { | ||
| path: path.clone(), | ||
| is_dir: false, | ||
| project_key: doc.project_key, | ||
| features: analyzer_features, | ||
| ignore_kind: IgnoreKind::Ancestors, | ||
| })? { | ||
| return Ok(None); | ||
| } | ||
|
|
||
| let size_limit_result = session.workspace.check_file_size(CheckFileSizeParams { | ||
| project_key: doc.project_key, | ||
| path: path.clone(), | ||
|
|
@@ -701,3 +705,45 @@ fn fix_all( | |
| data: None, | ||
| }))) | ||
| } | ||
|
|
||
| fn config_migrate_code_action( | ||
| session: &Session, | ||
| url: &Uri, | ||
| path: &BiomePath, | ||
| line_index: &LineIndex, | ||
| position_encoding: biome_lsp_converters::PositionEncoding, | ||
| filters: &[&str], | ||
| project_key: biome_service::projects::ProjectKey, | ||
| ) -> Result<Option<CodeActionOrCommand>, Error> { | ||
| if !path.is_config() { | ||
| return Ok(None); | ||
| } | ||
|
|
||
| if !filters.is_empty() | ||
| && !filters | ||
| .iter() | ||
| .any(|filter| CONFIG_MIGRATE_QUICKFIX_CATEGORY.matches(filter)) | ||
| { | ||
| return Ok(None); | ||
| } | ||
|
|
||
| let Some(action) = session | ||
| .workspace | ||
| .pull_configuration_actions(PullConfigurationActionsParams { | ||
| project_key, | ||
| path: path.clone(), | ||
| })? | ||
| .actions | ||
| .into_iter() | ||
| .next() | ||
| else { | ||
| return Ok(None); | ||
| }; | ||
|
|
||
| Ok( | ||
| utils::code_fix_to_lsp(url, line_index, position_encoding, &[], action) | ||
| .ok() | ||
| .flatten() | ||
| .map(CodeActionOrCommand::CodeAction), | ||
| ) | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: biomejs/biome
Length of output: 2718
🏁 Script executed:
Repository: biomejs/biome
Length of output: 763
🏁 Script executed:
Repository: biomejs/biome
Length of output: 1141
🏁 Script executed:
Repository: biomejs/biome
Length of output: 370
🏁 Script executed:
rg -n 'is_config\(\)' crates/biome_service/src crates/biome_lsp/srcRepository: biomejs/biome
Length of output: 595
🏁 Script executed:
sed -n '1440,1450p' crates/biome_service/src/workspace/server.rsRepository: biomejs/biome
Length of output: 636
🏁 Script executed:
sed -n '255,265p' crates/biome_service/src/projects.rsRepository: biomejs/biome
Length of output: 565
🏁 Script executed:
sed -n '564,580p' crates/biome_service/src/file_handlers/json.rsRepository: biomejs/biome
Length of output: 690
Hidden config variants are classified but not validated.
The change promotes
.biome.jsonand.biome.jsonctoFileKinds::ConfigviaConfigName::file_names(), and tests confirm this. However,crates/biome_service/src/file_handlers/json.rs:566–567still checks onlyConfigName::biome_json()andConfigName::biome_jsonc()to decide whether to deserialise the config and emit diagnostics. Hidden variants will now be classified as config files but won't trigger config validation.Either add hidden variants to the validation check in
file_handlers/json.rs, or remove them fromConfigName::file_names()if they're not ready for full support.🤖 Prompt for AI Agents