From f62951411d6d99ce4ffdd4b2f834392fb6c72de0 Mon Sep 17 00:00:00 2001
From: DonIsaac <22823424+DonIsaac@users.noreply.github.com>
Date: Sat, 10 Aug 2024 00:13:06 +0000
Subject: [PATCH] feat(website): auto-generate rule docs pages (#4640)
> AI-generated description because I'm lazy
### TL;DR
This PR introduces the ability to generate documentation for linter rules and adds new methods and metadata for rule fix capabilities.
To see what this looks like, please check out https://github.com/oxc-project/oxc-project.github.io/pull/165.
## Screenshots
Hyperlinks to rule doc pages in auto-generated rules table
Example of a docs page
### What changed?
- Added `RuleFixMeta` to indicate rule fix capabilities
- Introduced methods `is_none` and `is_pending` in `RuleFixMeta`
- Modified `render_markdown_table` in `RuleTableSection` to accept an optional link prefix
- Created new modules for rule documentation and HTML rendering
- Updated `print_rules` function to generate markdown for rules and detailed documentation pages
### How to test?
Run the `linter-rules` task with appropriate arguments to generate the markdown table and documentation pages.
Verify the generated files for correctness and that all metadata is correctly displayed.
### Why make this change?
To enhance the project documentation and provide clear rule fix capabilities, thereby improving the developer experience and easing the integration process.
---
---
crates/oxc_linter/src/lib.rs | 4 +-
crates/oxc_linter/src/rule.rs | 21 ++-
.../oxc_linter/src/rules/import/namespace.rs | 10 +-
.../src/rules/jsx_a11y/anchor_is_valid.rs | 22 +--
crates/oxc_linter/src/rules/jsx_a11y/lang.rs | 6 +-
.../rules/jsx_a11y/no_distracting_elements.rs | 8 +-
crates/oxc_linter/src/rules/jsx_a11y/scope.rs | 4 +-
.../src/rules/nextjs/no_duplicate_head.rs | 4 +-
.../src/rules/typescript/no_this_alias.rs | 10 +-
.../no_unnecessary_type_constraint.rs | 4 +-
crates/oxc_linter/src/table.rs | 19 ++-
tasks/website/src/linter/rules/doc_page.rs | 57 ++++++++
tasks/website/src/linter/rules/html.rs | 121 +++++++++++++++++
tasks/website/src/linter/rules/mod.rs | 128 ++++++++++++++++++
.../src/linter/{rules.rs => rules/table.rs} | 14 +-
tasks/website/src/main.rs | 2 +-
16 files changed, 377 insertions(+), 57 deletions(-)
create mode 100644 tasks/website/src/linter/rules/doc_page.rs
create mode 100644 tasks/website/src/linter/rules/html.rs
create mode 100644 tasks/website/src/linter/rules/mod.rs
rename tasks/website/src/linter/{rules.rs => rules/table.rs} (71%)
diff --git a/crates/oxc_linter/src/lib.rs b/crates/oxc_linter/src/lib.rs
index db0a174f886d0..38c221f27bb98 100644
--- a/crates/oxc_linter/src/lib.rs
+++ b/crates/oxc_linter/src/lib.rs
@@ -31,7 +31,7 @@ pub use crate::{
fixer::FixKind,
frameworks::FrameworkFlags,
options::{AllowWarnDeny, LintOptions},
- rule::{RuleCategory, RuleMeta, RuleWithSeverity},
+ rule::{RuleCategory, RuleFixMeta, RuleMeta, RuleWithSeverity},
service::{LintService, LintServiceOptions},
};
use crate::{
@@ -146,7 +146,7 @@ impl Linter {
pub fn print_rules(writer: &mut W) {
let table = RuleTable::new();
for section in table.sections {
- writeln!(writer, "{}", section.render_markdown_table()).unwrap();
+ writeln!(writer, "{}", section.render_markdown_table(None)).unwrap();
}
writeln!(writer, "Default: {}", table.turned_on_by_default_count).unwrap();
writeln!(writer, "Total: {}", table.total).unwrap();
diff --git a/crates/oxc_linter/src/rule.rs b/crates/oxc_linter/src/rule.rs
index 2d240170fa6f4..3fb081fb1315d 100644
--- a/crates/oxc_linter/src/rule.rs
+++ b/crates/oxc_linter/src/rule.rs
@@ -117,7 +117,7 @@ impl fmt::Display for RuleCategory {
// NOTE: this could be packed into a single byte if we wanted. I don't think
// this is needed, but we could do it if it would have a performance impact.
-/// Describes the auto-fixing capabilities of a [`Rule`].
+/// Describes the auto-fixing capabilities of a `Rule`.
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RuleFixMeta {
/// An auto-fix is not available.
@@ -132,7 +132,12 @@ pub enum RuleFixMeta {
}
impl RuleFixMeta {
- /// Does this [`Rule`] have some kind of auto-fix available?
+ #[inline]
+ pub fn is_none(self) -> bool {
+ matches!(self, Self::None)
+ }
+
+ /// Does this `Rule` have some kind of auto-fix available?
///
/// Also returns `true` for suggestions.
#[inline]
@@ -140,6 +145,11 @@ impl RuleFixMeta {
matches!(self, Self::Fixable(_) | Self::Conditional(_))
}
+ #[inline]
+ pub fn is_pending(self) -> bool {
+ matches!(self, Self::FixPending)
+ }
+
pub fn supports_fix(self, kind: FixKind) -> bool {
matches!(self, Self::Fixable(fix_kind) | Self::Conditional(fix_kind) if fix_kind.can_apply(kind))
}
@@ -163,9 +173,10 @@ impl RuleFixMeta {
let mut message =
if kind.is_dangerous() { format!("dangerous {noun}") } else { noun.into() };
- let article = match message.chars().next().unwrap() {
- 'a' | 'e' | 'i' | 'o' | 'u' => "An",
- _ => "A",
+ let article = match message.chars().next() {
+ Some('a' | 'e' | 'i' | 'o' | 'u') => "An",
+ Some(_) => "A",
+ None => unreachable!(),
};
if matches!(self, Self::Conditional(_)) {
diff --git a/crates/oxc_linter/src/rules/import/namespace.rs b/crates/oxc_linter/src/rules/import/namespace.rs
index 9209b11b20d44..af1264baec0db 100644
--- a/crates/oxc_linter/src/rules/import/namespace.rs
+++ b/crates/oxc_linter/src/rules/import/namespace.rs
@@ -40,10 +40,12 @@ pub struct Namespace {
declare_oxc_lint!(
/// ### What it does
- /// Enforces names exist at the time they are dereferenced, when imported as a full namespace (i.e. import * as foo from './foo'; foo.bar(); will report if bar is not exported by ./foo.).
- /// Will report at the import declaration if there are no exported names found.
- /// Also, will report for computed references (i.e. foo["bar"]()).
- /// Reports on assignment to a member of an imported namespace.
+ /// Enforces names exist at the time they are dereferenced, when imported as
+ /// a full namespace (i.e. `import * as foo from './foo'; foo.bar();` will
+ /// report if bar is not exported by `./foo.`). Will report at the import
+ /// declaration if there are no exported names found. Also, will report for
+ /// computed references (i.e. `foo["bar"]()`). Reports on assignment to a
+ /// member of an imported namespace.
Namespace,
correctness
);
diff --git a/crates/oxc_linter/src/rules/jsx_a11y/anchor_is_valid.rs b/crates/oxc_linter/src/rules/jsx_a11y/anchor_is_valid.rs
index 858e5d7c2ae63..5818637998967 100644
--- a/crates/oxc_linter/src/rules/jsx_a11y/anchor_is_valid.rs
+++ b/crates/oxc_linter/src/rules/jsx_a11y/anchor_is_valid.rs
@@ -56,7 +56,7 @@ declare_oxc_lint!(
///
/// Consider the following:
///
- /// ```javascript
+ /// ```jsx
/// Perform action
/// Perform action
/// Perform action
@@ -64,7 +64,7 @@ declare_oxc_lint!(
///
/// All these anchor implementations indicate that the element is only used to execute JavaScript code. All the above should be replaced with:
///
- /// ```javascript
+ /// ```jsx
///
/// ```
/// `
@@ -78,33 +78,19 @@ declare_oxc_lint!(
///
/// #### Valid
///
- /// ```javascript
+ /// ```jsx
/// navigate here
- /// ```
- ///
- /// ```javascript
/// navigate here
- /// ```
- ///
- /// ```javascript
/// navigate here
/// ```
///
/// #### Invalid
///
- /// ```javascript
+ /// ```jsx
/// navigate here
- /// ```
- /// ```javascript
/// navigate here
- /// ```
- /// ```javascript
/// navigate here
- /// ```
- /// ```javascript
/// navigate here
- /// ```
- /// ```javascript
/// navigate here
/// ```
///
diff --git a/crates/oxc_linter/src/rules/jsx_a11y/lang.rs b/crates/oxc_linter/src/rules/jsx_a11y/lang.rs
index a16e28a21dd41..4c894be11e8bd 100644
--- a/crates/oxc_linter/src/rules/jsx_a11y/lang.rs
+++ b/crates/oxc_linter/src/rules/jsx_a11y/lang.rs
@@ -26,7 +26,7 @@ pub struct Lang;
declare_oxc_lint!(
/// ### What it does
///
- /// The lang prop on the element must be a valid IETF's BCP 47 language tag.
+ /// The lang prop on the `` element must be a valid IETF's BCP 47 language tag.
///
/// ### Why is this bad?
///
@@ -39,13 +39,13 @@ declare_oxc_lint!(
/// ### Example
///
/// // good
- /// ```javascript
+ /// ```jsx
///
///
/// ```
///
/// // bad
- /// ```javascript
+ /// ```jsx
///
///
/// ````
diff --git a/crates/oxc_linter/src/rules/jsx_a11y/no_distracting_elements.rs b/crates/oxc_linter/src/rules/jsx_a11y/no_distracting_elements.rs
index faf44d9c20ffe..88bfa3de54efc 100644
--- a/crates/oxc_linter/src/rules/jsx_a11y/no_distracting_elements.rs
+++ b/crates/oxc_linter/src/rules/jsx_a11y/no_distracting_elements.rs
@@ -22,15 +22,17 @@ declare_oxc_lint!(
///
/// ### Why is this necessary?
///
- /// Elements that can be visually distracting can cause accessibility issues with visually impaired users.
- /// Such elements are most likely deprecated, and should be avoided. By default,