From 42f20995b7e559b9189e99ebcf6e966f7063a57a Mon Sep 17 00:00:00 2001 From: Ze-Zheng Wu Date: Fri, 14 Jun 2024 02:34:00 +0800 Subject: [PATCH] fix(migrate): properly handle rule removal and insertion --- crates/biome_cli/src/commands/migrate.rs | 2 +- .../src/analyzers/nursery_rules.rs | 132 ++++++++++++------ ...son => existingGroupWithExistingRule.json} | 2 +- .../existingGroupWithExistingRule.json.snap | 44 ++++++ .../nurseryRules/firstToExistingGroup.json | 11 ++ .../firstToExistingGroup.json.snap | 47 +++++++ .../nurseryRules/lastToExistingGroup.json | 11 ++ .../lastToExistingGroup.json.snap | 50 +++++++ .../nurseryRules/middleToExistingGroup.json | 12 ++ .../middleToExistingGroup.json.snap | 52 +++++++ .../renamedRuleAndNewRule.json.snap | 8 +- .../nurseryRules/singleToExistingGroup.json | 10 ++ ...n.snap => singleToExistingGroup.json.snap} | 20 ++- 13 files changed, 344 insertions(+), 57 deletions(-) rename crates/biome_migrate/tests/specs/migrations/nurseryRules/{existingGroup.json => existingGroupWithExistingRule.json} (75%) create mode 100644 crates/biome_migrate/tests/specs/migrations/nurseryRules/existingGroupWithExistingRule.json.snap create mode 100644 crates/biome_migrate/tests/specs/migrations/nurseryRules/firstToExistingGroup.json create mode 100644 crates/biome_migrate/tests/specs/migrations/nurseryRules/firstToExistingGroup.json.snap create mode 100644 crates/biome_migrate/tests/specs/migrations/nurseryRules/lastToExistingGroup.json create mode 100644 crates/biome_migrate/tests/specs/migrations/nurseryRules/lastToExistingGroup.json.snap create mode 100644 crates/biome_migrate/tests/specs/migrations/nurseryRules/middleToExistingGroup.json create mode 100644 crates/biome_migrate/tests/specs/migrations/nurseryRules/middleToExistingGroup.json.snap create mode 100644 crates/biome_migrate/tests/specs/migrations/nurseryRules/singleToExistingGroup.json rename crates/biome_migrate/tests/specs/migrations/nurseryRules/{existingGroup.json.snap => singleToExistingGroup.json.snap} (56%) diff --git a/crates/biome_cli/src/commands/migrate.rs b/crates/biome_cli/src/commands/migrate.rs index e4acffd72d83..7f0362f3ab90 100644 --- a/crates/biome_cli/src/commands/migrate.rs +++ b/crates/biome_cli/src/commands/migrate.rs @@ -8,7 +8,7 @@ use biome_service::workspace::RegisterProjectFolderParams; use super::{check_fix_incompatible_arguments, FixFileModeOptions, MigrateSubCommand}; -/// Handler for the "check" command of the Biome CLI +/// Handler for the "migrate" command of the Biome CLI pub(crate) fn migrate( session: CliSession, cli_options: CliOptions, diff --git a/crates/biome_migrate/src/analyzers/nursery_rules.rs b/crates/biome_migrate/src/analyzers/nursery_rules.rs index f471b5c015b8..ffebb98d6f50 100644 --- a/crates/biome_migrate/src/analyzers/nursery_rules.rs +++ b/crates/biome_migrate/src/analyzers/nursery_rules.rs @@ -6,11 +6,13 @@ use biome_diagnostics::category; use biome_json_factory::make::{ json_member, json_member_list, json_member_name, json_object_value, json_string_literal, token, }; -use biome_json_syntax::{AnyJsonValue, JsonMember, JsonMemberList, JsonRoot, T}; +use biome_json_syntax::{AnyJsonValue, JsonLanguage, JsonMember, JsonMemberList, JsonRoot, T}; use biome_rowan::{ - AstNode, AstNodeExt, AstSeparatedList, BatchMutationExt, TextRange, TriviaPieceKind, WalkEvent, + AstNode, AstNodeExt, AstSeparatedList, BatchMutationExt, SyntaxToken, TextRange, + TriviaPieceKind, WalkEvent, }; use rustc_hash::FxHashMap; +use std::iter::repeat; declare_migration! { pub(crate) NurseryRules { @@ -23,9 +25,11 @@ declare_migration! { #[derive(Debug)] pub(crate) struct MigrateRuleState { /// The member of the new rule - nursery_rule_member: JsonMember, + nursery_rule: JsonMember, /// The member of the group where the new rule should be moved nursery_group: JsonMember, + /// The comma separator to be deleted + optional_separator: Option>, /// The name of the new rule new_rule_name: &'static str, /// The new group name @@ -34,7 +38,12 @@ pub(crate) struct MigrateRuleState { impl MigrateRuleState { fn as_rule_name_range(&self) -> TextRange { - self.nursery_rule_member.range() + let range = self.nursery_rule.range(); + if let Some(separator) = &self.optional_separator { + TextRange::cover(separator.text_range(), range) + } else { + range + } } } @@ -131,36 +140,55 @@ impl Rule for NurseryRules { let node = ctx.query(); let mut rules_to_migrate = vec![]; - let nursery_group = find_group_by_name(node, "nursery"); - - if let Some(nursery_member) = nursery_group { - let mut rules = FxHashMap::default(); - for (group, (new_group, new_name)) in RULES_TO_MIGRATE { - rules.insert(*group, (*new_group, *new_name)); + if let Some(nursery_group) = find_group_by_name(node, "nursery") { + let mut rules_should_be_migrated = FxHashMap::default(); + for (group, (new_group_name, new_rule_name)) in RULES_TO_MIGRATE { + rules_should_be_migrated.insert(*group, (*new_group_name, *new_rule_name)); } - let object_value = nursery_member + let Some(nursery_group_object) = nursery_group .value() .ok() - .and_then(|node| node.as_json_object_value().cloned()); - - let Some(object_value) = object_value else { + .and_then(|node| node.as_json_object_value().cloned()) + else { return rules_to_migrate; }; - for group_member in object_value.json_member_list().iter().flatten() { - let Ok(member_name_text) = group_member + let mut separator_iterator = nursery_group_object + .json_member_list() + .separators() + .flatten() + .enumerate() + // Repeat the first separator, + // so when the rule to be deleted is the first rule, + // its trailing comma is also deleted: + // { + // "ruleA": "error", + // "ruleB": "error", + // "ruleC": "error" + // } + .flat_map(|(i, s)| repeat(s).take(if i == 0 { 2 } else { 1 })); + + for nursery_rule in nursery_group_object.json_member_list().iter().flatten() { + let optional_separator = separator_iterator.next(); + + let Ok(nursery_rule_name) = nursery_rule .name() .and_then(|node| node.inner_string_text()) else { continue; }; - let new_rule = rules.get(member_name_text.text()).copied(); - if let Some((new_group, new_rule)) = new_rule { + + let new_rule = rules_should_be_migrated + .get(nursery_rule_name.text()) + .copied(); + + if let Some((new_group_name, new_rule_name)) = new_rule { rules_to_migrate.push(MigrateRuleState { - nursery_rule_member: group_member.clone(), - nursery_group: nursery_member.clone(), - new_rule_name: new_rule, - new_group_name: new_group, + nursery_rule: nursery_rule.clone(), + nursery_group: nursery_group.clone(), + optional_separator, + new_rule_name, + new_group_name, }) } } @@ -188,33 +216,51 @@ impl Rule for NurseryRules { let MigrateRuleState { new_group_name, new_rule_name, + optional_separator, nursery_group, - nursery_rule_member: nursery_rule, + nursery_rule, } = state; let mut mutation = ctx.root().begin(); - - let new_group = find_group_by_name(node, new_group_name); + let mut rule_existed = false; // If the group exists, then we just need to update that group by adding a new member // with the name of rule we are migrating - if let Some(group) = new_group { - let value = group.value().ok()?; - let value = value.as_json_object_value()?; + if let Some(group) = find_group_by_name(node, new_group_name) { + let group_value = group.value().ok()?; + let group_value_object = group_value.as_json_object_value()?; - let mut separators = vec![]; - let mut new_list = vec![]; + let old_group_rules = group_value_object.json_member_list(); + let old_group_rules_count = old_group_rules.len(); - let old_list_node = value.json_member_list(); - let new_rule_member = - make_new_rule_name_member(new_rule_name, &nursery_rule.clone().detach())?; + let mut separators = Vec::with_capacity(old_group_rules_count + 1); + let mut new_group_rules = Vec::with_capacity(old_group_rules_count + 1); - for member in old_list_node.iter() { - let member = member.ok()?; - new_list.push(member.clone()); + for old_rule in old_group_rules.iter() { + let old_rule = old_rule.ok()?; + if old_rule + .name() + .and_then(|node| node.inner_string_text()) + .is_ok_and(|text| text.text() == *new_rule_name) + { + rule_existed = true; + break; + } + new_group_rules.push(old_rule.clone()); separators.push(token(T![,])); } - new_list.push(new_rule_member); - mutation.replace_node(old_list_node, json_member_list(new_list, separators)); + + if !rule_existed { + let new_rule_member = + make_new_rule_name_member(new_rule_name, &nursery_rule.clone().detach())?; + new_group_rules.push(new_rule_member); + mutation.replace_node( + old_group_rules, + json_member_list(new_group_rules, separators), + ); + } + if let Some(separator) = optional_separator { + mutation.remove_token(separator.clone()); + } mutation.remove_node(nursery_rule.clone()); } // If we don't have a group, we have to create one. To avoid possible side effects with our mutation logic @@ -311,8 +357,14 @@ impl Rule for NurseryRules { Some(MigrationAction::new( ActionCategory::QuickFix, ctx.metadata().applicability(), - markup! { - "Move the rule to the new stable group." + if rule_existed { + markup! { + "Remove the stale rule from the nursery group." + } + } else { + markup! { + "Move the rule to the new stable group." + } } .to_owned(), mutation, diff --git a/crates/biome_migrate/tests/specs/migrations/nurseryRules/existingGroup.json b/crates/biome_migrate/tests/specs/migrations/nurseryRules/existingGroupWithExistingRule.json similarity index 75% rename from crates/biome_migrate/tests/specs/migrations/nurseryRules/existingGroup.json rename to crates/biome_migrate/tests/specs/migrations/nurseryRules/existingGroupWithExistingRule.json index 92b49d30a5e9..47082f244d1e 100644 --- a/crates/biome_migrate/tests/specs/migrations/nurseryRules/existingGroup.json +++ b/crates/biome_migrate/tests/specs/migrations/nurseryRules/existingGroupWithExistingRule.json @@ -2,7 +2,7 @@ "linter": { "rules": { "nursery": { - "noExcessiveNestedTestSuites": "error" + "noExcessiveNestedTestSuites": "warn" }, "complexity": { "noExcessiveNestedTestSuites": "error" diff --git a/crates/biome_migrate/tests/specs/migrations/nurseryRules/existingGroupWithExistingRule.json.snap b/crates/biome_migrate/tests/specs/migrations/nurseryRules/existingGroupWithExistingRule.json.snap new file mode 100644 index 000000000000..fddf8ee5a9d0 --- /dev/null +++ b/crates/biome_migrate/tests/specs/migrations/nurseryRules/existingGroupWithExistingRule.json.snap @@ -0,0 +1,44 @@ +--- +source: crates/biome_migrate/tests/spec_tests.rs +expression: existingGroupWithExistingRule.json +--- +# Input +```json +{ + "linter": { + "rules": { + "nursery": { + "noExcessiveNestedTestSuites": "warn" + }, + "complexity": { + "noExcessiveNestedTestSuites": "error" + } + } + } +} + +``` + +# Diagnostics +``` +existingGroupWithExistingRule.json:5:9 migrate FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! This rule has been promoted to complexity/noExcessiveNestedTestSuites. + + 3 │ "rules": { + 4 │ "nursery": { + > 5 │ "noExcessiveNestedTestSuites": "warn" + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 6 │ }, + 7 │ "complexity": { + + i Unsafe fix: Remove the stale rule from the nursery group. + + 3 3 │ "rules": { + 4 4 │ "nursery": { + 5 │ - ········"noExcessiveNestedTestSuites":·"warn" + 6 5 │ }, + 7 6 │ "complexity": { + + +``` diff --git a/crates/biome_migrate/tests/specs/migrations/nurseryRules/firstToExistingGroup.json b/crates/biome_migrate/tests/specs/migrations/nurseryRules/firstToExistingGroup.json new file mode 100644 index 000000000000..4ff1543d6d40 --- /dev/null +++ b/crates/biome_migrate/tests/specs/migrations/nurseryRules/firstToExistingGroup.json @@ -0,0 +1,11 @@ +{ + "linter": { + "rules": { + "nursery": { + "noExcessiveNestedTestSuites": "error", + "nuseryRuleAlways": "error" + }, + "complexity": {} + } + } +} diff --git a/crates/biome_migrate/tests/specs/migrations/nurseryRules/firstToExistingGroup.json.snap b/crates/biome_migrate/tests/specs/migrations/nurseryRules/firstToExistingGroup.json.snap new file mode 100644 index 000000000000..0d3127bafd19 --- /dev/null +++ b/crates/biome_migrate/tests/specs/migrations/nurseryRules/firstToExistingGroup.json.snap @@ -0,0 +1,47 @@ +--- +source: crates/biome_migrate/tests/spec_tests.rs +expression: firstToExistingGroup.json +--- +# Input +```json +{ + "linter": { + "rules": { + "nursery": { + "noExcessiveNestedTestSuites": "error", + "nuseryRuleAlways": "error" + }, + "complexity": {} + } + } +} + +``` + +# Diagnostics +``` +firstToExistingGroup.json:5:9 migrate FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! This rule has been promoted to complexity/noExcessiveNestedTestSuites. + + 3 │ "rules": { + 4 │ "nursery": { + > 5 │ "noExcessiveNestedTestSuites": "error", + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 6 │ "nuseryRuleAlways": "error" + 7 │ }, + + i Unsafe fix: Move the rule to the new stable group. + + 3 3 │ "rules": { + 4 4 │ "nursery": { + 5 │ - ········"noExcessiveNestedTestSuites":·"error", + 6 5 │ "nuseryRuleAlways": "error" + 7 6 │ }, + 8 │ - ······"complexity":·{} + 7 │ + ······"complexity":·{"noExcessiveNestedTestSuites":·"error"} + 9 8 │ } + 10 9 │ } + + +``` diff --git a/crates/biome_migrate/tests/specs/migrations/nurseryRules/lastToExistingGroup.json b/crates/biome_migrate/tests/specs/migrations/nurseryRules/lastToExistingGroup.json new file mode 100644 index 000000000000..015893c755d0 --- /dev/null +++ b/crates/biome_migrate/tests/specs/migrations/nurseryRules/lastToExistingGroup.json @@ -0,0 +1,11 @@ +{ + "linter": { + "rules": { + "nursery": { + "nuseryRuleAlways": "error", + "noExcessiveNestedTestSuites": "error" + }, + "complexity": {} + } + } +} diff --git a/crates/biome_migrate/tests/specs/migrations/nurseryRules/lastToExistingGroup.json.snap b/crates/biome_migrate/tests/specs/migrations/nurseryRules/lastToExistingGroup.json.snap new file mode 100644 index 000000000000..faa235188d89 --- /dev/null +++ b/crates/biome_migrate/tests/specs/migrations/nurseryRules/lastToExistingGroup.json.snap @@ -0,0 +1,50 @@ +--- +source: crates/biome_migrate/tests/spec_tests.rs +expression: lastToExistingGroup.json +--- +# Input +```json +{ + "linter": { + "rules": { + "nursery": { + "nuseryRuleAlways": "error", + "noExcessiveNestedTestSuites": "error" + }, + "complexity": {} + } + } +} + +``` + +# Diagnostics +``` +lastToExistingGroup.json:5:36 migrate FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! This rule has been promoted to complexity/noExcessiveNestedTestSuites. + + 3 │ "rules": { + 4 │ "nursery": { + > 5 │ "nuseryRuleAlways": "error", + │ ^ + > 6 │ "noExcessiveNestedTestSuites": "error" + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 7 │ }, + 8 │ "complexity": {} + + i Unsafe fix: Move the rule to the new stable group. + + 3 3 │ "rules": { + 4 4 │ "nursery": { + 5 │ - ········"nuseryRuleAlways":·"error", + 6 │ - ········"noExcessiveNestedTestSuites":·"error" + 5 │ + ········"nuseryRuleAlways":·"error" + 7 6 │ }, + 8 │ - ······"complexity":·{} + 7 │ + ······"complexity":·{"noExcessiveNestedTestSuites":·"error"} + 9 8 │ } + 10 9 │ } + + +``` diff --git a/crates/biome_migrate/tests/specs/migrations/nurseryRules/middleToExistingGroup.json b/crates/biome_migrate/tests/specs/migrations/nurseryRules/middleToExistingGroup.json new file mode 100644 index 000000000000..6513070a137b --- /dev/null +++ b/crates/biome_migrate/tests/specs/migrations/nurseryRules/middleToExistingGroup.json @@ -0,0 +1,12 @@ +{ + "linter": { + "rules": { + "nursery": { + "nuseryRuleAlways": "error", + "noExcessiveNestedTestSuites": "error", + "nuseryRuleForever": "error" + }, + "complexity": {} + } + } +} diff --git a/crates/biome_migrate/tests/specs/migrations/nurseryRules/middleToExistingGroup.json.snap b/crates/biome_migrate/tests/specs/migrations/nurseryRules/middleToExistingGroup.json.snap new file mode 100644 index 000000000000..ad0d1c0a8a89 --- /dev/null +++ b/crates/biome_migrate/tests/specs/migrations/nurseryRules/middleToExistingGroup.json.snap @@ -0,0 +1,52 @@ +--- +source: crates/biome_migrate/tests/spec_tests.rs +expression: middleToExistingGroup.json +--- +# Input +```json +{ + "linter": { + "rules": { + "nursery": { + "nuseryRuleAlways": "error", + "noExcessiveNestedTestSuites": "error", + "nuseryRuleForever": "error" + }, + "complexity": {} + } + } +} + +``` + +# Diagnostics +``` +middleToExistingGroup.json:5:36 migrate FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! This rule has been promoted to complexity/noExcessiveNestedTestSuites. + + 3 │ "rules": { + 4 │ "nursery": { + > 5 │ "nuseryRuleAlways": "error", + │ ^ + > 6 │ "noExcessiveNestedTestSuites": "error", + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 7 │ "nuseryRuleForever": "error" + 8 │ }, + + i Unsafe fix: Move the rule to the new stable group. + + 3 3 │ "rules": { + 4 4 │ "nursery": { + 5 │ - ········"nuseryRuleAlways":·"error", + 6 │ - ········"noExcessiveNestedTestSuites":·"error", + 5 │ + ········"nuseryRuleAlways":·"error", + 7 6 │ "nuseryRuleForever": "error" + 8 7 │ }, + 9 │ - ······"complexity":·{} + 8 │ + ······"complexity":·{"noExcessiveNestedTestSuites":·"error"} + 10 9 │ } + 11 10 │ } + + +``` diff --git a/crates/biome_migrate/tests/specs/migrations/nurseryRules/renamedRuleAndNewRule.json.snap b/crates/biome_migrate/tests/specs/migrations/nurseryRules/renamedRuleAndNewRule.json.snap index 7033afa7f05c..598d34d6e56d 100644 --- a/crates/biome_migrate/tests/specs/migrations/nurseryRules/renamedRuleAndNewRule.json.snap +++ b/crates/biome_migrate/tests/specs/migrations/nurseryRules/renamedRuleAndNewRule.json.snap @@ -26,7 +26,7 @@ renamedRuleAndNewRule.json:5:9 migrate FIXABLE ━━━━━━━━━━ 3 │ "rules": { 4 │ "nursery": { > 5 │ "noExcessiveNestedTestSuites": "error", - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 6 │ "oldName": "error" 7 │ } @@ -48,12 +48,14 @@ renamedRuleAndNewRule.json:5:9 migrate FIXABLE ━━━━━━━━━━ ``` ``` -renamedRuleAndNewRule.json:6:9 migrate FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +renamedRuleAndNewRule.json:5:47 migrate FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! This rule has been promoted to suspicious/noSuspiciousSemicolonInJsx. + 3 │ "rules": { 4 │ "nursery": { - 5 │ "noExcessiveNestedTestSuites": "error", + > 5 │ "noExcessiveNestedTestSuites": "error", + │ ^ > 6 │ "oldName": "error" │ ^^^^^^^^^^^^^^^^^^ 7 │ } diff --git a/crates/biome_migrate/tests/specs/migrations/nurseryRules/singleToExistingGroup.json b/crates/biome_migrate/tests/specs/migrations/nurseryRules/singleToExistingGroup.json new file mode 100644 index 000000000000..8634a951b501 --- /dev/null +++ b/crates/biome_migrate/tests/specs/migrations/nurseryRules/singleToExistingGroup.json @@ -0,0 +1,10 @@ +{ + "linter": { + "rules": { + "nursery": { + "noExcessiveNestedTestSuites": "error" + }, + "complexity": {} + } + } +} diff --git a/crates/biome_migrate/tests/specs/migrations/nurseryRules/existingGroup.json.snap b/crates/biome_migrate/tests/specs/migrations/nurseryRules/singleToExistingGroup.json.snap similarity index 56% rename from crates/biome_migrate/tests/specs/migrations/nurseryRules/existingGroup.json.snap rename to crates/biome_migrate/tests/specs/migrations/nurseryRules/singleToExistingGroup.json.snap index 40081817859e..2ec9746fb393 100644 --- a/crates/biome_migrate/tests/specs/migrations/nurseryRules/existingGroup.json.snap +++ b/crates/biome_migrate/tests/specs/migrations/nurseryRules/singleToExistingGroup.json.snap @@ -1,6 +1,6 @@ --- source: crates/biome_migrate/tests/spec_tests.rs -expression: existingGroup.json +expression: singleToExistingGroup.json --- # Input ```json @@ -10,9 +10,7 @@ expression: existingGroup.json "nursery": { "noExcessiveNestedTestSuites": "error" }, - "complexity": { - "noExcessiveNestedTestSuites": "error" - } + "complexity": {} } } } @@ -21,7 +19,7 @@ expression: existingGroup.json # Diagnostics ``` -existingGroup.json:5:9 migrate FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +singleToExistingGroup.json:5:9 migrate FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! This rule has been promoted to complexity/noExcessiveNestedTestSuites. @@ -30,7 +28,7 @@ existingGroup.json:5:9 migrate FIXABLE ━━━━━━━━━━━━━ > 5 │ "noExcessiveNestedTestSuites": "error" │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 6 │ }, - 7 │ "complexity": { + 7 │ "complexity": {} i Unsafe fix: Move the rule to the new stable group. @@ -38,12 +36,10 @@ existingGroup.json:5:9 migrate FIXABLE ━━━━━━━━━━━━━ 4 4 │ "nursery": { 5 │ - ········"noExcessiveNestedTestSuites":·"error" 6 5 │ }, - 7 6 │ "complexity": { - 8 │ - ········"noExcessiveNestedTestSuites":·"error" - 7 │ + ········"noExcessiveNestedTestSuites":·"error", - 8 │ + ········"noExcessiveNestedTestSuites":·"error" - 9 9 │ } - 10 10 │ } + 7 │ - ······"complexity":·{} + 6 │ + ······"complexity":·{"noExcessiveNestedTestSuites":·"error"} + 8 7 │ } + 9 8 │ } ```