mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
refactor(linter): add declare_all_lint_rules proc macro (#121)
This commit is contained in:
parent
3562a49592
commit
2687d7868f
4 changed files with 158 additions and 123 deletions
40
Cargo.lock
generated
40
Cargo.lock
generated
|
|
@ -285,9 +285,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.7"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c"
|
||||
checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
|
|
@ -295,9 +295,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.3"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
|
||||
checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-epoch",
|
||||
|
|
@ -306,9 +306,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.14"
|
||||
version = "0.9.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695"
|
||||
checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
|
|
@ -319,9 +319,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.15"
|
||||
version = "0.8.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
|
||||
checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
|
@ -612,9 +612,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.6"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
|
||||
checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
|
||||
|
||||
[[package]]
|
||||
name = "jemalloc-sys"
|
||||
|
|
@ -696,9 +696,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
|||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.8.0"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
|
||||
checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
|
@ -1145,9 +1145,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
|||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.36.9"
|
||||
version = "0.36.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc"
|
||||
checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
|
|
@ -1177,9 +1177,9 @@ checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70"
|
|||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.13"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
|
||||
checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
|
||||
|
||||
[[package]]
|
||||
name = "ryu-js"
|
||||
|
|
@ -1251,9 +1251,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.9.18"
|
||||
version = "0.9.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05864bf272adeeef0f3e0ff93408e53fc94131201caab11dfd6045e2e8570d1b"
|
||||
checksum = "f82e6c8c047aa50a7328632d067bcae6ef38772a79e28daf32f735e0e4f3dd10"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa",
|
||||
|
|
@ -1459,9 +1459,9 @@ checksum = "238a3d5702128479aa8f25de86d12dde3ef71859109b6c1be6ce62dd4e76b160"
|
|||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.7"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "775c11906edafc97bc378816b94585fbd9a054eabaf86fdd0ced94af449efab7"
|
||||
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-linebreak"
|
||||
|
|
|
|||
|
|
@ -1,104 +1,10 @@
|
|||
mod constructor_super;
|
||||
mod eq_eq_eq;
|
||||
mod for_direction;
|
||||
mod no_array_constructor;
|
||||
mod no_debugger;
|
||||
mod no_empty;
|
||||
mod no_empty_pattern;
|
||||
mod deepscan {
|
||||
pub mod uninvoked_array_callback;
|
||||
}
|
||||
|
||||
pub use constructor_super::ConstructorSuper;
|
||||
pub use deepscan::uninvoked_array_callback::UninvokedArrayCallback;
|
||||
pub use eq_eq_eq::EqEqEq;
|
||||
pub use for_direction::ForDirection;
|
||||
pub use no_array_constructor::NoArrayConstructor;
|
||||
pub use no_debugger::NoDebugger;
|
||||
pub use no_empty::NoEmpty;
|
||||
pub use no_empty_pattern::NoEmptyPattern;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, rule::RuleMeta, AstNode};
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref RULES: Vec<RuleEnum> = vec![
|
||||
RuleEnum::EqEqEq(EqEqEq::default()),
|
||||
RuleEnum::ConstructorSuper(ConstructorSuper::default()),
|
||||
RuleEnum::NoDebugger(NoDebugger::default()),
|
||||
RuleEnum::NoEmpty(NoEmpty::default()),
|
||||
RuleEnum::NoArrayConstructor(NoArrayConstructor::default()),
|
||||
RuleEnum::NoEmptyPattern(NoEmptyPattern::default()),
|
||||
RuleEnum::UninvokedArrayCallback(UninvokedArrayCallback::default()),
|
||||
RuleEnum::ForDirection(ForDirection::default()),
|
||||
];
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
pub enum RuleEnum {
|
||||
EqEqEq(EqEqEq),
|
||||
ConstructorSuper(ConstructorSuper),
|
||||
NoDebugger(NoDebugger),
|
||||
NoEmpty(NoEmpty),
|
||||
NoArrayConstructor(NoArrayConstructor),
|
||||
NoEmptyPattern(NoEmptyPattern),
|
||||
UninvokedArrayCallback(UninvokedArrayCallback),
|
||||
ForDirection(ForDirection),
|
||||
}
|
||||
|
||||
impl RuleEnum {
|
||||
pub fn name(&self) -> &'static str {
|
||||
match self {
|
||||
Self::EqEqEq(_) => EqEqEq::NAME,
|
||||
Self::ConstructorSuper(_) => ConstructorSuper::NAME,
|
||||
Self::NoDebugger(_) => NoDebugger::NAME,
|
||||
Self::NoEmpty(_) => NoEmpty::NAME,
|
||||
Self::NoArrayConstructor(_) => NoArrayConstructor::NAME,
|
||||
Self::NoEmptyPattern(_) => NoEmptyPattern::NAME,
|
||||
Self::UninvokedArrayCallback(_) => UninvokedArrayCallback::NAME,
|
||||
Self::ForDirection(_) => ForDirection::NAME,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_json(&self, maybe_value: Option<serde_json::Value>) -> Self {
|
||||
match self {
|
||||
Self::EqEqEq(_) => {
|
||||
Self::EqEqEq(maybe_value.map(EqEqEq::from_configuration).unwrap_or_default())
|
||||
}
|
||||
Self::ConstructorSuper(_) => Self::ConstructorSuper(
|
||||
maybe_value.map(ConstructorSuper::from_configuration).unwrap_or_default(),
|
||||
),
|
||||
Self::NoDebugger(_) => Self::NoDebugger(
|
||||
maybe_value.map(NoDebugger::from_configuration).unwrap_or_default(),
|
||||
),
|
||||
Self::NoEmpty(_) => {
|
||||
Self::NoEmpty(maybe_value.map(NoEmpty::from_configuration).unwrap_or_default())
|
||||
}
|
||||
Self::NoArrayConstructor(_) => Self::NoArrayConstructor(
|
||||
maybe_value.map(NoArrayConstructor::from_configuration).unwrap_or_default(),
|
||||
),
|
||||
Self::NoEmptyPattern(_) => Self::NoEmptyPattern(
|
||||
maybe_value.map(NoEmptyPattern::from_configuration).unwrap_or_default(),
|
||||
),
|
||||
Self::UninvokedArrayCallback(_) => Self::UninvokedArrayCallback(
|
||||
maybe_value.map(UninvokedArrayCallback::from_configuration).unwrap_or_default(),
|
||||
),
|
||||
Self::ForDirection(_) => Self::ForDirection(
|
||||
maybe_value.map(ForDirection::from_configuration).unwrap_or_default(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
|
||||
match self {
|
||||
Self::EqEqEq(rule) => rule.run(node, ctx),
|
||||
Self::ConstructorSuper(rule) => rule.run(node, ctx),
|
||||
Self::NoDebugger(rule) => rule.run(node, ctx),
|
||||
Self::NoEmpty(rule) => rule.run(node, ctx),
|
||||
Self::NoArrayConstructor(rule) => rule.run(node, ctx),
|
||||
Self::NoEmptyPattern(rule) => rule.run(node, ctx),
|
||||
Self::UninvokedArrayCallback(rule) => rule.run(node, ctx),
|
||||
Self::ForDirection(rule) => rule.run(node, ctx),
|
||||
}
|
||||
}
|
||||
oxc_macros::declare_all_lint_rules! {
|
||||
constructor_super,
|
||||
eq_eq_eq,
|
||||
for_direction,
|
||||
no_debugger,
|
||||
no_array_constructor,
|
||||
no_empty,
|
||||
no_empty_pattern,
|
||||
deepscan::uninvoked_array_callback,
|
||||
}
|
||||
|
|
|
|||
121
crates/oxc_macros/src/declare_all_lint_rules.rs
Normal file
121
crates/oxc_macros/src/declare_all_lint_rules.rs
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
use convert_case::{Case, Casing};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::parse::{Parse, ParseStream};
|
||||
use syn::Result;
|
||||
|
||||
pub struct LintRuleMeta {
|
||||
name: syn::Ident,
|
||||
path: syn::Path,
|
||||
}
|
||||
|
||||
impl LintRuleMeta {
|
||||
pub fn mod_stmt(&self) -> TokenStream {
|
||||
let mut segments = self.path.segments.iter().rev().peekable();
|
||||
let first = &segments.next().unwrap().ident;
|
||||
let mut stmts = quote! {mod #first;};
|
||||
if segments.peek().is_some() {
|
||||
stmts = quote! {pub #stmts};
|
||||
}
|
||||
|
||||
while let Some(segment) = segments.next() {
|
||||
let ident = &segment.ident;
|
||||
|
||||
stmts = quote! {
|
||||
mod #ident { #stmts }
|
||||
};
|
||||
|
||||
if segments.peek().is_some() {
|
||||
stmts = quote! {
|
||||
pub #stmts
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
stmts
|
||||
}
|
||||
|
||||
pub fn use_stmt(&self) -> TokenStream {
|
||||
let mut path = self.path.clone();
|
||||
path.segments.push(self.name.clone().into());
|
||||
|
||||
quote! {
|
||||
pub use #path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for LintRuleMeta {
|
||||
fn parse(input: ParseStream<'_>) -> Result<Self> {
|
||||
let path = input.parse::<syn::Path>()?;
|
||||
let name = syn::parse_str(
|
||||
&path.segments.iter().last().unwrap().ident.to_string().to_case(Case::Pascal),
|
||||
)
|
||||
.unwrap();
|
||||
Ok(Self { path, name })
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AllLintRulesMeta {
|
||||
rules: Vec<LintRuleMeta>,
|
||||
}
|
||||
|
||||
impl Parse for AllLintRulesMeta {
|
||||
fn parse(input: ParseStream<'_>) -> Result<Self> {
|
||||
let rules = input
|
||||
.parse_terminated::<LintRuleMeta, syn::Token![,]>(LintRuleMeta::parse)?
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
Ok(Self { rules })
|
||||
}
|
||||
}
|
||||
|
||||
pub fn declare_all_lint_rules(metadata: AllLintRulesMeta) -> TokenStream {
|
||||
let AllLintRulesMeta { rules } = metadata;
|
||||
|
||||
let mod_stmts = rules.iter().map(|rule| rule.mod_stmt());
|
||||
let use_stmts = rules.iter().map(|rule| rule.use_stmt());
|
||||
let struct_names = rules.iter().map(|rule| &rule.name).collect::<Vec<_>>();
|
||||
|
||||
quote! {
|
||||
#(#mod_stmts)*
|
||||
#(#use_stmts)*
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, rule::RuleMeta, AstNode};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
pub enum RuleEnum {
|
||||
#(#struct_names(#struct_names)),*
|
||||
}
|
||||
|
||||
impl RuleEnum {
|
||||
pub const fn name(&self) -> &'static str {
|
||||
match self {
|
||||
#(Self::#struct_names(_) => #struct_names::NAME),*
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_json(&self, maybe_value: Option<serde_json::Value>) -> Self {
|
||||
match self {
|
||||
#(Self::#struct_names(_) => Self::#struct_names(
|
||||
maybe_value.map(#struct_names::from_configuration).unwrap_or_default(),
|
||||
)),*
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
|
||||
match self {
|
||||
#(Self::#struct_names(rule) => rule.run(node, ctx)),*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref RULES: Vec<RuleEnum> = vec![
|
||||
#(RuleEnum::#struct_names(#struct_names::default())),*
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
use syn::parse_macro_input;
|
||||
|
||||
mod declare_all_lint_rules;
|
||||
mod declare_oxc_lint;
|
||||
|
||||
/// Macro used to declare an oxc lint rule
|
||||
|
|
@ -50,3 +51,10 @@ pub fn declare_oxc_lint_test(input: proc_macro::TokenStream) -> proc_macro::Toke
|
|||
|
||||
declare_oxc_lint::declare_oxc_lint(metadata).into()
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn declare_all_lint_rules(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let metadata = parse_macro_input!(input as declare_all_lint_rules::AllLintRulesMeta);
|
||||
|
||||
declare_all_lint_rules::declare_all_lint_rules(metadata).into()
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue