diff --git a/crates/oxc_linter/src/lib.rs b/crates/oxc_linter/src/lib.rs index e2fe91dbf..7212b89fd 100644 --- a/crates/oxc_linter/src/lib.rs +++ b/crates/oxc_linter/src/lib.rs @@ -12,15 +12,15 @@ mod fixer; mod globals; mod javascript_globals; mod options; -pub mod partial_loader; -pub mod rule; +mod rule; mod rules; mod service; mod utils; -use std::{io::Write, rc::Rc, sync::Arc}; +pub mod partial_loader; +pub mod table; -use rustc_hash::{FxHashMap, FxHashSet}; +use std::{io::Write, rc::Rc, sync::Arc}; use oxc_diagnostics::Error; use oxc_semantic::AstNode; @@ -29,15 +29,15 @@ pub use crate::{ config::ESLintConfig, context::LintContext, options::{AllowWarnDeny, LintOptions}, - rule::RuleWithSeverity, + rule::{RuleCategory, RuleMeta, RuleWithSeverity}, service::{LintService, LintServiceOptions}, }; use crate::{ config::{ESLintEnv, ESLintGlobals, ESLintSettings}, fixer::Fix, fixer::{Fixer, Message}, - rule::RuleCategory, - rules::{RuleEnum, RULES}, + rules::RuleEnum, + table::RuleTable, }; #[cfg(target_pointer_width = "64")] @@ -132,51 +132,12 @@ impl Linter { /// # Panics pub fn print_rules(writer: &mut W) { - let default_rules = Linter::default() - .rules - .into_iter() - .map(|rule| rule.name()) - .collect::>(); - - let rules_by_category = RULES.iter().fold( - FxHashMap::default(), - |mut map: FxHashMap>, rule| { - map.entry(rule.category()).or_default().push(rule); - map - }, - ); - - let mut default_count = 0; - - for (category, rules) in rules_by_category { - writeln!(writer, "## {} ({}):", category, rules.len()).unwrap(); - - let rule_width = rules.iter().map(|r| r.name().len()).max().unwrap(); - let plugin_width = rules.iter().map(|r| r.plugin_name().len()).max().unwrap(); - let x = ""; - writeln!( - writer, - "| {:, + pub total: usize, + pub turned_on_by_default_count: usize, +} + +pub struct RuleTableSection { + pub rows: Vec, + pub category: String, + pub rule_column_width: usize, + pub plugin_column_width: usize, +} + +pub struct RuleTableRow { + pub name: &'static str, + pub plugin: String, + pub category: String, + pub documentation: Option<&'static str>, + pub turned_on_by_default: bool, +} + +impl Default for RuleTable { + fn default() -> Self { + Self::new() + } +} + +impl RuleTable { + pub fn new() -> Self { + let default_rules = Linter::default() + .rules + .into_iter() + .map(|rule| rule.name()) + .collect::>(); + + let mut rows = RULES + .iter() + .map(|rule| { + let name = rule.name(); + RuleTableRow { + name, + documentation: rule.documentation(), + plugin: rule.plugin_name().to_string(), + category: rule.category().to_string(), + turned_on_by_default: default_rules.contains(name), + } + }) + .collect::>(); + + let total = rows.len(); + + rows.sort_by_key(|row| (row.plugin.clone(), row.name)); + + let mut rows_by_category = rows.into_iter().fold( + HashMap::default(), + |mut map: HashMap>, row| { + map.entry(row.category.clone()).or_default().push(row); + map + }, + ); + + let sections = + ["Correctness", "Perf", "Restriction", "Suspicious", "Pedantic", "Style", "Nursery"] + .into_iter() + .filter_map(|category| { + let rows = rows_by_category.remove(category)?; + let rule_column_width = rows.iter().map(|r| r.name.len()).max()?; + let plugin_column_width = rows.iter().map(|r| r.plugin.len()).max()?; + Some(RuleTableSection { + rows, + category: category.to_string(), + rule_column_width, + plugin_column_width, + }) + }) + .collect::>(); + + RuleTable { total, sections, turned_on_by_default_count: default_rules.len() } + } +} + +impl RuleTableSection { + pub fn render_markdown_table(&self) -> String { + let mut s = String::new(); + let category = &self.category; + let rows = &self.rows; + let rule_width = self.rule_column_width; + let plugin_width = self.plugin_column_width; + writeln!(s, "## {} ({}):", category, rows.len()).unwrap(); + + let x = ""; + writeln!(s, "| {: /path/to/oxc/oxc-project.github.io/src/docs/guide/usage/linter/generated-rules.md` // pub fn generate_rules() { - use oxc_linter::Linter; - let mut v = vec![]; - Linter::print_rules(&mut v); - println!("{}", String::from_utf8(v).unwrap()); + let table = RuleTable::new(); + + let total = table.total; + let turned_on_by_default_count = table.turned_on_by_default_count; + + let body = table + .sections + .into_iter() + .map(|section| section.render_markdown_table()) + .collect::>() + .join("\n"); + + println!(" +# Rules + +The progress of all rule implementations is tracked [here](https://github.com/oxc-project/oxc/issues/481). + +- Total number of rules: {total} +- Rules turned on by default: {turned_on_by_default_count} + + + +{body} + + + +"); }