diff --git a/apps/oxlint/src/lint.rs b/apps/oxlint/src/lint.rs index ae14276cd3496..8049aeb5756d4 100644 --- a/apps/oxlint/src/lint.rs +++ b/apps/oxlint/src/lint.rs @@ -238,13 +238,6 @@ impl CliRunner { let mut external_linter = self.external_linter; if external_plugin_store.is_empty() { external_linter = None; - } else { - #[expect(clippy::print_stderr)] - { - eprintln!( - "WARNING: JS plugins are experimental and not subject to semver.\nBreaking changes are possible while JS plugins support is under development." - ); - } } if let Some(basic_config_file) = oxlintrc_for_print { diff --git a/apps/oxlint/test/fixtures/custom_plugin_import_error/output.snap.md b/apps/oxlint/test/fixtures/custom_plugin_import_error/output.snap.md index 43edd338621dd..9297d670ca48e 100644 --- a/apps/oxlint/test/fixtures/custom_plugin_import_error/output.snap.md +++ b/apps/oxlint/test/fixtures/custom_plugin_import_error/output.snap.md @@ -12,4 +12,6 @@ Failed to parse configuration file. # stderr ``` +WARNING: JS plugins are experimental and not subject to semver. +Breaking changes are possible while JS plugins support is under development. ``` diff --git a/apps/oxlint/test/fixtures/custom_plugin_lint_createOnce_error/output.snap.md b/apps/oxlint/test/fixtures/custom_plugin_lint_createOnce_error/output.snap.md index 2f64101c30010..8ebc8356c12a3 100644 --- a/apps/oxlint/test/fixtures/custom_plugin_lint_createOnce_error/output.snap.md +++ b/apps/oxlint/test/fixtures/custom_plugin_lint_createOnce_error/output.snap.md @@ -12,4 +12,6 @@ Failed to parse configuration file. # stderr ``` +WARNING: JS plugins are experimental and not subject to semver. +Breaking changes are possible while JS plugins support is under development. ``` diff --git a/apps/oxlint/test/fixtures/custom_plugin_missing_rule/output.snap.md b/apps/oxlint/test/fixtures/custom_plugin_missing_rule/output.snap.md index 4ac74b1405b1c..fc598d9584c2b 100644 --- a/apps/oxlint/test/fixtures/custom_plugin_missing_rule/output.snap.md +++ b/apps/oxlint/test/fixtures/custom_plugin_missing_rule/output.snap.md @@ -10,4 +10,6 @@ Failed to parse configuration file. # stderr ``` +WARNING: JS plugins are experimental and not subject to semver. +Breaking changes are possible while JS plugins support is under development. ``` diff --git a/apps/oxlint/test/fixtures/custom_plugin_via_overrides_missing_rule/output.snap.md b/apps/oxlint/test/fixtures/custom_plugin_via_overrides_missing_rule/output.snap.md index a5e5f3b1cba1b..768e2a0bf30b3 100644 --- a/apps/oxlint/test/fixtures/custom_plugin_via_overrides_missing_rule/output.snap.md +++ b/apps/oxlint/test/fixtures/custom_plugin_via_overrides_missing_rule/output.snap.md @@ -10,4 +10,6 @@ Failed to build configuration. # stderr ``` +WARNING: JS plugins are experimental and not subject to semver. +Breaking changes are possible while JS plugins support is under development. ``` diff --git a/apps/oxlint/test/fixtures/missing_custom_plugin/output.snap.md b/apps/oxlint/test/fixtures/missing_custom_plugin/output.snap.md index e6fe8cb914044..e60e6f37e9c3f 100644 --- a/apps/oxlint/test/fixtures/missing_custom_plugin/output.snap.md +++ b/apps/oxlint/test/fixtures/missing_custom_plugin/output.snap.md @@ -11,4 +11,6 @@ Failed to parse configuration file. # stderr ``` +WARNING: JS plugins are experimental and not subject to semver. +Breaking changes are possible while JS plugins support is under development. ``` diff --git a/crates/oxc_linter/src/config/config_builder.rs b/crates/oxc_linter/src/config/config_builder.rs index 95ad4dcee70af..c762c3b24559b 100644 --- a/crates/oxc_linter/src/config/config_builder.rs +++ b/crates/oxc_linter/src/config/config_builder.rs @@ -499,6 +499,14 @@ impl ConfigStoreBuilder { ) -> Result<(), ConfigBuilderError> { use crate::PluginLoadResult; + // Print warning on 1st attempt to load a plugin + #[expect(clippy::print_stderr)] + if external_plugin_store.is_empty() { + eprintln!( + "WARNING: JS plugins are experimental and not subject to semver.\nBreaking changes are possible while JS plugins support is under development." + ); + } + let resolved = resolver.resolve(oxlintrc_dir_path, plugin_specifier).map_err(|e| { ConfigBuilderError::PluginLoadFailed { plugin_specifier: plugin_specifier.to_string(),