diff --git a/crates/oxc_linter/Cargo.toml b/crates/oxc_linter/Cargo.toml index 87f0ab74487da..6e15b2f6c67e9 100644 --- a/crates/oxc_linter/Cargo.toml +++ b/crates/oxc_linter/Cargo.toml @@ -13,6 +13,9 @@ repository.workspace = true rust-version.workspace = true description.workspace = true +[features] +ruledocs = ["oxc_macros/ruledocs"] # Enables the `ruledocs` feature for conditional compilation + [lints] workspace = true @@ -28,7 +31,7 @@ oxc_codegen = { workspace = true } oxc_diagnostics = { workspace = true } oxc_ecmascript = { workspace = true } oxc_index = { workspace = true, features = ["serde"] } -oxc_macros = { workspace = true } +oxc_macros = { workspace = true, features = ["ruledocs"] } oxc_parser = { workspace = true } oxc_regular_expression = { workspace = true } oxc_resolver = { workspace = true } diff --git a/crates/oxc_linter/src/rule.rs b/crates/oxc_linter/src/rule.rs index 264e7adadbc5f..caf16a10186cb 100644 --- a/crates/oxc_linter/src/rule.rs +++ b/crates/oxc_linter/src/rule.rs @@ -306,13 +306,14 @@ impl RuleWithSeverity { #[cfg(test)] mod test { - use markdown::{Options, to_html_with_options}; - use super::RuleCategory; - use crate::rules::RULES; #[test] + #[cfg(feature = "ruledocs")] fn ensure_documentation() { + use crate::rules::RULES; + use markdown::{Options, to_html_with_options}; + assert!(!RULES.is_empty()); let options = Options::gfm(); diff --git a/crates/oxc_linter/src/table.rs b/crates/oxc_linter/src/table.rs index 0c1c6128deb59..2f414f5f6e631 100644 --- a/crates/oxc_linter/src/table.rs +++ b/crates/oxc_linter/src/table.rs @@ -21,6 +21,7 @@ pub struct RuleTableRow { pub name: &'static str, pub plugin: String, pub category: RuleCategory, + #[cfg(feature = "ruledocs")] pub documentation: Option<&'static str>, pub turned_on_by_default: bool, pub autofix: RuleFixMeta, @@ -46,6 +47,7 @@ impl RuleTable { let name = rule.name(); RuleTableRow { name, + #[cfg(feature = "ruledocs")] documentation: rule.documentation(), plugin: rule.plugin_name().to_string(), category: rule.category(), diff --git a/crates/oxc_linter/tests/integration_test.rs b/crates/oxc_linter/tests/integration_test.rs index 22b938526c69d..56bc2e1f7b0c1 100644 --- a/crates/oxc_linter/tests/integration_test.rs +++ b/crates/oxc_linter/tests/integration_test.rs @@ -11,8 +11,8 @@ declare_oxc_lint_test!( correctness ); +#[expect(dead_code)] struct TestRule2 { - #[expect(dead_code)] dummy_field: u8, } @@ -26,9 +26,11 @@ declare_oxc_lint_test!( #[test] fn test_declare_oxc_lint() { // Simple, multiline documentation + #[cfg(feature = "ruledocs")] assert_eq!(TestRule::documentation().unwrap(), "Dummy description\n# which is multiline\n"); // Ensure structs with fields can be passed to the macro + #[cfg(feature = "ruledocs")] assert_eq!(TestRule2::documentation().unwrap(), "Dummy description2\n"); // Auto-generated kebab-case name diff --git a/crates/oxc_macros/Cargo.toml b/crates/oxc_macros/Cargo.toml index ac825fcbc5577..971e3dec18f0d 100644 --- a/crates/oxc_macros/Cargo.toml +++ b/crates/oxc_macros/Cargo.toml @@ -13,6 +13,9 @@ repository.workspace = true rust-version.workspace = true description.workspace = true +[features] +ruledocs = [] # Enables the `ruledocs` feature for conditional compilation + [lints] workspace = true diff --git a/crates/oxc_macros/src/declare_oxc_lint.rs b/crates/oxc_macros/src/declare_oxc_lint.rs index 6d1cd3d7ffa8f..92f25484242e7 100644 --- a/crates/oxc_macros/src/declare_oxc_lint.rs +++ b/crates/oxc_macros/src/declare_oxc_lint.rs @@ -13,21 +13,27 @@ pub struct LintRuleMeta { category: Ident, /// Describes what auto-fixing capabilities the rule has fix: Option, + #[cfg(feature = "ruledocs")] documentation: String, pub used_in_test: bool, } impl Parse for LintRuleMeta { fn parse(input: ParseStream<'_>) -> Result { + #[cfg(feature = "ruledocs")] let mut documentation = String::new(); + for attr in input.call(Attribute::parse_outer)? { match parse_attr(["doc"], &attr) { Some(lit) => { - let value = lit.value(); - let line = value.strip_prefix(' ').unwrap_or(&value); - - documentation.push_str(line); - documentation.push('\n'); + #[cfg(feature = "ruledocs")] + { + let value = lit.value(); + let line = value.strip_prefix(' ').unwrap_or(&value); + + documentation.push_str(line); + documentation.push('\n'); + } } _ => { return Err(Error::new_spanned(attr, "unexpected attribute")); @@ -54,7 +60,15 @@ impl Parse for LintRuleMeta { // Ignore the rest input.parse::()?; - Ok(Self { name: struct_name, plugin, category, fix, documentation, used_in_test: false }) + Ok(Self { + name: struct_name, + plugin, + category, + fix, + #[cfg(feature = "ruledocs")] + documentation, + used_in_test: false, + }) } } @@ -63,7 +77,15 @@ pub fn rule_name_converter() -> Converter { } pub fn declare_oxc_lint(metadata: LintRuleMeta) -> TokenStream { - let LintRuleMeta { name, plugin, category, fix, documentation, used_in_test } = metadata; + let LintRuleMeta { + name, + plugin, + category, + fix, + #[cfg(feature = "ruledocs")] + documentation, + used_in_test, + } = metadata; let canonical_name = rule_name_converter().convert(name.to_string()); let plugin = plugin.to_string(); // ToDo: validate plugin name @@ -91,6 +113,16 @@ pub fn declare_oxc_lint(metadata: LintRuleMeta) -> TokenStream { Some(quote! { use crate::{rule::{RuleCategory, RuleMeta, RuleFixMeta}, fixer::FixKind}; }) }; + #[cfg(not(feature = "ruledocs"))] + let docs: Option = None; + + #[cfg(feature = "ruledocs")] + let docs = Some(quote! { + fn documentation() -> Option<&'static str> { + Some(#documentation) + } + }); + let output = quote! { #import_statement @@ -103,9 +135,7 @@ pub fn declare_oxc_lint(metadata: LintRuleMeta) -> TokenStream { #fix - fn documentation() -> Option<&'static str> { - Some(#documentation) - } + #docs } }; diff --git a/tasks/website/Cargo.toml b/tasks/website/Cargo.toml index 92ce082b5210c..30d86672a00c2 100644 --- a/tasks/website/Cargo.toml +++ b/tasks/website/Cargo.toml @@ -19,7 +19,7 @@ doctest = false [dependencies] bpaf = { workspace = true, features = ["docgen"] } handlebars = { workspace = true } -oxc_linter = { workspace = true } +oxc_linter = { workspace = true, features = ["ruledocs"] } oxlint = { path = "../../apps/oxlint" } pico-args = { workspace = true } project-root = { workspace = true }