Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/oxc_linter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ impl Linter {

let rules = rules
.iter()
.filter(|(rule, _)| rule.should_run(&ctx_host))
.filter(|(rule, _)| rule.should_run(&ctx_host) && !rule.is_tsgolint_rule())
.map(|(rule, severity)| (rule, Rc::clone(&ctx_host).spawn(rule, *severity)));

let semantic = ctx_host.semantic();
Expand Down
2 changes: 2 additions & 0 deletions crates/oxc_linter/src/rule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ pub trait RuleMeta {

const CATEGORY: RuleCategory;

const IS_TSGOLINT_RULE: bool = false;

/// What kind of auto-fixing can this rule do?
const FIX: RuleFixMeta = RuleFixMeta::None;

Expand Down
7 changes: 0 additions & 7 deletions crates/oxc_linter/src/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1112,10 +1112,3 @@ oxc_macros::declare_all_lint_rules! {
vitest::prefer_to_be_truthy,
vitest::require_local_test_context_for_concurrent_snapshots,
}

impl RuleEnum {
pub fn is_tsgolint_rule(&self) -> bool {
// TODO: Codegen this?
matches!(self, Self::TypescriptNoFloatingPromises(_) | Self::TypescriptNoMisusedPromises(_))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,10 @@ declare_oxc_lint!(
///
/// await Promise.all([1, 2, 3].map(async x => x + 1));
/// ```
NoFloatingPromises,
NoFloatingPromises(tsgolint),
typescript,
suspicious,
pending,
);

impl Rule for NoFloatingPromises {
fn should_run(&self, _ctx: &crate::context::ContextHost) -> bool {
false
}
}
impl Rule for NoFloatingPromises {}
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,10 @@ declare_oxc_lint!(
/// const getData = () => fetch('/');
/// console.log({ foo: 42, ...(await getData()) });
/// ```
NoMisusedPromises,
NoMisusedPromises(tsgolint),
typescript,
suspicious,
pending,
);

impl Rule for NoMisusedPromises {
fn should_run(&self, _ctx: &crate::context::ContextHost) -> bool {
false
}
}
impl Rule for NoMisusedPromises {}
6 changes: 6 additions & 0 deletions crates/oxc_macros/src/declare_all_lint_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,12 @@ pub fn declare_all_lint_rules(metadata: AllLintRulesMeta) -> TokenStream {
#(Self::#struct_names(rule) => rule.should_run(ctx)),*
}
}

pub fn is_tsgolint_rule(&self) -> bool {
match self {
#(Self::#struct_names(rule) => #struct_names::IS_TSGOLINT_RULE),*
}
}
}

impl std::hash::Hash for RuleEnum {
Expand Down
28 changes: 26 additions & 2 deletions crates/oxc_macros/src/declare_oxc_lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ use syn::{

pub struct LintRuleMeta {
name: Ident,
// Whether this rule should be exposed to tsgolint integration
is_tsgolint_rule: bool,
plugin: Ident,
category: Ident,
/// Describes what auto-fixing capabilities the rule has
Expand Down Expand Up @@ -49,7 +51,25 @@ impl Parse for LintRuleMeta {
}
}

let struct_name = input.parse()?;
let struct_name: Ident = input.parse()?;
// Optional marker `(tsgolint)` directly after the rule struct name
let mut is_tsgolint_rule = false;
if input.peek(syn::token::Paren) {
let content;
syn::parenthesized!(content in input);
let marker: Ident = content.parse()?;
if marker == "tsgolint" {
if !content.is_empty() {
return Err(Error::new_spanned(marker, "unexpected tokens after 'tsgolint'"));
}
is_tsgolint_rule = true;
} else {
return Err(Error::new_spanned(
marker,
"unsupported marker (only 'tsgolint' is allowed)",
));
}
}
input.parse::<Token!(,)>()?;
let plugin = input.parse()?;
input.parse::<Token!(,)>()?;
Expand Down Expand Up @@ -101,6 +121,7 @@ impl Parse for LintRuleMeta {

Ok(Self {
name: struct_name,
is_tsgolint_rule,
plugin,
category,
fix,
Expand All @@ -119,6 +140,7 @@ pub fn rule_name_converter() -> Converter {
pub fn declare_oxc_lint(metadata: LintRuleMeta) -> TokenStream {
let LintRuleMeta {
name,
is_tsgolint_rule,
plugin,
category,
fix,
Expand Down Expand Up @@ -193,6 +215,8 @@ pub fn declare_oxc_lint(metadata: LintRuleMeta) -> TokenStream {

const CATEGORY: RuleCategory = #category;

const IS_TSGOLINT_RULE: bool = #is_tsgolint_rule;

#fix

#docs
Expand Down Expand Up @@ -259,7 +283,7 @@ fn parse_fix(s: &str) -> proc_macro2::TokenStream {
// e.g. "safe_fix". safe is implied
"safe"
// e.g. fix_or_suggestion
| "and" | "or"
| "and" | "or"
=> false,
_ => true,
})
Expand Down
21 changes: 21 additions & 0 deletions crates/oxc_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,27 @@ mod declare_oxc_lint;
/// - `dangerous_fix_dangerous_suggestion` (provides dangerous fixes and suggestions in all cases)
///
/// `pending` and `none` are special cases that do not follow this pattern.
///
/// ## Integration markers
/// You can optionally add an integration marker immediately after the rule's struct
/// name in parentheses. Currently the only supported marker is `tsgolint`:
///
/// ```rust,ignore
/// declare_oxc_lint!(
/// /// Docs...
/// MyRule(tsgolint),
/// eslint,
/// style,
/// fix
/// );
/// ```
///
/// Adding `(tsgolint)` sets an internal `IS_TSGOLINT_RULE` flag to `true`, which
/// allows the `oxlint` CLI to surface this rule to the external `tsgolint`
/// executable. Rules without the marker keep the default `false` value and are
/// ignored by that integration. Only one marker is allowed and any other value
/// will result in a compile error.
///
/// # Example
///
/// ```
Expand Down
Loading