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
33 changes: 21 additions & 12 deletions crates/oxc_linter/src/config/config_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,10 @@ impl ConfigStoreBuilder {

RULES
.iter()
.filter(|rule| builtin_plugins.contains(LintPlugins::from(rule.plugin_name())))
.filter(|rule| {
LintPlugins::try_from(rule.plugin_name())
.is_ok_and(|plugin_flag| builtin_plugins.contains(plugin_flag))
})
.cloned()
.collect()
}
Expand Down Expand Up @@ -396,7 +399,10 @@ impl ConfigStoreBuilder {
let mut rules: Vec<_> = self
.rules
.into_iter()
.filter(|(r, _)| plugins.contains(r.plugin_name().into()))
.filter(|(r, _)| {
LintPlugins::try_from(r.plugin_name())
.is_ok_and(|plugin_name| plugins.contains(plugin_name))
})
.collect();
rules.sort_unstable_by_key(|(r, _)| r.id());

Expand Down Expand Up @@ -457,7 +463,8 @@ impl ConfigStoreBuilder {
// NOTE: this logic means there's no way to disable ESLint
// correctness rules. I think that's fine for now.
rule.category() == RuleCategory::Correctness
&& plugins.contains(LintPlugins::from(rule.plugin_name()))
&& LintPlugins::try_from(rule.plugin_name())
.is_ok_and(|plugin_flag| plugins.contains(plugin_flag))
})
.map(|rule| (rule.clone(), AllowWarnDeny::Warn))
.collect()
Expand Down Expand Up @@ -535,7 +542,7 @@ impl ConfigStoreBuilder {

match result {
PluginLoadResult::Success { name, offset, rule_names } => {
if name != "eslint" && LintPlugins::from(name.as_str()) == LintPlugins::empty() {
if LintPlugins::try_from(name.as_str()).is_err() {
external_plugin_store.register_plugin(plugin_path, name, offset, rule_names);
Ok(())
} else {
Expand Down Expand Up @@ -650,11 +657,12 @@ mod test {
for (rule, severity) in &builder.rules {
assert_eq!(rule.category(), RuleCategory::Correctness);
assert_eq!(*severity, AllowWarnDeny::Warn);
let plugin = rule.plugin_name();
let plugin_name = rule.plugin_name();
let plugin = LintPlugins::try_from(plugin_name);
let name = rule.name();
assert!(
builder.plugins().contains(plugin.into()),
"{plugin}/{name} is in the default rule set but its plugin is not enabled"
plugin.is_ok_and(|plugin| builder.plugins().contains(plugin)),
"{plugin_name}/{name} is in the default rule set but its plugin is not enabled"
);
}
}
Expand Down Expand Up @@ -683,11 +691,12 @@ mod test {
assert_eq!(rule.category(), RuleCategory::Correctness);
assert_eq!(*severity, AllowWarnDeny::Deny);

let plugin = rule.plugin_name();
let plugin_name = rule.plugin_name();
let plugin = LintPlugins::try_from(plugin_name);
let name = rule.name();
assert!(
builder.plugins().contains(plugin.into()),
"{plugin}/{name} is in the default rule set but its plugin is not enabled"
plugin.is_ok_and(|plugin| builder.plugins().contains(plugin)),
"{plugin_name}/{name} is in the default rule set but its plugin is not enabled"
);
}
}
Expand Down Expand Up @@ -792,8 +801,8 @@ mod test {
let name = rule.name();
let plugin = rule.plugin_name();
assert_ne!(
LintPlugins::from(plugin),
LintPlugins::TYPESCRIPT,
LintPlugins::try_from(plugin),
Ok(LintPlugins::TYPESCRIPT),
"{plugin}/{name} is in the rules list after typescript plugin has been disabled"
);
}
Expand Down
13 changes: 10 additions & 3 deletions crates/oxc_linter/src/config/config_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,13 +167,19 @@ impl Config {
let mut rules = self
.base_rules
.iter()
.filter(|(rule, _)| plugins.contains(LintPlugins::from(rule.plugin_name())))
.filter(|(rule, _)| {
LintPlugins::try_from(rule.plugin_name())
.is_ok_and(|plugin| plugins.contains(plugin))
})
.cloned()
.collect::<FxHashMap<_, _>>();

let all_rules = RULES
.iter()
.filter(|rule| plugins.contains(LintPlugins::from(rule.plugin_name())))
.filter(|rule| {
LintPlugins::try_from(rule.plugin_name())
.is_ok_and(|plugin| plugins.contains(plugin))
})
.cloned()
.collect::<Vec<_>>();

Expand All @@ -194,7 +200,8 @@ impl Config {

if !unconfigured_plugins.is_empty() {
for (rule, severity) in all_rules.iter().filter_map(|rule| {
let rule_plugin = LintPlugins::from(rule.plugin_name());
let rule_plugin = LintPlugins::try_from(rule.plugin_name())
.unwrap_or(LintPlugins::empty());
// Only apply categories to rules from unconfigured plugins
if unconfigured_plugins.contains(rule_plugin) {
self.categories
Expand Down
57 changes: 28 additions & 29 deletions crates/oxc_linter/src/config/plugins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,31 +75,34 @@ impl LintPlugins {
}
}

impl From<&str> for LintPlugins {
fn from(value: &str) -> Self {
impl TryFrom<&str> for LintPlugins {
type Error = ();

fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
"react" | "react-hooks" | "react_hooks" => LintPlugins::REACT,
"unicorn" => LintPlugins::UNICORN,
"react" | "react-hooks" | "react_hooks" => Ok(LintPlugins::REACT),
"unicorn" => Ok(LintPlugins::UNICORN),
"typescript" | "typescript-eslint" | "typescript_eslint" | "@typescript-eslint" => {
LintPlugins::TYPESCRIPT
Ok(LintPlugins::TYPESCRIPT)
}
// deepscan for backwards compatibility. Those rules have been moved into oxc
"oxc" | "deepscan" => LintPlugins::OXC,
"oxc" | "deepscan" => Ok(LintPlugins::OXC),
// import-x has the same rules but better performance
"import" | "import-x" => LintPlugins::IMPORT,
"jsdoc" => LintPlugins::JSDOC,
"jest" => LintPlugins::JEST,
"vitest" => LintPlugins::VITEST,
"jsx-a11y" | "jsx_a11y" => LintPlugins::JSX_A11Y,
"nextjs" => LintPlugins::NEXTJS,
"react-perf" | "react_perf" => LintPlugins::REACT_PERF,
"promise" => LintPlugins::PROMISE,
"node" => LintPlugins::NODE,
"regex" => LintPlugins::REGEX,
"vue" => LintPlugins::VUE,
"import" | "import-x" => Ok(LintPlugins::IMPORT),
"jsdoc" => Ok(LintPlugins::JSDOC),
"jest" => Ok(LintPlugins::JEST),
"vitest" => Ok(LintPlugins::VITEST),
"jsx-a11y" | "jsx_a11y" => Ok(LintPlugins::JSX_A11Y),
"nextjs" => Ok(LintPlugins::NEXTJS),
"react-perf" | "react_perf" => Ok(LintPlugins::REACT_PERF),
"promise" => Ok(LintPlugins::PROMISE),
"node" => Ok(LintPlugins::NODE),
"regex" => Ok(LintPlugins::REGEX),
"vue" => Ok(LintPlugins::VUE),
// "eslint" is not really a plugin, so it's 'empty'. This has the added benefit of
// making it the default value.
_ => LintPlugins::empty(),
"eslint" => Ok(LintPlugins::ESLINT),
_ => Err(()),
}
}
}
Expand Down Expand Up @@ -134,15 +137,11 @@ impl<'de> Deserialize<'de> for LintPlugins {
let mut lint_plugins = LintPlugins::empty();

for plugin in &plugin_names {
if plugin == "eslint" {
continue;
}

let plugin_flag = LintPlugins::from(plugin.as_str());
if plugin_flag == LintPlugins::empty() {
if let Ok(plugin_flag) = LintPlugins::try_from(plugin.as_str()) {
lint_plugins |= plugin_flag;
} else {
return Err(serde::de::Error::custom(format!("Unknown plugin: '{plugin}'.")));
}
lint_plugins |= plugin_flag;
}

Ok(lint_plugins)
Expand Down Expand Up @@ -243,10 +242,10 @@ mod tests {

#[test]
fn test_plugin_from_str() {
assert_eq!(LintPlugins::from("react"), LintPlugins::REACT);
assert_eq!(LintPlugins::from("typescript-eslint"), LintPlugins::TYPESCRIPT);
assert_eq!(LintPlugins::from("deepscan"), LintPlugins::OXC);
assert_eq!(LintPlugins::from("unknown"), LintPlugins::empty());
assert_eq!(LintPlugins::try_from("react"), Ok(LintPlugins::REACT));
assert_eq!(LintPlugins::try_from("typescript-eslint"), Ok(LintPlugins::TYPESCRIPT));
assert_eq!(LintPlugins::try_from("deepscan"), Ok(LintPlugins::OXC));
assert_eq!(LintPlugins::try_from("unknown"), Err(()));
}

#[test]
Expand Down
3 changes: 1 addition & 2 deletions crates/oxc_linter/src/config/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,7 @@ impl OxlintRules {
let config = rule_config.config.clone().unwrap_or_default();
let severity = rule_config.severity;

// TODO(camc314): remove the `plugin_name == "eslint"`
if plugin_name == "eslint" || !LintPlugins::from(plugin_name).is_empty() {
if LintPlugins::try_from(plugin_name).is_ok() {
let rule = rules_map.get(&plugin_name).copied().or_else(|| {
all_rules
.iter()
Expand Down
7 changes: 6 additions & 1 deletion crates/oxc_linter/src/tester.rs
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,12 @@ impl Tester {
)
.unwrap()
})
.with_builtin_plugins(self.plugins | LintPlugins::from(self.plugin_name))
.with_builtin_plugins(
self.plugins
| LintPlugins::try_from(self.plugin_name).unwrap_or_else(|()| {
panic!("invalid plugin name: {}", self.plugin_name)
}),
)
.with_rule(rule, AllowWarnDeny::Warn)
.build(&external_plugin_store)
.unwrap(),
Expand Down
5 changes: 2 additions & 3 deletions tasks/website/src/linter/rules/doc_page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,16 +172,15 @@ fn rule_source(rule: &RuleTableRow) -> String {
/// - Example: `eslint` => true
/// - Example: `jest` => false
fn is_default_plugin(plugin: &str) -> bool {
let plugin = LintPlugins::from(plugin);
LintPlugins::default().contains(plugin)
LintPlugins::try_from(plugin).is_ok_and(|plugin| LintPlugins::default().contains(plugin))
}

/// Returns the normalized plugin name.
/// - Example: `react_perf` -> `react-perf`
/// - Example: `eslint` -> `eslint`
/// - Example: `jsx_a11y` -> `jsx-a11y`
fn get_normalized_plugin_name(plugin: &str) -> &str {
LintPlugins::from(plugin).into()
LintPlugins::try_from(plugin).unwrap_or(LintPlugins::empty()).into()
}

fn how_to_use(rule: &RuleTableRow) -> String {
Expand Down
Loading