Skip to content

Commit

Permalink
feat(linter): allow lint rules with the same name
Browse files Browse the repository at this point in the history
  • Loading branch information
camc314 committed Nov 26, 2024
1 parent ef62b9d commit d143dba
Show file tree
Hide file tree
Showing 10 changed files with 57 additions and 28 deletions.
5 changes: 4 additions & 1 deletion crates/oxc_linter/src/config/flat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,10 @@ mod test {

#[allow(clippy::default_trait_access)]
fn no_explicit_any() -> RuleWithSeverity {
RuleWithSeverity::new(RuleEnum::NoExplicitAny(Default::default()), AllowWarnDeny::Warn)
RuleWithSeverity::new(
RuleEnum::TypescriptNoExplicitAny(Default::default()),
AllowWarnDeny::Warn,
)
}

/// an empty ruleset is a no-op
Expand Down
4 changes: 2 additions & 2 deletions crates/oxc_linter/src/config/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ mod test {
fn test_override_allow() {
let mut rules = RuleSet::default();
rules.insert(RuleWithSeverity {
rule: RuleEnum::NoConsole(Default::default()),
rule: RuleEnum::EslintNoConsole(Default::default()),
severity: AllowWarnDeny::Deny,
});
r#override(&mut rules, &json!({ "eslint/no-console": "off" }));
Expand Down Expand Up @@ -461,7 +461,7 @@ mod test {
for config in &configs {
let mut rules = RuleSet::default();
rules.insert(RuleWithSeverity {
rule: RuleEnum::NoUnusedVars(Default::default()),
rule: RuleEnum::EslintNoUnusedVars(Default::default()),
severity: AllowWarnDeny::Warn,
});
r#override(&mut rules, config);
Expand Down
4 changes: 2 additions & 2 deletions crates/oxc_linter/src/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ mod import {
pub mod default;
pub mod export;
pub mod first;
pub mod import_no_namespace;
pub mod max_dependencies;
pub mod named;
pub mod namespace;
Expand All @@ -24,6 +23,7 @@ mod import {
pub mod no_dynamic_require;
pub mod no_named_as_default;
pub mod no_named_as_default_member;
pub mod no_namespace;
pub mod no_self_import;
pub mod no_webpack_loader_syntax;
pub mod unambiguous;
Expand Down Expand Up @@ -639,7 +639,7 @@ oxc_macros::declare_all_lint_rules! {
import::default,
import::export,
import::first,
import::import_no_namespace,
import::no_namespace,
import::max_dependencies,
import::named,
import::namespace,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,22 @@ use oxc_syntax::module_record::ImportImportName;

use crate::{context::LintContext, rule::Rule};

fn import_no_namespace_diagnostic(span: Span) -> OxcDiagnostic {
fn no_namespace_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Usage of namespaced aka wildcard \"*\" imports prohibited")
.with_help("Use named or default imports")
.with_label(span)
}

#[derive(Debug, Default, Clone)]
pub struct ImportNoNamespace(Box<ImportNoNamespaceConfig>);
pub struct NoNamespace(Box<NoNamespaceConfig>);

#[derive(Debug, Default, Clone)]
pub struct ImportNoNamespaceConfig {
pub struct NoNamespaceConfig {
ignore: Vec<CompactStr>,
}

impl std::ops::Deref for ImportNoNamespace {
type Target = ImportNoNamespaceConfig;
impl std::ops::Deref for NoNamespace {
type Target = NoNamespaceConfig;

fn deref(&self) -> &Self::Target {
&self.0
Expand Down Expand Up @@ -77,16 +77,16 @@ declare_oxc_lint!(
/// import defaultExport, { isUser } from './user';
/// ```
///
ImportNoNamespace,
NoNamespace,
style,
pending // TODO: fixer
);

/// <https://github.com/import-js/eslint-plugin-import/blob/v2.29.1/docs/rules/no-namespace.md>
impl Rule for ImportNoNamespace {
impl Rule for NoNamespace {
fn from_configuration(value: serde_json::Value) -> Self {
let obj = value.get(0);
Self(Box::new(ImportNoNamespaceConfig {
Self(Box::new(NoNamespaceConfig {
ignore: obj
.and_then(|v| v.get("ignore"))
.and_then(serde_json::Value::as_array)
Expand All @@ -110,7 +110,7 @@ impl Rule for ImportNoNamespace {
let source = entry.module_request.name();

if self.ignore.is_empty() {
ctx.diagnostic(import_no_namespace_diagnostic(entry.local_name.span()));
ctx.diagnostic(no_namespace_diagnostic(entry.local_name.span()));
} else {
if !source.contains('.') {
return;
Expand All @@ -124,7 +124,7 @@ impl Rule for ImportNoNamespace {
return;
}

ctx.diagnostic(import_no_namespace_diagnostic(entry.local_name.span()));
ctx.diagnostic(no_namespace_diagnostic(entry.local_name.span()));
}
}
ImportImportName::Name(_) | ImportImportName::Default(_) => {}
Expand Down Expand Up @@ -159,7 +159,7 @@ fn test() {
(r"import * as foo from './foo';", None),
];

Tester::new(ImportNoNamespace::NAME, pass, fail)
Tester::new(NoNamespace::NAME, pass, fail)
.change_rule_path("index.js")
.with_import_plugin(true)
.test_and_snapshot();
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_linter/src/rules/jsx_a11y/autocomplete_valid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ impl Rule for AutocompleteValid {

#[test]
fn test() {
use crate::{rules::AutocompleteValid, tester::Tester};
use crate::tester::Tester;

fn settings() -> serde_json::Value {
serde_json::json!({
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_linter/src/rules/jsx_a11y/no_redundant_roles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ impl Rule for NoRedundantRoles {

#[test]
fn test() {
use crate::{rules::NoRedundantRoles, tester::Tester};
use crate::tester::Tester;

fn settings() -> serde_json::Value {
serde_json::json!({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ impl Rule for RoleHasRequiredAriaProps {

#[test]
fn test() {
use crate::{rules::RoleHasRequiredAriaProps, tester::Tester};
use crate::tester::Tester;

fn settings() -> serde_json::Value {
serde_json::json!({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ static AWS_TOKEN_PREFIXES: Map<&'static str, &'static str> = phf_map! {

#[test]
fn test() {
use crate::{rules::ApiKeys, tester::Tester, RuleMeta};
use crate::{rules::SecurityApiKeys, tester::Tester, RuleMeta};

let pass = vec![
"let x = ''",
Expand All @@ -94,7 +94,7 @@ fn test() {
"let key = 'AKIAAABCD1099FAM9KEY'",
];

Tester::new(ApiKeys::NAME, pass, fail)
Tester::new(SecurityApiKeys::NAME, pass, fail)
.with_snapshot_suffix("aws_access_token")
.test_and_snapshot();
}
5 changes: 4 additions & 1 deletion crates/oxc_linter/src/tester.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,10 @@ impl Tester {
}

settings.bind(|| {
insta::assert_snapshot!(name.as_ref(), self.snapshot);
insta::assert_snapshot!(
format!("{}_{}", self.find_rule().plugin_name(), name.as_ref()),
self.snapshot
);
});
}

Expand Down
35 changes: 29 additions & 6 deletions crates/oxc_macros/src/declare_all_lint_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,39 @@ use syn::{
};

pub struct LintRuleMeta {
name: syn::Ident,
rule_name: syn::Ident,
enum_name: syn::Ident,
path: syn::Path,
}

impl Parse for LintRuleMeta {
fn parse(input: ParseStream<'_>) -> Result<Self> {
let path = input.parse::<syn::Path>()?;

let segments = &path.segments;
let last_two_segments = segments.iter().rev().take(2).collect::<Vec<_>>(); // Collect the last two segments in reverse order
let combined = last_two_segments
.iter()
.rev()
.map(|seg| seg.ident.to_string().to_case(Case::Pascal))
.join("");

let combined = combined.to_case(Case::Pascal);

let name = syn::parse_str(
&path.segments.iter().last().unwrap().ident.to_string().to_case(Case::Pascal),
//&path.segments.iter().last().unwrap().ident.to_string().to_case(Case::Pascal),
&combined,
)
.unwrap();
Ok(Self { name, path })
Ok(Self {
enum_name: name,
rule_name: syn::parse_str(
&path.segments.iter().last().unwrap().ident.to_string().to_case(Case::Pascal),
//&combined,
)
.unwrap(),
path,
})
}
}

Expand All @@ -39,14 +60,16 @@ impl Parse for AllLintRulesMeta {
pub fn declare_all_lint_rules(metadata: AllLintRulesMeta) -> TokenStream {
let AllLintRulesMeta { rules } = metadata;

let mut use_stmts = Vec::with_capacity(rules.len());
let mut use_stmts: Vec<&syn::Path> = Vec::with_capacity(rules.len());
let mut struct_names = Vec::with_capacity(rules.len());
let mut struct_rule_names = Vec::with_capacity(rules.len());
let mut plugin_names = Vec::with_capacity(rules.len());
let mut ids = Vec::with_capacity(rules.len());

for (i, rule) in rules.iter().enumerate() {
use_stmts.push(&rule.path);
struct_names.push(&rule.name);
struct_names.push(&rule.enum_name);
struct_rule_names.push(&rule.rule_name);
plugin_names.push(
rule.path
.segments
Expand All @@ -59,7 +82,7 @@ pub fn declare_all_lint_rules(metadata: AllLintRulesMeta) -> TokenStream {
}

let expanded = quote! {
#(pub use self::#use_stmts::#struct_names;)*
#(pub use self::#use_stmts::#struct_rule_names as #struct_names;)*

use crate::{
context::{ContextHost, LintContext},
Expand Down

0 comments on commit d143dba

Please sign in to comment.