refactor(linter): add declare_all_lint_rules proc macro (#121)

This commit is contained in:
Amit Dahan 2023-03-07 17:39:38 +02:00 committed by GitHub
parent 3562a49592
commit 2687d7868f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 158 additions and 123 deletions

40
Cargo.lock generated
View file

@ -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"

View file

@ -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,
}

View 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())),*
];
}
}
}

View file

@ -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()
}