Skip to content
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

feat(core): implement workspace plugin loading #5160

Merged
merged 2 commits into from
Feb 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Compile
timeout-minutes: 15
run: cargo codspeed build --features codspeed -p xtask_bench

- name: Run the benchmarks
Expand Down
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 8 additions & 2 deletions crates/biome_analyze/src/analyzer_plugin.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
use crate::RuleDiagnostic;
use biome_parser::AnyParse;
use camino::Utf8PathBuf;
use std::fmt::Debug;
use std::{fmt::Debug, sync::Arc};

/// Slice of analyzer plugins that can be cheaply cloned.
pub type AnalyzerPluginSlice<'a> = &'a [Arc<Box<dyn AnalyzerPlugin>>];

/// Vector of analyzer plugins that can be cheaply cloned.
pub type AnalyzerPluginVec = Vec<Arc<Box<dyn AnalyzerPlugin>>>;

/// Definition of an analyzer plugin.
pub trait AnalyzerPlugin: Debug {
pub trait AnalyzerPlugin: Debug + Send + Sync {
fn evaluate(&self, root: AnyParse, path: Utf8PathBuf) -> Vec<RuleDiagnostic>;

fn supports_css(&self) -> bool;
Expand Down
7 changes: 4 additions & 3 deletions crates/biome_analyze/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use biome_parser::AnyParse;
use std::collections::{BTreeMap, BinaryHeap};
use std::fmt::{Debug, Display, Formatter};
use std::ops;
use std::sync::Arc;

mod analyzer_plugin;
mod categories;
Expand All @@ -25,7 +26,7 @@ mod visitor;
// Re-exported for use in the `declare_group` macro
pub use biome_diagnostics::category_concat;

pub use crate::analyzer_plugin::AnalyzerPlugin;
pub use crate::analyzer_plugin::{AnalyzerPlugin, AnalyzerPluginSlice, AnalyzerPluginVec};
pub use crate::categories::{
ActionCategory, OtherActionCategory, RefactorKind, RuleCategories, RuleCategoriesBuilder,
RuleCategory, SourceActionKind, SUPPRESSION_INLINE_ACTION_CATEGORY,
Expand Down Expand Up @@ -72,7 +73,7 @@ pub struct Analyzer<'analyzer, L: Language, Matcher, Break, Diag> {
/// List of visitors being run by this instance of the analyzer for each phase
phases: BTreeMap<Phases, Vec<Box<dyn Visitor<Language = L> + 'analyzer>>>,
/// Plugins to be run after the phases for built-in rules.
plugins: Vec<Box<dyn AnalyzerPlugin>>,
plugins: AnalyzerPluginVec,
/// Holds the metadata for all the rules statically known to the analyzer
metadata: &'analyzer MetadataRegistry,
/// Executor for the query matches emitted by the visitors
Expand Down Expand Up @@ -128,7 +129,7 @@ where
}

/// Registers an [AnalyzerPlugin] to be executed after the regular phases.
pub fn add_plugin(&mut self, plugin: Box<dyn AnalyzerPlugin>) {
pub fn add_plugin(&mut self, plugin: Arc<Box<dyn AnalyzerPlugin>>) {
self.plugins.push(plugin);
}

Expand Down
5 changes: 4 additions & 1 deletion crates/biome_cli/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -801,13 +801,16 @@ pub(crate) trait CommandRunner: Sized {
open_uninitialized: true,
})?;

workspace.update_settings(UpdateSettingsParams {
let result = 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,
})?;
for diagnostic in &result.diagnostics {
console.log(markup! {{PrintDiagnostic::simple(diagnostic)}});
}

let execution = self.get_execution(cli_options, console, workspace, project_key)?;

Expand Down
11 changes: 9 additions & 2 deletions crates/biome_configuration/src/plugins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ use std::str::FromStr;
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct Plugins(pub Vec<PluginConfiguration>);

impl Plugins {
pub fn iter(&self) -> impl Iterator<Item = &PluginConfiguration> {
self.0.iter()
}
}

impl FromStr for Plugins {
type Err = String;

Expand All @@ -36,8 +42,9 @@ impl Deserializable for PluginConfiguration {
Deserializable::deserialize(ctx, value, rule_name).map(Self::Path)
} else {
// TODO: Fix this to allow plugins to receive options.
// Difficulty is that we need a `Deserializable` implementation
// for `serde_json::Value`, since plugin options are untyped.
// We probably need to pass them as `AnyJsonValue` or
// `biome_json_value::JsonValue`, since plugin options are
// untyped.
// Also, we don't have a way to configure Grit plugins yet.
/*Deserializable::deserialize(value, rule_name, diagnostics)
.map(|plugin| Self::PathWithOptions(plugin))*/
Expand Down
18 changes: 9 additions & 9 deletions crates/biome_css_analyze/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ mod utils;
pub use crate::registry::visit_registry;
use crate::suppression_action::CssSuppressionAction;
use biome_analyze::{
to_analyzer_suppressions, AnalysisFilter, AnalyzerOptions, AnalyzerPlugin, AnalyzerSignal,
to_analyzer_suppressions, AnalysisFilter, AnalyzerOptions, AnalyzerPluginSlice, AnalyzerSignal,
AnalyzerSuppression, ControlFlow, LanguageRoot, MatchQueryParams, MetadataRegistry, RuleAction,
RuleRegistry,
};
Expand All @@ -36,7 +36,7 @@ pub fn analyze<'a, F, B>(
root: &LanguageRoot<CssLanguage>,
filter: AnalysisFilter,
options: &'a AnalyzerOptions,
plugins: Vec<Box<dyn AnalyzerPlugin>>,
plugins: AnalyzerPluginSlice<'a>,
emit_signal: F,
) -> (Option<B>, Vec<Error>)
where
Expand All @@ -57,7 +57,7 @@ pub fn analyze_with_inspect_matcher<'a, V, F, B>(
filter: AnalysisFilter,
inspect_matcher: V,
options: &'a AnalyzerOptions,
plugins: Vec<Box<dyn AnalyzerPlugin>>,
plugins: AnalyzerPluginSlice<'a>,
mut emit_signal: F,
) -> (Option<B>, Vec<Error>)
where
Expand Down Expand Up @@ -111,7 +111,7 @@ where

for plugin in plugins {
if plugin.supports_css() {
analyzer.add_plugin(plugin);
analyzer.add_plugin(plugin.clone());
}
}

Expand Down Expand Up @@ -189,7 +189,7 @@ mod tests {
..AnalysisFilter::default()
},
&options,
Vec::new(),
&[],
|signal| {
if let Some(diag) = signal.diagnostic() {
error_ranges.push(diag.location().span.unwrap());
Expand Down Expand Up @@ -234,7 +234,7 @@ mod tests {
};

let options = AnalyzerOptions::default();
analyze(&parsed.tree(), filter, &options, Vec::new(), |signal| {
analyze(&parsed.tree(), filter, &options, &[], |signal| {
if let Some(diag) = signal.diagnostic() {
let error = diag
.with_file_path("dummyFile")
Expand Down Expand Up @@ -274,7 +274,7 @@ a {
};

let options = AnalyzerOptions::default();
analyze(&parsed.tree(), filter, &options, Vec::new(), |signal| {
analyze(&parsed.tree(), filter, &options, &[], |signal| {
if let Some(diag) = signal.diagnostic() {
let error = diag
.with_file_path("dummyFile")
Expand Down Expand Up @@ -310,7 +310,7 @@ a {
};

let options = AnalyzerOptions::default();
analyze(&parsed.tree(), filter, &options, Vec::new(), |signal| {
analyze(&parsed.tree(), filter, &options, &[], |signal| {
if let Some(diag) = signal.diagnostic() {
let error = diag
.with_file_path("dummyFile")
Expand Down Expand Up @@ -343,7 +343,7 @@ a {
};

let options = AnalyzerOptions::default();
analyze(&parsed.tree(), filter, &options, Vec::new(), |signal| {
analyze(&parsed.tree(), filter, &options, &[], |signal| {
if let Some(diag) = signal.diagnostic() {
let code = diag.category().unwrap();
if code != category!("suppressions/unused") {
Expand Down
13 changes: 7 additions & 6 deletions crates/biome_css_analyze/tests/spec_tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use biome_analyze::{
AnalysisFilter, AnalyzerAction, AnalyzerPlugin, ControlFlow, Never, RuleFilter,
AnalysisFilter, AnalyzerAction, AnalyzerPluginSlice, ControlFlow, Never, RuleFilter,
};
use biome_css_parser::{parse_css, CssParserOptions};
use biome_css_syntax::{CssFileSource, CssLanguage};
Expand All @@ -14,6 +14,7 @@ use biome_test_utils::{
};
use camino::Utf8Path;
use std::ops::Deref;
use std::sync::Arc;
use std::{fs::read_to_string, slice};

tests_macros::gen_tests! {"tests/specs/**/*.{css,json,jsonc}", crate::run_test, "module"}
Expand Down Expand Up @@ -72,7 +73,7 @@ fn run_test(input: &'static str, _: &str, _: &str, _: &str) {
input_file,
CheckActionType::Lint,
parser_options,
Vec::new(),
&[],
);
}

Expand All @@ -90,7 +91,7 @@ fn run_test(input: &'static str, _: &str, _: &str, _: &str) {
input_file,
CheckActionType::Lint,
parser_options,
Vec::new(),
&[],
)
};

Expand All @@ -116,7 +117,7 @@ pub(crate) fn analyze_and_snap(
input_file: &Utf8Path,
check_action_type: CheckActionType,
parser_options: CssParserOptions,
plugins: Vec<Box<dyn AnalyzerPlugin>>,
plugins: AnalyzerPluginSlice,
) -> usize {
let parsed = parse_css(input_code, parser_options);
let root = parsed.tree();
Expand Down Expand Up @@ -241,7 +242,7 @@ pub(crate) fn run_suppression_test(input: &'static str, _: &str, _: &str, _: &st
input_file,
CheckActionType::Suppression,
CssParserOptions::default(),
Vec::new(),
&[],
);

insta::with_settings!({
Expand Down Expand Up @@ -288,7 +289,7 @@ fn run_plugin_test(input: &'static str, _: &str, _: &str, _: &str) {
&input_path,
CheckActionType::Lint,
CssParserOptions::default(),
vec![Box::new(plugin)],
&[Arc::new(Box::new(plugin))],
);

insta::with_settings!({
Expand Down
Loading
Loading