Skip to content

Commit

Permalink
feat(biome_js_analyze): noFlatMapIdentity (#2324)
Browse files Browse the repository at this point in the history
Co-authored-by: unvalley <[email protected]>
Co-authored-by: Victorien Elvinger <[email protected]>
Co-authored-by: Ze-Zheng Wu <[email protected]>
  • Loading branch information
4 people authored Apr 14, 2024
1 parent a70e6af commit 6ec264c
Show file tree
Hide file tree
Showing 16 changed files with 543 additions and 37 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,8 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b

- Implement [#2043](https://github.com/biomejs/biome/issues/2043): The React rule [`useExhaustiveDependencies`](https://biomejs.dev/linter/rules/use-exhaustive-dependencies/) is now also compatible with Preact hooks imported from `preact/hooks` or `preact/compat`. Contributed by @arendjr

- Add rule [noFlatMapIdentity](https://biomejs.dev/linter/rules/no-flat-map-identity) to disallow unnecessary callback use on `flatMap`. Contributed by @isnakode

- Add rule [noConstantMathMinMaxClamp](https://biomejs.dev/linter/rules/no-constant-math-min-max-clamp), which disallows using `Math.min` and `Math.max` to clamp a value where the result itself is constant. Contributed by @mgomulak

#### Enhancements
Expand Down
93 changes: 57 additions & 36 deletions crates/biome_configuration/src/linter/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2620,6 +2620,9 @@ pub struct Nursery {
#[doc = "Disallow using export or module.exports in files containing tests"]
#[serde(skip_serializing_if = "Option::is_none")]
pub no_exports_in_test: Option<RuleConfiguration<NoExportsInTest>>,
#[doc = "Disallow to use unnecessary callback on flatMap."]
#[serde(skip_serializing_if = "Option::is_none")]
pub no_flat_map_identity: Option<RuleConfiguration<NoFlatMapIdentity>>,
#[doc = "Disallow focused tests."]
#[serde(skip_serializing_if = "Option::is_none")]
pub no_focused_tests: Option<RuleConfiguration<NoFocusedTests>>,
Expand Down Expand Up @@ -2679,7 +2682,7 @@ impl DeserializableValidator for Nursery {
}
impl Nursery {
const GROUP_NAME: &'static str = "nursery";
pub(crate) const GROUP_RULES: [&'static str; 26] = [
pub(crate) const GROUP_RULES: [&'static str; 27] = [
"noBarrelFile",
"noColorInvalidHex",
"noConsole",
Expand All @@ -2692,6 +2695,7 @@ impl Nursery {
"noEvolvingAny",
"noExcessiveNestedTestSuites",
"noExportsInTest",
"noFlatMapIdentity",
"noFocusedTests",
"noMisplacedAssertion",
"noNamespaceImport",
Expand All @@ -2707,7 +2711,7 @@ impl Nursery {
"useNodeAssertStrict",
"useSortedClasses",
];
const RECOMMENDED_RULES: [&'static str; 11] = [
const RECOMMENDED_RULES: [&'static str; 12] = [
"noDoneCallback",
"noDuplicateElseIf",
"noDuplicateFontNames",
Expand All @@ -2716,11 +2720,12 @@ impl Nursery {
"noEvolvingAny",
"noExcessiveNestedTestSuites",
"noExportsInTest",
"noFlatMapIdentity",
"noFocusedTests",
"noSuspiciousSemicolonInJsx",
"noUselessTernary",
];
const RECOMMENDED_RULES_AS_FILTERS: [RuleFilter<'static>; 11] = [
const RECOMMENDED_RULES_AS_FILTERS: [RuleFilter<'static>; 12] = [
RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[4]),
RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[5]),
RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[6]),
Expand All @@ -2730,10 +2735,11 @@ impl Nursery {
RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[10]),
RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[11]),
RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[12]),
RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[19]),
RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[21]),
RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[13]),
RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[20]),
RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[22]),
];
const ALL_RULES_AS_FILTERS: [RuleFilter<'static>; 26] = [
const ALL_RULES_AS_FILTERS: [RuleFilter<'static>; 27] = [
RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[0]),
RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[1]),
RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[2]),
Expand All @@ -2760,6 +2766,7 @@ impl Nursery {
RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[23]),
RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[24]),
RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[25]),
RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[26]),
];
#[doc = r" Retrieves the recommended rules"]
pub(crate) fn is_recommended_true(&self) -> bool {
Expand Down Expand Up @@ -2836,76 +2843,81 @@ impl Nursery {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[11]));
}
}
if let Some(rule) = self.no_focused_tests.as_ref() {
if let Some(rule) = self.no_flat_map_identity.as_ref() {
if rule.is_enabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[12]));
}
}
if let Some(rule) = self.no_misplaced_assertion.as_ref() {
if let Some(rule) = self.no_focused_tests.as_ref() {
if rule.is_enabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[13]));
}
}
if let Some(rule) = self.no_namespace_import.as_ref() {
if let Some(rule) = self.no_misplaced_assertion.as_ref() {
if rule.is_enabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[14]));
}
}
if let Some(rule) = self.no_nodejs_modules.as_ref() {
if let Some(rule) = self.no_namespace_import.as_ref() {
if rule.is_enabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[15]));
}
}
if let Some(rule) = self.no_re_export_all.as_ref() {
if let Some(rule) = self.no_nodejs_modules.as_ref() {
if rule.is_enabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[16]));
}
}
if let Some(rule) = self.no_restricted_imports.as_ref() {
if let Some(rule) = self.no_re_export_all.as_ref() {
if rule.is_enabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[17]));
}
}
if let Some(rule) = self.no_skipped_tests.as_ref() {
if let Some(rule) = self.no_restricted_imports.as_ref() {
if rule.is_enabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[18]));
}
}
if let Some(rule) = self.no_suspicious_semicolon_in_jsx.as_ref() {
if let Some(rule) = self.no_skipped_tests.as_ref() {
if rule.is_enabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[19]));
}
}
if let Some(rule) = self.no_undeclared_dependencies.as_ref() {
if let Some(rule) = self.no_suspicious_semicolon_in_jsx.as_ref() {
if rule.is_enabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[20]));
}
}
if let Some(rule) = self.no_useless_ternary.as_ref() {
if let Some(rule) = self.no_undeclared_dependencies.as_ref() {
if rule.is_enabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[21]));
}
}
if let Some(rule) = self.use_import_restrictions.as_ref() {
if let Some(rule) = self.no_useless_ternary.as_ref() {
if rule.is_enabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[22]));
}
}
if let Some(rule) = self.use_jsx_key_in_iterable.as_ref() {
if let Some(rule) = self.use_import_restrictions.as_ref() {
if rule.is_enabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[23]));
}
}
if let Some(rule) = self.use_node_assert_strict.as_ref() {
if let Some(rule) = self.use_jsx_key_in_iterable.as_ref() {
if rule.is_enabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[24]));
}
}
if let Some(rule) = self.use_sorted_classes.as_ref() {
if let Some(rule) = self.use_node_assert_strict.as_ref() {
if rule.is_enabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[25]));
}
}
if let Some(rule) = self.use_sorted_classes.as_ref() {
if rule.is_enabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[26]));
}
}
index_set
}
pub(crate) fn get_disabled_rules(&self) -> IndexSet<RuleFilter> {
Expand Down Expand Up @@ -2970,76 +2982,81 @@ impl Nursery {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[11]));
}
}
if let Some(rule) = self.no_focused_tests.as_ref() {
if let Some(rule) = self.no_flat_map_identity.as_ref() {
if rule.is_disabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[12]));
}
}
if let Some(rule) = self.no_misplaced_assertion.as_ref() {
if let Some(rule) = self.no_focused_tests.as_ref() {
if rule.is_disabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[13]));
}
}
if let Some(rule) = self.no_namespace_import.as_ref() {
if let Some(rule) = self.no_misplaced_assertion.as_ref() {
if rule.is_disabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[14]));
}
}
if let Some(rule) = self.no_nodejs_modules.as_ref() {
if let Some(rule) = self.no_namespace_import.as_ref() {
if rule.is_disabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[15]));
}
}
if let Some(rule) = self.no_re_export_all.as_ref() {
if let Some(rule) = self.no_nodejs_modules.as_ref() {
if rule.is_disabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[16]));
}
}
if let Some(rule) = self.no_restricted_imports.as_ref() {
if let Some(rule) = self.no_re_export_all.as_ref() {
if rule.is_disabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[17]));
}
}
if let Some(rule) = self.no_skipped_tests.as_ref() {
if let Some(rule) = self.no_restricted_imports.as_ref() {
if rule.is_disabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[18]));
}
}
if let Some(rule) = self.no_suspicious_semicolon_in_jsx.as_ref() {
if let Some(rule) = self.no_skipped_tests.as_ref() {
if rule.is_disabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[19]));
}
}
if let Some(rule) = self.no_undeclared_dependencies.as_ref() {
if let Some(rule) = self.no_suspicious_semicolon_in_jsx.as_ref() {
if rule.is_disabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[20]));
}
}
if let Some(rule) = self.no_useless_ternary.as_ref() {
if let Some(rule) = self.no_undeclared_dependencies.as_ref() {
if rule.is_disabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[21]));
}
}
if let Some(rule) = self.use_import_restrictions.as_ref() {
if let Some(rule) = self.no_useless_ternary.as_ref() {
if rule.is_disabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[22]));
}
}
if let Some(rule) = self.use_jsx_key_in_iterable.as_ref() {
if let Some(rule) = self.use_import_restrictions.as_ref() {
if rule.is_disabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[23]));
}
}
if let Some(rule) = self.use_node_assert_strict.as_ref() {
if let Some(rule) = self.use_jsx_key_in_iterable.as_ref() {
if rule.is_disabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[24]));
}
}
if let Some(rule) = self.use_sorted_classes.as_ref() {
if let Some(rule) = self.use_node_assert_strict.as_ref() {
if rule.is_disabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[25]));
}
}
if let Some(rule) = self.use_sorted_classes.as_ref() {
if rule.is_disabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[26]));
}
}
index_set
}
#[doc = r" Checks if, given a rule name, matches one of the rules contained in this category"]
Expand All @@ -3050,10 +3067,10 @@ impl Nursery {
pub(crate) fn is_recommended_rule(rule_name: &str) -> bool {
Self::RECOMMENDED_RULES.contains(&rule_name)
}
pub(crate) fn recommended_rules_as_filters() -> [RuleFilter<'static>; 11] {
pub(crate) fn recommended_rules_as_filters() -> [RuleFilter<'static>; 12] {
Self::RECOMMENDED_RULES_AS_FILTERS
}
pub(crate) fn all_rules_as_filters() -> [RuleFilter<'static>; 26] {
pub(crate) fn all_rules_as_filters() -> [RuleFilter<'static>; 27] {
Self::ALL_RULES_AS_FILTERS
}
#[doc = r" Select preset rules"]
Expand Down Expand Up @@ -3124,6 +3141,10 @@ impl Nursery {
.no_exports_in_test
.as_ref()
.map(|conf| (conf.level(), conf.get_options())),
"noFlatMapIdentity" => self
.no_flat_map_identity
.as_ref()
.map(|conf| (conf.level(), conf.get_options())),
"noFocusedTests" => self
.no_focused_tests
.as_ref()
Expand Down
1 change: 1 addition & 0 deletions crates/biome_diagnostics_categories/src/categories.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ define_categories! {
"lint/nursery/noEvolvingAny": "https://biomejs.dev/linter/rules/no-evolving-any",
"lint/nursery/noExcessiveNestedTestSuites": "https://biomejs.dev/linter/rules/no-excessive-nested-test-suites",
"lint/nursery/noExportsInTest": "https://biomejs.dev/linter/rules/no-exports-in-test",
"lint/nursery/noFlatMapIdentity": "https://biomejs.dev/linter/rules/no-flat-map-identity",
"lint/nursery/noFocusedTests": "https://biomejs.dev/linter/rules/no-focused-tests",
"lint/nursery/noDuplicateFontNames": "https://biomejs.dev/linter/rules/no-font-family-duplicate-names",
"lint/nursery/noMisplacedAssertion": "https://biomejs.dev/linter/rules/no-misplaced-assertion",
Expand Down
2 changes: 2 additions & 0 deletions crates/biome_js_analyze/src/lint/nursery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub mod no_duplicate_test_hooks;
pub mod no_evolving_any;
pub mod no_excessive_nested_test_suites;
pub mod no_exports_in_test;
pub mod no_flat_map_identity;
pub mod no_focused_tests;
pub mod no_misplaced_assertion;
pub mod no_namespace_import;
Expand Down Expand Up @@ -39,6 +40,7 @@ declare_group! {
self :: no_evolving_any :: NoEvolvingAny ,
self :: no_excessive_nested_test_suites :: NoExcessiveNestedTestSuites ,
self :: no_exports_in_test :: NoExportsInTest ,
self :: no_flat_map_identity :: NoFlatMapIdentity ,
self :: no_focused_tests :: NoFocusedTests ,
self :: no_misplaced_assertion :: NoMisplacedAssertion ,
self :: no_namespace_import :: NoNamespaceImport ,
Expand Down
Loading

0 comments on commit 6ec264c

Please sign in to comment.