diff --git a/apps/oxlint/src/js_plugins/external_linter.rs b/apps/oxlint/src/js_plugins/external_linter.rs index 00ca9998851b6..3f26ee22beeb5 100644 --- a/apps/oxlint/src/js_plugins/external_linter.rs +++ b/apps/oxlint/src/js_plugins/external_linter.rs @@ -31,6 +31,13 @@ pub fn create_external_linter( ExternalLinter::new(rust_load_plugin, rust_setup_configs, rust_lint_file) } +/// Result returned by `loadPlugin` JS callback. +#[derive(Clone, Debug, Deserialize)] +pub enum LoadPluginReturnValue { + Success(LoadPluginResult), + Failure(String), +} + /// Wrap `loadPlugin` JS callback as a normal Rust function. /// /// The JS-side function is async. The returned Rust function blocks the current thread @@ -48,9 +55,11 @@ fn wrap_load_plugin(cb: JsLoadPluginCb) -> ExternalLinterLoadPluginCb { match res { // `loadPlugin` returns JSON string if plugin loaded successfully, or an error occurred - Ok(json) => match serde_json::from_str::(&json) { - // Plugin loaded successfully, or error occurred on JS side - Ok(result) => Ok(result), + Ok(json) => match serde_json::from_str(&json) { + // Plugin loaded successfully + Ok(LoadPluginReturnValue::Success(result)) => Ok(result), + // Error occurred on JS side + Ok(LoadPluginReturnValue::Failure(err)) => Err(err), // Invalid JSON - should be impossible, because we control serialization on JS side Err(err) => { Err(format!("Failed to deserialize JSON returned by `loadPlugin`: {err}")) diff --git a/crates/oxc_linter/src/config/config_builder.rs b/crates/oxc_linter/src/config/config_builder.rs index d25b3a59d777d..38644ed765284 100644 --- a/crates/oxc_linter/src/config/config_builder.rs +++ b/crates/oxc_linter/src/config/config_builder.rs @@ -14,7 +14,9 @@ use crate::{ AllowWarnDeny, ExternalPluginStore, LintConfig, LintFilter, LintFilterKind, Oxlintrc, RuleCategory, RuleEnum, config::{ - ESLintRule, OxlintOverrides, OxlintRules, overrides::OxlintOverride, plugins::LintPlugins, + ESLintRule, OxlintOverrides, OxlintRules, + overrides::OxlintOverride, + plugins::{LintPlugins, normalize_plugin_name}, }, external_linter::ExternalLinter, external_plugin_store::{ExternalOptionsId, ExternalRuleId, ExternalRuleLookupError}, @@ -525,8 +527,6 @@ impl ConfigStoreBuilder { resolver: &Resolver, external_plugin_store: &mut ExternalPluginStore, ) -> Result<(), ConfigBuilderError> { - use crate::LoadPluginResult; - // Print warning on 1st attempt to load a plugin #[expect(clippy::print_stderr)] if external_plugin_store.is_empty() { @@ -562,30 +562,19 @@ impl ConfigStoreBuilder { } })?; - match result { - LoadPluginResult::Success { name, offset, rule_names } => { - // Normalize plugin name (e.g., "eslint-plugin-foo" -> "foo", "@foo/eslint-plugin" -> "@foo") - use crate::config::plugins::normalize_plugin_name; - let normalized_name = normalize_plugin_name(&name).into_owned(); - - if LintPlugins::try_from(normalized_name.as_str()).is_err() { - external_plugin_store.register_plugin( - plugin_path, - normalized_name, - offset, - rule_names, - ); - Ok(()) - } else { - Err(ConfigBuilderError::ReservedExternalPluginName { - plugin_name: normalized_name, - }) - } - } - LoadPluginResult::Failure(e) => Err(ConfigBuilderError::PluginLoadFailed { - plugin_specifier: plugin_specifier.to_string(), - error: e, - }), + // Normalize plugin name (e.g., "eslint-plugin-foo" -> "foo", "@foo/eslint-plugin" -> "@foo") + let plugin_name = normalize_plugin_name(&result.name).into_owned(); + + if LintPlugins::try_from(plugin_name.as_str()).is_err() { + external_plugin_store.register_plugin( + plugin_path, + plugin_name, + result.offset, + result.rule_names, + ); + Ok(()) + } else { + Err(ConfigBuilderError::ReservedExternalPluginName { plugin_name }) } } } diff --git a/crates/oxc_linter/src/external_linter.rs b/crates/oxc_linter/src/external_linter.rs index 9cce719c51049..c7709fc14fda0 100644 --- a/crates/oxc_linter/src/external_linter.rs +++ b/crates/oxc_linter/src/external_linter.rs @@ -16,14 +16,11 @@ pub type ExternalLinterLintFileCb = Box< >; #[derive(Clone, Debug, Deserialize)] -pub enum LoadPluginResult { - #[serde(rename_all = "camelCase")] - Success { - name: String, - offset: usize, - rule_names: Vec, - }, - Failure(String), +#[serde(rename_all = "camelCase")] +pub struct LoadPluginResult { + pub name: String, + pub offset: usize, + pub rule_names: Vec, } #[derive(Clone, Debug, Deserialize)]