From baf8249ec4b5cb4260130540d8a4f8e78ded8b81 Mon Sep 17 00:00:00 2001 From: Nikola Hristov Date: Thu, 19 Dec 2024 00:10:38 +0200 Subject: [PATCH] --- crates/biome_analyze/Source/categories.rs | 40 +- crates/biome_analyze/Source/context.rs | 12 +- crates/biome_analyze/Source/diagnostics.rs | 26 +- crates/biome_analyze/Source/lib.rs | 70 +- crates/biome_analyze/Source/matcher.rs | 36 +- crates/biome_analyze/Source/options.rs | 8 +- crates/biome_analyze/Source/query.rs | 5 +- crates/biome_analyze/Source/registry.rs | 35 +- crates/biome_analyze/Source/rule.rs | 65 +- crates/biome_analyze/Source/services.rs | 9 +- crates/biome_analyze/Source/signals.rs | 16 +- .../Source/suppression_action.rs | 24 +- crates/biome_analyze/Source/syntax.rs | 12 +- crates/biome_analyze/Source/visitor.rs | 12 +- crates/biome_aria/Source/lib.rs | 8 +- crates/biome_aria/Source/properties.rs | 18 +- crates/biome_aria/Source/roles.rs | 31 +- crates/biome_aria_metadata/Source/lib.rs | 67 +- crates/biome_aria_metadata/build.rs | 100 +- crates/biome_cli/Source/changed.rs | 8 +- crates/biome_cli/Source/cli_options.rs | 3 +- crates/biome_cli/Source/commands/check.rs | 291 +- crates/biome_cli/Source/commands/ci.rs | 268 +- crates/biome_cli/Source/commands/clean.rs | 25 +- crates/biome_cli/Source/commands/daemon.rs | 437 +- crates/biome_cli/Source/commands/explain.rs | 99 +- crates/biome_cli/Source/commands/format.rs | 410 +- crates/biome_cli/Source/commands/init.rs | 21 +- crates/biome_cli/Source/commands/lint.rs | 299 +- crates/biome_cli/Source/commands/migrate.rs | 149 +- crates/biome_cli/Source/commands/mod.rs | 2038 +- crates/biome_cli/Source/commands/rage.rs | 621 +- crates/biome_cli/Source/commands/search.rs | 110 +- crates/biome_cli/Source/commands/version.rs | 51 +- crates/biome_cli/Source/diagnostics.rs | 78 +- .../biome_cli/Source/execute/diagnostics.rs | 176 +- crates/biome_cli/Source/execute/migrate.rs | 652 +- .../Source/execute/migrate/eslint.rs | 795 +- .../migrate/eslint_any_rule_to_biome.rs | 3292 +- .../Source/execute/migrate/eslint_eslint.rs | 942 +- .../Source/execute/migrate/eslint_jsxa11y.rs | 21 +- .../Source/execute/migrate/eslint_to_biome.rs | 862 +- .../execute/migrate/eslint_typescript.rs | 1216 +- .../Source/execute/migrate/eslint_unicorn.rs | 114 +- .../Source/execute/migrate/ignorefile.rs | 301 +- .../biome_cli/Source/execute/migrate/node.rs | 119 +- .../Source/execute/migrate/prettier.rs | 957 +- crates/biome_cli/Source/execute/mod.rs | 1073 +- .../biome_cli/Source/execute/process_file.rs | 338 +- .../Source/execute/process_file/assists.rs | 121 +- .../Source/execute/process_file/check.rs | 267 +- .../Source/execute/process_file/format.rs | 256 +- .../Source/execute/process_file/lint.rs | 266 +- .../execute/process_file/organize_imports.rs | 107 +- .../Source/execute/process_file/search.rs | 84 +- .../execute/process_file/workspace_file.rs | 140 +- crates/biome_cli/Source/execute/std_in.rs | 469 +- crates/biome_cli/Source/execute/traverse.rs | 1450 +- crates/biome_cli/Source/lib.rs | 27 +- crates/biome_cli/Source/logging.rs | 3 +- crates/biome_cli/Source/metrics.rs | 3 +- crates/biome_cli/Source/reporter/github.rs | 60 +- crates/biome_cli/Source/reporter/gitlab.rs | 375 +- crates/biome_cli/Source/reporter/json.rs | 89 +- crates/biome_cli/Source/reporter/junit.rs | 200 +- crates/biome_cli/Source/reporter/mod.rs | 72 +- crates/biome_cli/Source/reporter/summary.rs | 569 +- crates/biome_cli/Source/reporter/terminal.rs | 392 +- crates/biome_cli/Source/service/mod.rs | 680 +- crates/biome_cli/Source/service/unix.rs | 322 +- crates/biome_cli/Source/service/windows.rs | 437 +- crates/biome_cli/examples/text_reporter.rs | 21 +- .../Source/analyzer/assists/actions.rs | 297 +- .../Source/analyzer/assists/mod.rs | 48 +- .../Source/analyzer/linter/mod.rs | 63 +- .../Source/analyzer/linter/rules.rs | 15663 ++-- .../Source/analyzer/mod.rs | 689 +- crates/biome_configuration/Source/css.rs | 4 +- .../biome_configuration/Source/diagnostics.rs | 43 +- .../Source/editorconfig.rs | 39 +- .../biome_configuration/Source/formatter.rs | 9 +- .../Source/generated/assists.rs | 27 +- .../Source/generated/linter.rs | 153 +- crates/biome_configuration/Source/graphql.rs | 9 +- .../Source/javascript/formatter.rs | 257 +- .../Source/javascript/mod.rs | 170 +- crates/biome_configuration/Source/json.rs | 8 +- crates/biome_configuration/Source/lib.rs | 33 +- .../Source/organize_imports.rs | 4 +- .../biome_configuration/Source/overrides.rs | 33 +- .../Source/parse/json/linter.rs | 305 +- crates/biome_configuration/Source/vcs.rs | 12 +- crates/biome_console/Source/fmt.rs | 14 +- crates/biome_console/Source/lib.rs | 6 +- crates/biome_console/Source/markup.rs | 4 +- crates/biome_console/Source/utils.rs | 4 +- crates/biome_console/Source/write/html.rs | 425 +- .../biome_console/Source/write/termcolor.rs | 410 +- crates/biome_control_flow/Source/builder.rs | 29 +- crates/biome_control_flow/Source/lib.rs | 4 +- crates/biome_css_analyze/Source/keywords.rs | 19 +- crates/biome_css_analyze/Source/lib.rs | 24 +- crates/biome_css_analyze/Source/lint/a11y.rs | 12 +- .../lint/a11y/use_generic_font_names.rs | 257 +- .../Source/lint/correctness.rs | 26 +- ...no_invalid_direction_in_linear_gradient.rs | 248 +- .../lint/correctness/no_invalid_grid_areas.rs | 405 +- .../no_invalid_position_at_import_rule.rs | 137 +- .../lint/correctness/no_unknown_function.rs | 115 +- .../no_unknown_media_feature_name.rs | 612 +- .../lint/correctness/no_unknown_property.rs | 149 +- .../lint/correctness/no_unknown_unit.rs | 282 +- .../no_unmatchable_anb_selector.rs | 193 +- .../biome_css_analyze/Source/lint/nursery.rs | 30 +- .../lint/nursery/no_descending_specificity.rs | 312 +- .../nursery/no_duplicate_custom_properties.rs | 135 +- .../lint/nursery/no_duplicate_properties.rs | 190 +- .../lint/nursery/no_irregular_whitespace.rs | 163 +- .../lint/nursery/no_missing_var_function.rs | 422 +- .../Source/lint/nursery/no_unknown_at_rule.rs | 123 +- .../lint/nursery/no_unknown_pseudo_class.rs | 390 +- .../lint/nursery/no_unknown_pseudo_element.rs | 153 +- .../lint/nursery/no_unknown_type_selector.rs | 140 +- .../Source/lint/nursery/no_value_at_rule.rs | 95 +- .../Source/lint/suspicious.rs | 22 +- .../no_duplicate_at_import_rules.rs | 266 +- .../suspicious/no_duplicate_font_names.rs | 298 +- .../no_duplicate_selectors_keyframe_block.rs | 150 +- .../Source/lint/suspicious/no_empty_block.rs | 145 +- .../suspicious/no_important_in_keyframe.rs | 163 +- .../no_shorthand_property_overrides.rs | 328 +- crates/biome_css_analyze/Source/options.rs | 42 +- .../Source/services/semantic.rs | 207 +- .../Source/suppression_action.rs | 11 +- crates/biome_css_analyze/Source/utils.rs | 35 +- .../Source/generated/node_factory.rs | 5136 +- .../Source/generated/syntax_factory.rs | 9345 ++- crates/biome_css_formatter/Source/comments.rs | 28 +- crates/biome_css_formatter/Source/context.rs | 8 +- .../Source/css/any/at_rule.rs | 60 +- .../Source/css/any/attribute_matcher_value.rs | 20 +- .../Source/css/any/composes_import_source.rs | 20 +- .../Source/css/any/compound_selector.rs | 20 +- .../Source/css/any/conditional_block.rs | 22 +- .../css/any/container_and_combinable_query.rs | 26 +- .../css/any/container_or_combinable_query.rs | 26 +- .../Source/css/any/container_query.rs | 24 +- .../css/any/container_query_in_parens.rs | 26 +- .../container_style_and_combinable_query.rs | 32 +- .../css/any/container_style_in_parens.rs | 20 +- .../container_style_or_combinable_query.rs | 32 +- .../Source/css/any/container_style_query.rs | 26 +- .../Source/css/any/custom_identifier.rs | 20 +- .../Source/css/any/declaration_block.rs | 20 +- .../Source/css/any/declaration_name.rs | 20 +- .../Source/css/any/declaration_or_at_rule.rs | 20 +- .../css/any/declaration_or_at_rule_block.rs | 22 +- .../Source/css/any/declaration_or_rule.rs | 26 +- .../css/any/declaration_or_rule_block.rs | 20 +- .../Source/css/any/dimension.rs | 22 +- .../Source/css/any/document_matcher.rs | 22 +- .../Source/css/any/expression.rs | 22 +- .../Source/css/any/font_family_name.rs | 22 +- .../css/any/font_feature_values_block.rs | 20 +- .../css/any/font_feature_values_item.rs | 22 +- .../Source/css/any/function.rs | 20 +- .../Source/css/any/generic_component_value.rs | 20 +- .../Source/css/any/import_layer.rs | 20 +- .../css/any/import_supports_condition.rs | 20 +- .../Source/css/any/import_url.rs | 20 +- .../Source/css/any/keyframes_block.rs | 20 +- .../Source/css/any/keyframes_identifier.rs | 20 +- .../Source/css/any/keyframes_item.rs | 20 +- .../Source/css/any/keyframes_name.rs | 22 +- .../Source/css/any/keyframes_scope.rs | 20 +- .../Source/css/any/keyframes_selector.rs | 22 +- .../Source/css/any/layer.rs | 22 +- .../css/any/media_and_combinable_condition.rs | 24 +- .../Source/css/any/media_condition.rs | 24 +- .../Source/css/any/media_in_parens.rs | 20 +- .../css/any/media_or_combinable_condition.rs | 24 +- .../Source/css/any/media_query.rs | 24 +- .../Source/css/any/media_type_condition.rs | 22 +- .../Source/css/any/media_type_query.rs | 20 +- .../biome_css_formatter/Source/css/any/mod.rs | 3 +- .../Source/css/any/namespace_prefix.rs | 20 +- .../Source/css/any/namespace_url.rs | 20 +- .../Source/css/any/page_at_rule_block.rs | 20 +- .../Source/css/any/page_at_rule_item.rs | 22 +- .../Source/css/any/page_selector.rs | 20 +- .../Source/css/any/page_selector_pseudo.rs | 20 +- .../Source/css/any/property.rs | 22 +- .../Source/css/any/pseudo_class.rs | 40 +- .../Source/css/any/pseudo_class_nth.rs | 22 +- .../css/any/pseudo_class_nth_selector.rs | 20 +- .../Source/css/any/pseudo_element.rs | 24 +- .../Source/css/any/pseudo_value.rs | 20 +- .../Source/css/any/query_feature.rs | 26 +- .../Source/css/any/query_feature_value.rs | 26 +- .../Source/css/any/relative_selector.rs | 20 +- .../Source/css/any/rule.rs | 24 +- .../Source/css/any/rule_block.rs | 20 +- .../Source/css/any/scope_range.rs | 24 +- .../Source/css/any/selector.rs | 24 +- .../Source/css/any/simple_selector.rs | 20 +- .../Source/css/any/starting_style_block.rs | 22 +- .../Source/css/any/sub_selector.rs | 28 +- .../any/supports_and_combinable_condition.rs | 32 +- .../Source/css/any/supports_condition.rs | 24 +- .../Source/css/any/supports_in_parens.rs | 26 +- .../any/supports_or_combinable_condition.rs | 28 +- .../Source/css/any/unicode_value.rs | 24 +- .../Source/css/any/url_modifier.rs | 22 +- .../Source/css/any/url_value.rs | 20 +- .../Source/css/any/value.rs | 40 +- .../Source/css/any/value_at_rule_clause.rs | 20 +- .../css/any/value_at_rule_import_source.rs | 20 +- .../css/any/value_at_rule_import_specifier.rs | 28 +- .../Source/css/any/value_at_rule_property.rs | 20 +- .../Source/css/auxiliary/attribute_matcher.rs | 23 +- .../css/auxiliary/attribute_matcher_value.rs | 78 +- .../Source/css/auxiliary/attribute_name.rs | 11 +- .../Source/css/auxiliary/binary_expression.rs | 33 +- .../Source/css/auxiliary/bracketed_value.rs | 22 +- .../auxiliary/composes_import_specifier.rs | 15 +- .../css/auxiliary/composes_property_value.rs | 15 +- .../css/auxiliary/container_and_query.rs | 24 +- .../css/auxiliary/container_not_query.rs | 11 +- .../css/auxiliary/container_or_query.rs | 24 +- .../auxiliary/container_query_in_parens.rs | 33 +- .../container_size_feature_in_parens.rs | 33 +- .../auxiliary/container_style_and_query.rs | 28 +- .../auxiliary/container_style_in_parens.rs | 33 +- .../auxiliary/container_style_not_query.rs | 15 +- .../css/auxiliary/container_style_or_query.rs | 28 +- .../container_style_query_in_parens.rs | 43 +- .../Source/css/auxiliary/declaration.rs | 22 +- .../Source/css/auxiliary/declaration_block.rs | 28 +- .../css/auxiliary/declaration_important.rs | 14 +- .../auxiliary/declaration_or_at_rule_block.rs | 32 +- .../auxiliary/declaration_or_rule_block.rs | 32 +- .../auxiliary/declaration_with_semicolon.rs | 30 +- .../css/auxiliary/document_custom_matcher.rs | 31 +- .../Source/css/auxiliary/empty_declaration.rs | 24 +- .../Source/css/auxiliary/font_family_name.rs | 11 +- .../auxiliary/font_feature_values_block.rs | 32 +- .../css/auxiliary/font_feature_values_item.rs | 22 +- .../Source/css/auxiliary/function.rs | 36 +- .../Source/css/auxiliary/generic_delimiter.rs | 11 +- .../css/auxiliary/import_anonymous_layer.rs | 11 +- .../css/auxiliary/import_named_layer.rs | 36 +- .../Source/css/auxiliary/import_supports.rs | 36 +- .../Source/css/auxiliary/keyframes_block.rs | 28 +- .../Source/css/auxiliary/keyframes_item.rs | 18 +- .../css/auxiliary/keyframes_scope_function.rs | 31 +- .../css/auxiliary/keyframes_scope_prefix.rs | 11 +- .../css/auxiliary/keyframes_scoped_name.rs | 11 +- .../Source/css/auxiliary/layer_declaration.rs | 18 +- .../Source/css/auxiliary/layer_reference.rs | 20 +- .../list_of_component_values_expression.rs | 25 +- .../css/auxiliary/media_and_condition.rs | 24 +- .../css/auxiliary/media_and_type_query.rs | 24 +- .../auxiliary/media_condition_in_parens.rs | 33 +- .../css/auxiliary/media_condition_query.rs | 11 +- .../css/auxiliary/media_feature_in_parens.rs | 29 +- .../css/auxiliary/media_not_condition.rs | 14 +- .../css/auxiliary/media_or_condition.rs | 24 +- .../Source/css/auxiliary/media_type.rs | 11 +- .../Source/css/auxiliary/media_type_query.rs | 17 +- .../Source/css/auxiliary/metavariable.rs | 9 +- .../Source/css/auxiliary/mod.rs | 3 +- .../css/auxiliary/named_namespace_prefix.rs | 11 +- .../Source/css/auxiliary/namespace.rs | 14 +- .../css/auxiliary/nested_qualified_rule.rs | 29 +- .../Source/css/auxiliary/nth_offset.rs | 11 +- .../css/auxiliary/page_at_rule_block.rs | 28 +- .../Source/css/auxiliary/parameter.rs | 11 +- .../css/auxiliary/parenthesized_expression.rs | 33 +- .../Source/css/auxiliary/qualified_rule.rs | 29 +- .../css/auxiliary/query_feature_boolean.rs | 11 +- .../css/auxiliary/query_feature_plain.rs | 18 +- .../css/auxiliary/query_feature_range.rs | 24 +- .../query_feature_range_comparison.rs | 15 +- .../auxiliary/query_feature_range_interval.rs | 48 +- .../auxiliary/query_feature_reverse_range.rs | 28 +- .../Source/css/auxiliary/root.rs | 31 +- .../Source/css/auxiliary/rule_block.rs | 24 +- .../Source/css/auxiliary/scope_edge.rs | 29 +- .../Source/css/auxiliary/scope_range_end.rs | 11 +- .../css/auxiliary/scope_range_interval.rs | 24 +- .../Source/css/auxiliary/scope_range_start.rs | 11 +- .../css/auxiliary/supports_and_condition.rs | 33 +- .../auxiliary/supports_condition_in_parens.rs | 33 +- .../auxiliary/supports_feature_declaration.rs | 33 +- .../css/auxiliary/supports_not_condition.rs | 11 +- .../css/auxiliary/supports_or_condition.rs | 33 +- .../Source/css/auxiliary/unicode_codepoint.rs | 11 +- .../Source/css/auxiliary/unicode_range.rs | 14 +- .../css/auxiliary/unicode_range_interval.rs | 15 +- .../css/auxiliary/unicode_range_wildcard.rs | 11 +- .../auxiliary/universal_namespace_prefix.rs | 15 +- .../Source/css/auxiliary/url_function.rs | 35 +- .../value_at_rule_declaration_clause.rs | 13 +- .../auxiliary/value_at_rule_import_clause.rs | 28 +- .../value_at_rule_import_specifier.rs | 15 +- .../value_at_rule_named_import_specifier.rs | 36 +- .../Source/css/bogus/bogus.rs | 3 +- .../Source/css/bogus/bogus_at_rule.rs | 3 +- .../Source/css/bogus/bogus_block.rs | 3 +- .../css/bogus/bogus_custom_identifier.rs | 3 +- .../css/bogus/bogus_declaration_item.rs | 3 +- .../css/bogus/bogus_document_matcher.rs | 3 +- .../css/bogus/bogus_font_family_name.rs | 3 +- .../bogus/bogus_font_feature_values_item.rs | 3 +- .../Source/css/bogus/bogus_keyframes_item.rs | 3 +- .../Source/css/bogus/bogus_keyframes_name.rs | 3 +- .../Source/css/bogus/bogus_layer.rs | 3 +- .../Source/css/bogus/bogus_media_query.rs | 3 +- .../css/bogus/bogus_page_selector_pseudo.rs | 3 +- .../Source/css/bogus/bogus_parameter.rs | 3 +- .../Source/css/bogus/bogus_property.rs | 3 +- .../Source/css/bogus/bogus_property_value.rs | 3 +- .../Source/css/bogus/bogus_pseudo_class.rs | 3 +- .../Source/css/bogus/bogus_pseudo_element.rs | 3 +- .../Source/css/bogus/bogus_rule.rs | 3 +- .../Source/css/bogus/bogus_scope_range.rs | 3 +- .../Source/css/bogus/bogus_selector.rs | 3 +- .../Source/css/bogus/bogus_sub_selector.rs | 3 +- .../css/bogus/bogus_unicode_range_value.rs | 3 +- .../Source/css/bogus/bogus_url_modifier.rs | 3 +- .../Source/css/bogus/mod.rs | 3 +- .../bogus/unknown_at_rule_component_list.rs | 3 +- .../css/bogus/value_at_rule_generic_value.rs | 3 +- .../Source/css/lists/bracketed_value_list.rs | 13 +- .../Source/css/lists/component_value_list.rs | 12 +- .../Source/css/lists/composes_class_list.rs | 13 +- .../css/lists/compound_selector_list.rs | 47 +- .../css/lists/custom_identifier_list.rs | 13 +- .../Source/css/lists/declaration_list.rs | 26 +- .../css/lists/declaration_or_at_rule_list.rs | 29 +- .../css/lists/declaration_or_rule_list.rs | 26 +- .../Source/css/lists/document_matcher_list.rs | 21 +- .../Source/css/lists/font_family_name_list.rs | 21 +- .../lists/font_feature_values_item_list.rs | 23 +- .../css/lists/generic_component_value_list.rs | 12 +- .../Source/css/lists/keyframes_item_list.rs | 23 +- .../css/lists/keyframes_selector_list.rs | 69 +- .../Source/css/lists/layer_name_list.rs | 11 +- .../Source/css/lists/layer_reference_list.rs | 27 +- .../Source/css/lists/media_query_list.rs | 15 +- .../Source/css/lists/mod.rs | 3 +- .../Source/css/lists/nested_selector_list.rs | 11 +- .../css/lists/page_at_rule_item_list.rs | 23 +- .../Source/css/lists/page_selector_list.rs | 47 +- .../css/lists/page_selector_pseudo_list.rs | 11 +- .../Source/css/lists/parameter_list.rs | 27 +- .../Source/css/lists/pseudo_value_list.rs | 27 +- .../css/lists/relative_selector_list.rs | 80 +- .../Source/css/lists/rule_list.rs | 23 +- .../Source/css/lists/selector_list.rs | 154 +- .../Source/css/lists/sub_selector_list.rs | 11 +- .../Source/css/lists/url_modifier_list.rs | 11 +- .../value_at_rule_import_specifier_list.rs | 25 +- .../css/lists/value_at_rule_property_list.rs | 11 +- crates/biome_css_formatter/Source/css/mod.rs | 3 +- .../css/properties/composes_property.rs | 18 +- .../Source/css/properties/generic_property.rs | 18 +- .../Source/css/properties/mod.rs | 3 +- .../value_at_rule_generic_property.rs | 22 +- .../Source/css/pseudo/mod.rs | 3 +- .../Source/css/pseudo/page_selector_pseudo.rs | 14 +- ...o_class_function_compound_selector_list.rs | 49 +- .../pseudo_class_function_identifier.rs | 41 +- .../css/pseudo/pseudo_class_function_nth.rs | 40 +- ...o_class_function_relative_selector_list.rs | 53 +- .../pseudo_class_function_selector_list.rs | 49 +- .../pseudo_class_function_value_list.rs | 41 +- .../css/pseudo/pseudo_class_identifier.rs | 15 +- .../Source/css/pseudo/pseudo_class_nth.rs | 24 +- .../css/pseudo/pseudo_class_nth_identifier.rs | 15 +- .../css/pseudo/pseudo_class_nth_number.rs | 11 +- .../pseudo_element_function_identifier.rs | 48 +- .../css/pseudo/pseudo_element_identifier.rs | 15 +- .../css/selectors/attribute_selector.rs | 27 +- .../Source/css/selectors/class_selector.rs | 11 +- .../Source/css/selectors/complex_selector.rs | 137 +- .../Source/css/selectors/compound_selector.rs | 29 +- .../Source/css/selectors/id_selector.rs | 11 +- .../css/selectors/keyframes_ident_selector.rs | 15 +- .../keyframes_percentage_selector.rs | 15 +- .../Source/css/selectors/mod.rs | 3 +- .../Source/css/selectors/nested_selector.rs | 11 +- .../Source/css/selectors/page_selector.rs | 11 +- ...pseudo_class_function_compound_selector.rs | 49 +- .../pseudo_class_function_selector.rs | 40 +- .../selectors/pseudo_class_nth_selector.rs | 23 +- .../selectors/pseudo_class_of_nth_selector.rs | 18 +- .../css/selectors/pseudo_class_selector.rs | 11 +- .../pseudo_element_function_selector.rs | 40 +- .../css/selectors/pseudo_element_selector.rs | 18 +- .../Source/css/selectors/relative_selector.rs | 20 +- .../selectors/supports_feature_selector.rs | 37 +- .../Source/css/selectors/type_selector.rs | 11 +- .../css/selectors/universal_selector.rs | 14 +- .../Source/css/statements/at_rule.rs | 11 +- .../Source/css/statements/charset_at_rule.rs | 26 +- .../css/statements/color_profile_at_rule.rs | 27 +- .../css/statements/container_at_rule.rs | 24 +- .../css/statements/counter_style_at_rule.rs | 27 +- .../Source/css/statements/document_at_rule.rs | 27 +- .../css/statements/font_face_at_rule.rs | 14 +- .../statements/font_feature_values_at_rule.rs | 37 +- .../statements/font_palette_values_at_rule.rs | 37 +- .../Source/css/statements/import_at_rule.rs | 69 +- .../css/statements/keyframes_at_rule.rs | 24 +- .../Source/css/statements/layer_at_rule.rs | 11 +- .../Source/css/statements/margin_at_rule.rs | 18 +- .../Source/css/statements/media_at_rule.rs | 72 +- .../Source/css/statements/mod.rs | 3 +- .../css/statements/namespace_at_rule.rs | 36 +- .../Source/css/statements/page_at_rule.rs | 33 +- .../Source/css/statements/property_at_rule.rs | 24 +- .../Source/css/statements/scope_at_rule.rs | 24 +- .../css/statements/starting_style_at_rule.rs | 14 +- .../Source/css/statements/supports_at_rule.rs | 33 +- .../css/statements/unknown_block_at_rule.rs | 23 +- .../css/statements/unknown_value_at_rule.rs | 29 +- .../Source/css/statements/value_at_rule.rs | 23 +- .../Source/css/value/color.rs | 21 +- .../Source/css/value/custom_identifier.rs | 11 +- .../Source/css/value/dashed_identifier.rs | 11 +- .../Source/css/value/identifier.rs | 11 +- .../Source/css/value/mod.rs | 3 +- .../Source/css/value/number.rs | 9 +- .../Source/css/value/percentage.rs | 14 +- .../Source/css/value/ratio.rs | 33 +- .../Source/css/value/regular_dimension.rs | 26 +- .../Source/css/value/string.rs | 49 +- .../Source/css/value/unknown_dimension.rs | 28 +- .../Source/css/value/url_value_raw.rs | 27 +- .../biome_css_formatter/Source/generated.rs | 3266 +- crates/biome_css_formatter/Source/lib.rs | 25 +- crates/biome_css_formatter/Source/prelude.rs | 16 +- .../biome_css_formatter/Source/separated.rs | 30 +- .../Source/utils/block_like.rs | 130 +- .../Source/utils/component_value_list.rs | 393 +- .../Source/utils/string_utils.rs | 481 +- crates/biome_css_parser/Source/lexer/mod.rs | 2663 +- crates/biome_css_parser/Source/lexer/tests.rs | 666 +- crates/biome_css_parser/Source/lib.rs | 17 +- crates/biome_css_parser/Source/parser.rs | 4 +- .../Source/syntax/at_rule/charset.rs | 106 +- .../Source/syntax/at_rule/color_profile.rs | 86 +- .../Source/syntax/at_rule/container.rs | 361 +- .../Source/syntax/at_rule/counter_style.rs | 84 +- .../Source/syntax/at_rule/document.rs | 255 +- .../Source/syntax/at_rule/feature.rs | 181 +- .../Source/syntax/at_rule/font_face.rs | 34 +- .../syntax/at_rule/font_feature_values.rs | 446 +- .../syntax/at_rule/font_palette_values.rs | 79 +- .../Source/syntax/at_rule/import.rs | 220 +- .../Source/syntax/at_rule/keyframes.rs | 522 +- .../Source/syntax/at_rule/layer.rs | 195 +- .../Source/syntax/at_rule/media.rs | 386 +- .../Source/syntax/at_rule/mod.rs | 144 +- .../Source/syntax/at_rule/namespace.rs | 145 +- .../Source/syntax/at_rule/page.rs | 351 +- .../Source/syntax/at_rule/parse_error.rs | 119 +- .../Source/syntax/at_rule/property.rs | 84 +- .../Source/syntax/at_rule/scope.rs | 169 +- .../Source/syntax/at_rule/starting_style.rs | 59 +- .../Source/syntax/at_rule/supports.rs | 243 +- .../Source/syntax/at_rule/unknown.rs | 86 +- .../Source/syntax/at_rule/value.rs | 425 +- .../Source/syntax/block/conditional_block.rs | 30 +- .../Source/syntax/block/declaration_block.rs | 28 +- .../declaration_or_at_rule_list_block.rs | 111 +- .../block/declaration_or_rule_list_block.rs | 255 +- .../Source/syntax/block/mod.rs | 79 +- .../Source/syntax/block/rule_block.rs | 27 +- .../Source/syntax/css_modules.rs | 90 +- crates/biome_css_parser/Source/syntax/mod.rs | 841 +- .../Source/syntax/parse_error.rs | 419 +- .../Source/syntax/property/color.rs | 59 +- .../Source/syntax/property/mod.rs | 341 +- .../Source/syntax/property/unicode_range.rs | 271 +- .../Source/syntax/selector/attribute.rs | 182 +- .../Source/syntax/selector/mod.rs | 829 +- .../Source/syntax/selector/nested_selector.rs | 80 +- .../function_compound_selector.rs | 83 +- .../function_compound_selector_list.rs | 121 +- .../pseudo_class/function_identifier.rs | 96 +- .../selector/pseudo_class/function_nth.rs | 308 +- .../function_relative_selector_list.rs | 87 +- .../pseudo_class/function_selector.rs | 115 +- .../pseudo_class/function_selector_list.rs | 78 +- .../pseudo_class/function_value_list.rs | 140 +- .../selector/pseudo_class/identifier.rs | 33 +- .../syntax/selector/pseudo_class/mod.rs | 136 +- .../Source/syntax/selector/pseudo_element.rs | 191 +- .../syntax/selector/relative_selector.rs | 294 +- .../Source/syntax/value/dimension.rs | 333 +- .../Source/syntax/value/function.rs | 352 +- .../Source/syntax/value/parse_error.rs | 35 +- .../Source/syntax/value/url.rs | 249 +- .../biome_css_parser/Source/token_source.rs | 11 +- crates/biome_css_semantic/Source/events.rs | 56 +- .../Source/semantic_model/builder.rs | 327 +- .../Source/semantic_model/mod.rs | 362 +- .../Source/semantic_model/model.rs | 235 +- .../Source/semantic_model/specificity.rs | 318 +- crates/biome_css_syntax/Source/file_source.rs | 8 +- .../biome_css_syntax/Source/generated/kind.rs | 1907 +- .../Source/generated/macros.rs | 1795 +- .../Source/generated/nodes.rs | 38897 ++++----- .../Source/generated/nodes_mut.rs | 4621 +- crates/biome_css_syntax/Source/lib.rs | 14 +- .../biome_deserialize/Source/diagnostics.rs | 22 +- crates/biome_deserialize/Source/impls.rs | 50 +- crates/biome_deserialize/Source/json.rs | 54 +- crates/biome_deserialize/Source/lib.rs | 15 +- crates/biome_deserialize/Source/string_set.rs | 8 +- crates/biome_deserialize/Source/validator.rs | 7 +- .../Source/deserializable_derive.rs | 108 +- .../deserializable_derive/container_attrs.rs | 214 +- .../enum_variant_attrs.rs | 100 +- .../struct_field_attrs.rs | 293 +- .../Source/partial_derive.rs | 32 +- .../Source/partial_derive/attrs.rs | 177 +- .../biome_deserialize_macros/Source/util.rs | 5 +- crates/biome_diagnostics/Source/adapters.rs | 28 +- crates/biome_diagnostics/Source/advice.rs | 28 +- crates/biome_diagnostics/Source/context.rs | 97 +- crates/biome_diagnostics/Source/diagnostic.rs | 8 +- .../Source/display/backtrace.rs | 661 +- .../biome_diagnostics/Source/display/diff.rs | 1409 +- .../biome_diagnostics/Source/display/frame.rs | 1167 +- .../Source/display/message.rs | 94 +- .../Source/display_github.rs | 8 +- crates/biome_diagnostics/Source/error.rs | 18 +- crates/biome_diagnostics/Source/location.rs | 21 +- crates/biome_diagnostics/Source/panic.rs | 3 +- crates/biome_diagnostics/Source/serde.rs | 27 +- crates/biome_diagnostics/examples/fs.rs | 14 +- crates/biome_diagnostics/examples/lint.rs | 16 +- .../Source/lib.rs | 5 +- .../Source/generate.rs | 8 +- .../biome_diagnostics_macros/Source/parse.rs | 52 +- crates/biome_flags/Source/lib.rs | 17 +- crates/biome_formatter/Source/arguments.rs | 21 +- crates/biome_formatter/Source/buffer.rs | 48 +- crates/biome_formatter/Source/builders.rs | 109 +- crates/biome_formatter/Source/comments.rs | 84 +- .../Source/comments/builder.rs | 1899 +- crates/biome_formatter/Source/comments/map.rs | 1342 +- crates/biome_formatter/Source/diagnostics.rs | 54 +- .../biome_formatter/Source/format_element.rs | 32 +- .../Source/format_element/document.rs | 1655 +- .../Source/format_element/tag.rs | 449 +- crates/biome_formatter/Source/formatter.rs | 17 +- crates/biome_formatter/Source/group_id.rs | 8 +- crates/biome_formatter/Source/lib.rs | 87 +- crates/biome_formatter/Source/macros.rs | 10 +- .../biome_formatter/Source/printed_tokens.rs | 11 +- .../Source/printer/call_stack.rs | 448 +- .../Source/printer/line_suffixes.rs | 49 +- crates/biome_formatter/Source/printer/mod.rs | 3430 +- .../Source/printer/printer_options/mod.rs | 164 +- .../biome_formatter/Source/printer/queue.rs | 514 +- .../biome_formatter/Source/printer/stack.rs | 169 +- crates/biome_formatter/Source/separated.rs | 15 +- crates/biome_formatter/Source/source_map.rs | 79 +- crates/biome_formatter/Source/token/number.rs | 546 +- crates/biome_formatter/Source/token/string.rs | 322 +- crates/biome_formatter/Source/trivia.rs | 42 +- crates/biome_formatter/Source/verbatim.rs | 15 +- .../Source/check_reformat.rs | 37 +- .../Source/diff_report.rs | 98 +- crates/biome_formatter_test/Source/lib.rs | 10 +- .../Source/snapshot_builder.rs | 10 +- crates/biome_formatter_test/Source/spec.rs | 52 +- .../Source/test_prettier_snapshot.rs | 30 +- crates/biome_formatter_test/Source/utils.rs | 32 +- crates/biome_fs/Source/dir.rs | 5 +- crates/biome_fs/Source/fs.rs | 37 +- crates/biome_fs/Source/fs/memory.rs | 923 +- crates/biome_fs/Source/fs/os.rs | 710 +- crates/biome_fs/Source/path.rs | 10 +- crates/biome_glob/Source/lib.rs | 66 +- crates/biome_graphql_analyze/Source/lib.rs | 24 +- .../Source/lint/nursery.rs | 18 +- .../lint/nursery/no_duplicated_fields.rs | 340 +- .../lint/nursery/use_deprecated_reason.rs | 148 +- .../lint/nursery/use_named_operation.rs | 220 +- .../lint/nursery/use_naming_convention.rs | 121 +- .../biome_graphql_analyze/Source/options.rs | 6 +- .../Source/suppression_action.rs | 5 +- .../Source/generated/node_factory.rs | 2867 +- .../Source/generated/syntax_factory.rs | 4291 +- .../Source/comments.rs | 15 +- .../biome_graphql_formatter/Source/context.rs | 12 +- .../Source/generated.rs | 1110 +- .../Source/graphql/any/definition.rs | 34 +- .../Source/graphql/any/mod.rs | 3 +- .../graphql/any/operation_definition.rs | 24 +- .../Source/graphql/any/primitive_type.rs | 20 +- .../Source/graphql/any/selection.rs | 24 +- .../Source/graphql/any/ts_type.rs | 22 +- .../Source/graphql/any/type_definition.rs | 30 +- .../Source/graphql/any/type_extension.rs | 28 +- .../Source/graphql/any/value.rs | 36 +- .../Source/graphql/auxiliary/alias.rs | 11 +- .../Source/graphql/auxiliary/argument.rs | 18 +- .../Source/graphql/auxiliary/arguments.rs | 29 +- .../Source/graphql/auxiliary/description.rs | 13 +- .../Source/graphql/auxiliary/directive.rs | 15 +- .../graphql/auxiliary/directive_location.rs | 15 +- .../Source/graphql/auxiliary/field.rs | 33 +- .../graphql/auxiliary/fragment_spread.rs | 22 +- .../auxiliary/implements_interfaces.rs | 28 +- .../graphql/auxiliary/inline_fragment.rs | 29 +- .../Source/graphql/auxiliary/list_type.rs | 22 +- .../Source/graphql/auxiliary/literal_name.rs | 11 +- .../Source/graphql/auxiliary/mod.rs | 3 +- .../Source/graphql/auxiliary/name_binding.rs | 11 +- .../graphql/auxiliary/name_reference.rs | 15 +- .../Source/graphql/auxiliary/non_null_type.rs | 11 +- .../Source/graphql/auxiliary/object_field.rs | 18 +- .../graphql/auxiliary/operation_type.rs | 15 +- .../Source/graphql/auxiliary/root.rs | 31 +- .../graphql/auxiliary/root_operation_types.rs | 33 +- .../Source/graphql/auxiliary/selection_set.rs | 29 +- .../graphql/auxiliary/type_condition.rs | 15 +- .../graphql/auxiliary/union_member_types.rs | 83 +- .../graphql/auxiliary/variable_binding.rs | 15 +- .../graphql/auxiliary/variable_definitions.rs | 33 +- .../graphql/auxiliary/variable_reference.rs | 15 +- .../Source/graphql/bogus/bogus.rs | 3 +- .../Source/graphql/bogus/bogus_definition.rs | 3 +- .../Source/graphql/bogus/bogus_selection.rs | 3 +- .../Source/graphql/bogus/bogus_type.rs | 3 +- .../Source/graphql/bogus/bogus_value.rs | 3 +- .../Source/graphql/bogus/mod.rs | 3 +- .../definitions/arguments_definition.rs | 38 +- .../definitions/directive_definition.rs | 81 +- .../definitions/enum_type_definition.rs | 57 +- .../definitions/enum_value_definition.rs | 29 +- .../definitions/enum_values_definition.rs | 34 +- .../graphql/definitions/field_definition.rs | 59 +- .../graphql/definitions/fields_definition.rs | 34 +- .../definitions/fragment_definition.rs | 55 +- .../definitions/input_fields_definition.rs | 34 +- .../input_object_type_definition.rs | 60 +- .../definitions/input_value_definition.rs | 59 +- .../definitions/interface_type_definition.rs | 67 +- .../Source/graphql/definitions/mod.rs | 3 +- .../definitions/object_type_definition.rs | 63 +- .../definitions/operation_definition.rs | 52 +- .../root_operation_type_definition.rs | 40 +- .../definitions/scalar_type_definition.rs | 39 +- .../graphql/definitions/schema_definition.rs | 51 +- .../definitions/union_type_definition.rs | 65 +- .../definitions/variable_definition.rs | 46 +- .../graphql/extensions/enum_type_extension.rs | 55 +- .../extensions/input_object_type_extension.rs | 58 +- .../extensions/interface_type_extension.rs | 61 +- .../Source/graphql/extensions/mod.rs | 3 +- .../extensions/object_type_extension.rs | 61 +- .../extensions/scalar_type_extension.rs | 45 +- .../graphql/extensions/schema_extension.rs | 45 +- .../extensions/union_type_extension.rs | 53 +- .../graphql/lists/argument_definition_list.rs | 59 +- .../Source/graphql/lists/argument_list.rs | 39 +- .../Source/graphql/lists/definition_list.rs | 22 +- .../Source/graphql/lists/directive_list.rs | 50 +- .../graphql/lists/directive_location_list.rs | 16 +- .../Source/graphql/lists/enum_value_list.rs | 22 +- .../graphql/lists/field_definition_list.rs | 22 +- .../lists/implements_interface_list.rs | 20 +- .../Source/graphql/lists/input_field_list.rs | 22 +- .../graphql/lists/list_value_element_list.rs | 25 +- .../Source/graphql/lists/mod.rs | 3 +- .../graphql/lists/object_value_member_list.rs | 25 +- .../root_operation_type_definition_list.rs | 32 +- .../Source/graphql/lists/selection_list.rs | 22 +- .../graphql/lists/union_member_type_list.rs | 62 +- .../graphql/lists/variable_definition_list.rs | 29 +- .../Source/graphql/mod.rs | 3 +- .../Source/graphql/value/boolean_value.rs | 11 +- .../Source/graphql/value/default_value.rs | 11 +- .../Source/graphql/value/enum_value.rs | 11 +- .../Source/graphql/value/float_value.rs | 13 +- .../Source/graphql/value/int_value.rs | 13 +- .../Source/graphql/value/list_value.rs | 29 +- .../Source/graphql/value/mod.rs | 3 +- .../Source/graphql/value/null_value.rs | 11 +- .../Source/graphql/value/object_value.rs | 37 +- .../Source/graphql/value/string_value.rs | 136 +- .../Source/utils/list.rs | 54 +- .../biome_graphql_parser/Source/lexer/mod.rs | 1576 +- .../Source/lexer/tests.rs | 583 +- .../Source/parser/argument.rs | 111 +- .../Source/parser/definitions/directive.rs | 193 +- .../Source/parser/definitions/enum.rs | 197 +- .../Source/parser/definitions/field.rs | 283 +- .../Source/parser/definitions/fragment.rs | 56 +- .../Source/parser/definitions/input_object.rs | 142 +- .../Source/parser/definitions/interface.rs | 190 +- .../Source/parser/definitions/mod.rs | 171 +- .../Source/parser/definitions/object.rs | 76 +- .../Source/parser/definitions/operation.rs | 394 +- .../Source/parser/definitions/scalar.rs | 65 +- .../Source/parser/definitions/schema.rs | 216 +- .../Source/parser/definitions/union.rs | 174 +- .../Source/parser/directive.rs | 77 +- .../biome_graphql_parser/Source/parser/mod.rs | 240 +- .../Source/parser/parse_error.rs | 188 +- .../Source/parser/type.rs | 74 +- .../Source/parser/value.rs | 389 +- .../Source/parser/variable.rs | 40 +- .../Source/semantic_model/binding.rs | 154 +- .../Source/semantic_model/builder.rs | 289 +- .../Source/semantic_model/mod.rs | 40 +- .../Source/semantic_model/model.rs | 321 +- .../Source/semantic_model/reference.rs | 337 +- .../Source/generated/kind.rs | 576 +- .../Source/generated/macros.rs | 763 +- .../Source/generated/nodes.rs | 12840 ++- .../Source/generated/nodes_mut.rs | 2447 +- .../Source/generated/node_factory.rs | 2899 +- .../Source/generated/syntax_factory.rs | 6183 +- .../Source/grit/any/code_snippet_source.rs | 22 +- .../Source/grit/any/container.rs | 24 +- .../Source/grit/any/definition.rs | 26 +- .../Source/grit/any/language_declaration.rs | 20 +- .../Source/grit/any/language_flavor_kind.rs | 20 +- .../Source/grit/any/list_accessor_subject.rs | 20 +- .../Source/grit/any/list_index.rs | 22 +- .../Source/grit/any/list_pattern.rs | 20 +- .../Source/grit/any/literal.rs | 34 +- .../Source/grit/any/map_accessor_subject.rs | 20 +- .../Source/grit/any/map_element.rs | 20 +- .../Source/grit/any/map_key.rs | 20 +- .../Source/grit/any/maybe_curly_pattern.rs | 20 +- .../Source/grit/any/maybe_named_arg.rs | 22 +- .../Source/grit/any/mod.rs | 3 +- .../Source/grit/any/pattern.rs | 94 +- .../Source/grit/any/predicate.rs | 58 +- .../grit/any/predicate_match_subject.rs | 20 +- .../Source/grit/any/regex.rs | 20 +- .../Source/grit/any/version.rs | 20 +- .../Source/grit/auxiliary/annotation.rs | 9 +- .../Source/grit/auxiliary/bubble.rs | 23 +- .../Source/grit/auxiliary/bubble_scope.rs | 22 +- .../Source/grit/auxiliary/dot.rs | 9 +- .../Source/grit/auxiliary/dotdotdot.rs | 9 +- .../Source/grit/auxiliary/every.rs | 14 +- .../Source/grit/auxiliary/files.rs | 35 +- .../grit/auxiliary/language_declaration.rs | 37 +- .../Source/grit/auxiliary/language_flavor.rs | 22 +- .../grit/auxiliary/language_flavor_kind.rs | 11 +- .../Source/grit/auxiliary/language_name.rs | 9 +- .../auxiliary/language_specific_snippet.rs | 22 +- .../Source/grit/auxiliary/like.rs | 56 +- .../Source/grit/auxiliary/like_threshold.rs | 22 +- .../Source/grit/auxiliary/list.rs | 44 +- .../Source/grit/auxiliary/list_accessor.rs | 38 +- .../Source/grit/auxiliary/map.rs | 35 +- .../Source/grit/auxiliary/map_accessor.rs | 15 +- .../Source/grit/auxiliary/map_element.rs | 25 +- .../Source/grit/auxiliary/mod.rs | 3 +- .../Source/grit/auxiliary/name.rs | 9 +- .../Source/grit/auxiliary/named_arg.rs | 24 +- .../Source/grit/auxiliary/node_like.rs | 33 +- .../Source/grit/auxiliary/not.rs | 9 +- .../Source/grit/auxiliary/rewrite.rs | 24 +- .../Source/grit/auxiliary/root.rs | 39 +- .../Source/grit/auxiliary/sequential.rs | 40 +- .../Source/grit/auxiliary/some.rs | 14 +- .../Source/grit/auxiliary/underscore.rs | 9 +- .../Source/grit/auxiliary/variable.rs | 9 +- .../Source/grit/auxiliary/version.rs | 38 +- .../Source/grit/auxiliary/within.rs | 14 +- .../Source/grit/bogus/bogus.rs | 3 +- .../Source/grit/bogus/bogus_container.rs | 3 +- .../Source/grit/bogus/bogus_definition.rs | 3 +- .../grit/bogus/bogus_language_declaration.rs | 3 +- .../grit/bogus/bogus_language_flavor_kind.rs | 3 +- .../Source/grit/bogus/bogus_literal.rs | 3 +- .../Source/grit/bogus/bogus_map_element.rs | 3 +- .../Source/grit/bogus/bogus_named_arg.rs | 3 +- .../Source/grit/bogus/bogus_pattern.rs | 3 +- .../Source/grit/bogus/bogus_predicate.rs | 3 +- .../Source/grit/bogus/bogus_version.rs | 3 +- .../Source/grit/bogus/mod.rs | 3 +- .../grit/declarations/function_definition.rs | 49 +- .../Source/grit/declarations/mod.rs | 3 +- .../Source/grit/lists/definition_list.rs | 24 +- .../Source/grit/lists/language_flavor_list.rs | 21 +- .../Source/grit/lists/list_pattern_list.rs | 37 +- .../Source/grit/lists/map_element_list.rs | 18 +- .../Source/grit/lists/mod.rs | 3 +- .../Source/grit/lists/named_arg_list.rs | 18 +- .../Source/grit/lists/pattern_list.rs | 18 +- .../Source/grit/lists/predicate_list.rs | 18 +- .../Source/grit/lists/variable_list.rs | 18 +- .../biome_grit_formatter/Source/grit/mod.rs | 3 +- .../Source/grit/patterns/add_operation.rs | 24 +- .../grit/patterns/assignment_as_pattern.rs | 28 +- .../Source/grit/patterns/bracketed_pattern.rs | 22 +- .../Source/grit/patterns/curly_pattern.rs | 35 +- .../Source/grit/patterns/div_operation.rs | 24 +- .../Source/grit/patterns/mod.rs | 3 +- .../Source/grit/patterns/mod_operation.rs | 24 +- .../Source/grit/patterns/mul_operation.rs | 24 +- .../grit/patterns/pattern_accumulate.rs | 24 +- .../Source/grit/patterns/pattern_after.rs | 14 +- .../Source/grit/patterns/pattern_and.rs | 39 +- .../Source/grit/patterns/pattern_any.rs | 37 +- .../Source/grit/patterns/pattern_arg_list.rs | 9 +- .../Source/grit/patterns/pattern_as.rs | 24 +- .../Source/grit/patterns/pattern_before.rs | 14 +- .../Source/grit/patterns/pattern_contains.rs | 23 +- .../patterns/pattern_contains_until_clause.rs | 19 +- .../grit/patterns/pattern_definition.rs | 65 +- .../grit/patterns/pattern_definition_body.rs | 38 +- .../grit/patterns/pattern_else_clause.rs | 14 +- .../Source/grit/patterns/pattern_if_else.rs | 53 +- .../Source/grit/patterns/pattern_includes.rs | 14 +- .../Source/grit/patterns/pattern_limit.rs | 24 +- .../Source/grit/patterns/pattern_maybe.rs | 14 +- .../Source/grit/patterns/pattern_not.rs | 11 +- .../Source/grit/patterns/pattern_or.rs | 37 +- .../Source/grit/patterns/pattern_or_else.rs | 37 +- .../Source/grit/patterns/pattern_where.rs | 35 +- .../Source/grit/patterns/regex_pattern.rs | 11 +- .../grit/patterns/regex_pattern_variables.rs | 31 +- .../Source/grit/patterns/sub_operation.rs | 24 +- .../grit/predicates/bracketed_predicate.rs | 23 +- .../grit/predicates/curly_predicate_list.rs | 23 +- .../Source/grit/predicates/mod.rs | 3 +- .../grit/predicates/predicate_accumulate.rs | 28 +- .../Source/grit/predicates/predicate_and.rs | 37 +- .../Source/grit/predicates/predicate_any.rs | 37 +- .../grit/predicates/predicate_assignment.rs | 28 +- .../Source/grit/predicates/predicate_call.rs | 33 +- .../Source/grit/predicates/predicate_curly.rs | 37 +- .../grit/predicates/predicate_definition.rs | 53 +- .../grit/predicates/predicate_else_clause.rs | 18 +- .../Source/grit/predicates/predicate_equal.rs | 24 +- .../grit/predicates/predicate_greater.rs | 24 +- .../predicates/predicate_greater_equal.rs | 42 +- .../grit/predicates/predicate_if_else.rs | 53 +- .../Source/grit/predicates/predicate_less.rs | 24 +- .../grit/predicates/predicate_less_equal.rs | 27 +- .../Source/grit/predicates/predicate_match.rs | 24 +- .../Source/grit/predicates/predicate_maybe.rs | 17 +- .../Source/grit/predicates/predicate_not.rs | 11 +- .../grit/predicates/predicate_not_equal.rs | 24 +- .../Source/grit/predicates/predicate_or.rs | 37 +- .../grit/predicates/predicate_return.rs | 14 +- .../grit/predicates/predicate_rewrite.rs | 39 +- .../grit/value/backtick_snippet_literal.rs | 19 +- .../Source/grit/value/boolean_literal.rs | 11 +- .../Source/grit/value/code_snippet.rs | 11 +- .../Source/grit/value/double_literal.rs | 11 +- .../Source/grit/value/int_literal.rs | 11 +- .../Source/grit/value/mod.rs | 3 +- .../Source/grit/value/negative_int_literal.rs | 11 +- .../value/raw_backtick_snippet_literal.rs | 19 +- .../Source/grit/value/regex_literal.rs | 11 +- .../grit/value/snippet_regex_literal.rs | 15 +- .../Source/grit/value/string_literal.rs | 11 +- .../Source/grit/value/undefined_literal.rs | 11 +- crates/biome_grit_parser/Source/lexer/mod.rs | 2098 +- .../biome_grit_parser/Source/lexer/tests.rs | 652 +- .../Source/parser/definitions.rs | 239 +- .../Source/parser/literals.rs | 431 +- crates/biome_grit_parser/Source/parser/mod.rs | 468 +- .../Source/parser/parse_error.rs | 98 +- .../Source/parser/patterns.rs | 1401 +- .../Source/parser/predicates.rs | 611 +- .../Source/grit_target_language.rs | 3 +- .../js_target_language.rs | 344 +- .../js_target_language/constants.rs | 89 +- .../pattern_compiler/accumulate_compiler.rs | 90 +- .../Source/pattern_compiler/add_compiler.rs | 21 +- .../Source/pattern_compiler/after_compiler.rs | 19 +- .../Source/pattern_compiler/and_compiler.rs | 100 +- .../Source/pattern_compiler/any_compiler.rs | 72 +- .../Source/pattern_compiler/as_compiler.rs | 140 +- .../pattern_compiler/assignment_compiler.rs | 82 +- .../Source/pattern_compiler/auto_wrap.rs | 910 +- .../pattern_compiler/before_compiler.rs | 19 +- .../pattern_compiler/bubble_compiler.rs | 95 +- .../Source/pattern_compiler/call_compiler.rs | 430 +- .../pattern_compiler/compilation_context.rs | 154 +- .../pattern_compiler/container_compiler.rs | 53 +- .../pattern_compiler/contains_compiler.rs | 27 +- .../pattern_compiler/divide_compiler.rs | 21 +- .../Source/pattern_compiler/equal_compiler.rs | 28 +- .../Source/pattern_compiler/every_compiler.rs | 19 +- .../function_definition_compiler.rs | 82 +- .../Source/pattern_compiler/if_compiler.rs | 60 +- .../pattern_compiler/includes_compiler.rs | 19 +- .../Source/pattern_compiler/like_compiler.rs | 29 +- .../Source/pattern_compiler/limit_compiler.rs | 31 +- .../Source/pattern_compiler/list_compiler.rs | 67 +- .../pattern_compiler/list_index_compiler.rs | 74 +- .../pattern_compiler/literal_compiler.rs | 262 +- .../Source/pattern_compiler/log_compiler.rs | 72 +- .../pattern_compiler/map_accessor_compiler.rs | 57 +- .../Source/pattern_compiler/map_compiler.rs | 74 +- .../Source/pattern_compiler/match_compiler.rs | 54 +- .../Source/pattern_compiler/maybe_compiler.rs | 40 +- .../pattern_compiler/modulo_compiler.rs | 21 +- .../pattern_compiler/multiply_compiler.rs | 21 +- .../pattern_compiler/node_like_compiler.rs | 179 +- .../Source/pattern_compiler/not_compiler.rs | 100 +- .../Source/pattern_compiler/or_compiler.rs | 72 +- .../pattern_definition_compiler.rs | 70 +- .../predicate_call_compiler.rs | 74 +- .../pattern_compiler/predicate_compiler.rs | 168 +- .../predicate_definition_compiler.rs | 82 +- .../predicate_return_compiler.rs | 19 +- .../Source/pattern_compiler/regex_compiler.rs | 139 +- .../pattern_compiler/rewrite_compiler.rs | 136 +- .../pattern_compiler/sequential_compiler.rs | 55 +- .../pattern_compiler/snippet_compiler.rs | 991 +- .../Source/pattern_compiler/some_compiler.rs | 19 +- .../Source/pattern_compiler/step_compiler.rs | 194 +- .../pattern_compiler/subtract_compiler.rs | 21 +- .../pattern_compiler/variable_compiler.rs | 211 +- .../Source/pattern_compiler/where_compiler.rs | 28 +- .../pattern_compiler/within_compiler.rs | 19 +- .../Source/generated/kind.rs | 732 +- .../Source/generated/macros.rs | 977 +- .../Source/generated/nodes.rs | 19650 ++--- .../Source/generated/nodes_mut.rs | 3134 +- .../Source/generated/node_factory.rs | 489 +- .../Source/generated/syntax_factory.rs | 866 +- .../Source/html/any/attribute.rs | 20 +- .../Source/html/any/element.rs | 26 +- .../Source/html/any/mod.rs | 3 +- .../Source/html/auxiliary/attribute.rs | 11 +- .../auxiliary/attribute_initializer_clause.rs | 19 +- .../Source/html/auxiliary/closing_element.rs | 35 +- .../Source/html/auxiliary/comment.rs | 9 +- .../Source/html/auxiliary/content.rs | 9 +- .../Source/html/auxiliary/directive.rs | 94 +- .../Source/html/auxiliary/element.rs | 51 +- .../Source/html/auxiliary/mod.rs | 3 +- .../Source/html/auxiliary/name.rs | 11 +- .../Source/html/auxiliary/opening_element.rs | 27 +- .../Source/html/auxiliary/root.rs | 31 +- .../html/auxiliary/self_closing_element.rs | 47 +- .../Source/html/auxiliary/string.rs | 74 +- .../Source/html/bogus/bogus.rs | 3 +- .../Source/html/bogus/bogus_attribute.rs | 3 +- .../Source/html/bogus/bogus_element.rs | 3 +- .../Source/html/bogus/mod.rs | 3 +- .../Source/html/lists/attribute_list.rs | 35 +- .../Source/html/lists/element_list.rs | 1267 +- .../Source/html/lists/mod.rs | 3 +- .../biome_html_formatter/Source/html/mod.rs | 3 +- .../Source/utils/children.rs | 663 +- crates/biome_html_parser/Source/lexer/mod.rs | 1150 +- .../biome_html_parser/Source/lexer/tests.rs | 355 +- crates/biome_html_parser/Source/syntax/mod.rs | 444 +- .../Source/syntax/parse_error.rs | 39 +- .../Source/generated/kind.rs | 196 +- .../Source/generated/macros.rs | 177 +- .../Source/generated/nodes.rs | 2539 +- .../Source/generated/nodes_mut.rs | 453 +- .../biome_js_analyze/Source/assists/source.rs | 14 +- .../Source/assists/source/organize_imports.rs | 185 +- .../assists/source/organize_imports/legacy.rs | 1150 +- .../assists/source/organize_imports/util.rs | 623 +- .../Source/assists/source/sort_jsx_props.rs | 216 +- .../assists/source/use_sorted_attributes.rs | 216 +- .../Source/globals/javascript/language.rs | 760 +- .../Source/globals/javascript/mod.rs | 4 +- .../Source/globals/javascript/node.rs | 306 +- .../Source/globals/javascript/web.rs | 2984 +- crates/biome_js_analyze/Source/globals/mod.rs | 20 +- .../Source/globals/module/node.rs | 324 +- .../Source/globals/typescript/language.rs | 3608 +- .../Source/globals/typescript/mod.rs | 4 +- .../Source/globals/typescript/node.rs | 96 +- .../Source/globals/typescript/web.rs | 4042 +- crates/biome_js_analyze/Source/lint/a11y.rs | 76 +- .../Source/lint/a11y/no_access_key.rs | 217 +- .../lint/a11y/no_aria_hidden_on_focusable.rs | 225 +- .../lint/a11y/no_aria_unsupported_elements.rs | 213 +- .../Source/lint/a11y/no_autofocus.rs | 425 +- .../Source/lint/a11y/no_blank_target.rs | 419 +- .../lint/a11y/no_distracting_elements.rs | 179 +- .../Source/lint/a11y/no_header_scope.rs | 152 +- ...eractive_element_to_noninteractive_role.rs | 267 +- .../lint/a11y/no_label_without_control.rs | 587 +- ...interactive_element_to_interactive_role.rs | 207 +- .../lint/a11y/no_noninteractive_tabindex.rs | 269 +- .../Source/lint/a11y/no_positive_tabindex.rs | 386 +- .../Source/lint/a11y/no_redundant_alt.rs | 270 +- .../Source/lint/a11y/no_redundant_roles.rs | 179 +- .../Source/lint/a11y/no_svg_without_title.rs | 414 +- .../Source/lint/a11y/use_alt_text.rs | 353 +- .../Source/lint/a11y/use_anchor_content.rs | 255 +- ...use_aria_activedescendant_with_tabindex.rs | 257 +- .../lint/a11y/use_aria_props_for_role.rs | 208 +- .../Source/lint/a11y/use_button_type.rs | 381 +- .../lint/a11y/use_focusable_interactive.rs | 144 +- .../Source/lint/a11y/use_heading_content.rs | 249 +- .../Source/lint/a11y/use_html_lang.rs | 172 +- .../Source/lint/a11y/use_iframe_title.rs | 184 +- .../lint/a11y/use_key_with_click_events.rs | 223 +- .../lint/a11y/use_key_with_mouse_events.rs | 227 +- .../Source/lint/a11y/use_media_caption.rs | 228 +- .../Source/lint/a11y/use_semantic_elements.rs | 160 +- .../Source/lint/a11y/use_valid_anchor.rs | 367 +- .../Source/lint/a11y/use_valid_aria_props.rs | 195 +- .../Source/lint/a11y/use_valid_aria_role.rs | 220 +- .../Source/lint/a11y/use_valid_aria_values.rs | 175 +- .../Source/lint/a11y/use_valid_lang.rs | 267 +- .../Source/lint/complexity.rs | 74 +- .../Source/lint/complexity/no_banned_types.rs | 540 +- .../complexity/no_empty_type_parameters.rs | 113 +- .../no_excessive_cognitive_complexity.rs | 614 +- .../no_excessive_nested_test_suites.rs | 279 +- .../lint/complexity/no_extra_boolean_cast.rs | 436 +- .../Source/lint/complexity/no_for_each.rs | 349 +- ...e_spaces_in_regular_expression_literals.rs | 460 +- .../lint/complexity/no_static_only_class.rs | 316 +- .../lint/complexity/no_this_in_static.rs | 365 +- .../lint/complexity/no_useless_catch.rs | 262 +- .../lint/complexity/no_useless_constructor.rs | 637 +- .../complexity/no_useless_empty_export.rs | 221 +- .../lint/complexity/no_useless_fragments.rs | 925 +- .../lint/complexity/no_useless_label.rs | 259 +- .../no_useless_lone_block_statements.rs | 282 +- .../lint/complexity/no_useless_rename.rs | 351 +- .../complexity/no_useless_string_concat.rs | 763 +- .../lint/complexity/no_useless_switch_case.rs | 331 +- .../lint/complexity/no_useless_ternary.rs | 506 +- .../lint/complexity/no_useless_this_alias.rs | 371 +- .../complexity/no_useless_type_constraint.rs | 298 +- .../no_useless_undefined_initialization.rs | 395 +- .../Source/lint/complexity/no_void.rs | 78 +- .../Source/lint/complexity/no_with.rs | 101 +- .../lint/complexity/use_arrow_function.rs | 668 +- .../Source/lint/complexity/use_date_now.rs | 493 +- .../Source/lint/complexity/use_flat_map.rs | 270 +- .../lint/complexity/use_literal_keys.rs | 430 +- .../lint/complexity/use_optional_chain.rs | 1753 +- .../lint/complexity/use_regex_literals.rs | 403 +- .../lint/complexity/use_simple_number_keys.rs | 712 +- .../use_simplified_logic_expression.rs | 448 +- .../Source/lint/correctness.rs | 100 +- .../lint/correctness/no_children_prop.rs | 155 +- .../lint/correctness/no_const_assign.rs | 205 +- .../lint/correctness/no_constant_condition.rs | 1086 +- .../no_constant_math_min_max_clamp.rs | 336 +- .../lint/correctness/no_constructor_return.rs | 173 +- .../no_empty_character_class_in_regex.rs | 212 +- .../lint/correctness/no_empty_pattern.rs | 160 +- .../lint/correctness/no_flat_map_identity.rs | 362 +- .../correctness/no_global_object_calls.rs | 306 +- .../lint/correctness/no_inner_declarations.rs | 372 +- .../no_invalid_builtin_instantiation.rs | 436 +- .../no_invalid_constructor_super.rs | 480 +- .../correctness/no_invalid_new_builtin.rs | 189 +- .../no_invalid_use_before_declaration.rs | 396 +- .../Source/lint/correctness/no_new_symbol.rs | 189 +- .../lint/correctness/no_nodejs_modules.rs | 181 +- .../correctness/no_nonoctal_decimal_escape.rs | 701 +- .../lint/correctness/no_precision_loss.rs | 364 +- .../correctness/no_render_return_value.rs | 109 +- .../Source/lint/correctness/no_self_assign.rs | 1489 +- .../lint/correctness/no_setter_return.rs | 203 +- .../correctness/no_string_case_mismatch.rs | 501 +- .../correctness/no_switch_declarations.rs | 265 +- .../correctness/no_undeclared_dependencies.rs | 623 +- .../correctness/no_undeclared_variables.rs | 254 +- .../correctness/no_unnecessary_continue.rs | 352 +- .../Source/lint/correctness/no_unreachable.rs | 1731 +- .../lint/correctness/no_unreachable_super.rs | 476 +- .../lint/correctness/no_unsafe_finally.rs | 431 +- .../no_unsafe_optional_chaining.rs | 754 +- .../no_unused_function_parameters.rs | 326 +- .../lint/correctness/no_unused_imports.rs | 925 +- .../lint/correctness/no_unused_labels.rs | 402 +- .../no_unused_private_class_members.rs | 688 +- .../lint/correctness/no_unused_variables.rs | 683 +- .../no_void_elements_with_children.rs | 700 +- .../lint/correctness/no_void_type_return.rs | 292 +- .../lint/correctness/use_array_literals.rs | 311 +- .../use_exhaustive_dependencies.rs | 1851 +- .../lint/correctness/use_hook_at_top_level.rs | 962 +- .../lint/correctness/use_import_extensions.rs | 510 +- .../Source/lint/correctness/use_is_nan.rs | 566 +- .../correctness/use_jsx_key_in_iterable.rs | 753 +- .../correctness/use_valid_for_direction.rs | 301 +- .../Source/lint/correctness/use_yield.rs | 254 +- .../biome_js_analyze/Source/lint/nursery.rs | 92 +- .../Source/lint/nursery/no_common_js.rs | 248 +- .../Source/lint/nursery/no_document_cookie.rs | 268 +- .../nursery/no_document_import_in_page.rs | 133 +- .../lint/nursery/no_duplicate_else_if.rs | 395 +- .../no_dynamic_namespace_import_access.rs | 183 +- .../Source/lint/nursery/no_enum.rs | 137 +- .../lint/nursery/no_exported_imports.rs | 119 +- .../nursery/no_global_dirname_filename.rs | 497 +- .../Source/lint/nursery/no_head_element.rs | 143 +- .../nursery/no_head_import_in_document.rs | 182 +- .../Source/lint/nursery/no_img_element.rs | 179 +- .../lint/nursery/no_irregular_whitespace.rs | 216 +- .../Source/lint/nursery/no_nested_ternary.rs | 130 +- .../Source/lint/nursery/no_octal_escape.rs | 170 +- .../Source/lint/nursery/no_process_env.rs | 123 +- .../lint/nursery/no_restricted_imports.rs | 2129 +- .../lint/nursery/no_restricted_types.rs | 267 +- .../Source/lint/nursery/no_secrets.rs | 822 +- .../nursery/no_static_element_interactions.rs | 274 +- .../Source/lint/nursery/no_substr.rs | 357 +- .../nursery/no_template_curly_in_string.rs | 170 +- .../nursery/no_useless_escape_in_regex.rs | 432 +- .../lint/nursery/no_useless_string_raw.rs | 149 +- .../lint/nursery/no_useless_undefined.rs | 595 +- .../use_adjacent_overload_signatures.rs | 638 +- .../use_aria_props_supported_by_role.rs | 223 +- .../Source/lint/nursery/use_at_index.rs | 1340 +- .../Source/lint/nursery/use_collapsed_if.rs | 344 +- .../use_component_export_only_modules.rs | 607 +- .../nursery/use_consistent_curly_braces.rs | 668 +- .../use_consistent_member_accessibility.rs | 959 +- .../use_explicit_function_return_type.rs | 1073 +- .../Source/lint/nursery/use_explicit_type.rs | 865 +- .../Source/lint/nursery/use_exports_last.rs | 130 +- .../lint/nursery/use_google_font_display.rs | 228 +- .../nursery/use_google_font_preconnect.rs | 239 +- .../Source/lint/nursery/use_guard_for_in.rs | 242 +- .../lint/nursery/use_import_restrictions.rs | 362 +- .../Source/lint/nursery/use_sorted_classes.rs | 518 +- .../any_class_string_like.rs | 228 +- .../nursery/use_sorted_classes/class_info.rs | 1184 +- .../nursery/use_sorted_classes/class_lexer.rs | 746 +- .../nursery/use_sorted_classes/options.rs | 165 +- .../nursery/use_sorted_classes/presets.rs | 41 +- .../lint/nursery/use_sorted_classes/sort.rs | 511 +- .../nursery/use_sorted_classes/sort_config.rs | 60 +- .../use_sorted_classes/tailwind_preset.rs | 1509 +- .../Source/lint/nursery/use_strict_mode.rs | 177 +- .../Source/lint/nursery/use_trim_start_end.rs | 550 +- .../lint/nursery/use_valid_autocomplete.rs | 360 +- .../Source/lint/performance.rs | 20 +- .../performance/no_accumulating_spread.rs | 228 +- .../Source/lint/performance/no_barrel_file.rs | 180 +- .../Source/lint/performance/no_delete.rs | 358 +- .../lint/performance/no_re_export_all.rs | 127 +- .../lint/performance/use_top_level_regex.rs | 175 +- .../biome_js_analyze/Source/lint/security.rs | 16 +- .../security/no_dangerously_set_inner_html.rs | 222 +- ...angerously_set_inner_html_with_children.rs | 325 +- .../Source/lint/security/no_global_eval.rs | 146 +- crates/biome_js_analyze/Source/lint/style.rs | 110 +- .../Source/lint/style/no_arguments.rs | 98 +- .../Source/lint/style/no_comma_operator.rs | 149 +- .../Source/lint/style/no_default_export.rs | 202 +- .../Source/lint/style/no_done_callback.rs | 258 +- .../Source/lint/style/no_implicit_boolean.rs | 262 +- .../Source/lint/style/no_inferrable_types.rs | 500 +- .../Source/lint/style/no_namespace.rs | 148 +- .../Source/lint/style/no_namespace_import.rs | 125 +- .../Source/lint/style/no_negation_else.rs | 294 +- .../lint/style/no_non_null_assertion.rs | 321 +- .../Source/lint/style/no_parameter_assign.rs | 211 +- .../lint/style/no_parameter_properties.rs | 100 +- .../lint/style/no_restricted_globals.rs | 245 +- .../Source/lint/style/no_shouty_constants.rs | 324 +- .../lint/style/no_unused_template_literal.rs | 275 +- .../Source/lint/style/no_useless_else.rs | 521 +- .../Source/lint/style/no_var.rs | 233 +- .../Source/lint/style/no_yoda_expression.rs | 674 +- .../lint/style/use_as_const_assertion.rs | 457 +- .../Source/lint/style/use_block_statements.rs | 713 +- .../lint/style/use_collapsed_else_if.rs | 317 +- .../lint/style/use_consistent_array_type.rs | 972 +- .../use_consistent_builtin_instantiation.rs | 393 +- .../Source/lint/style/use_const.rs | 889 +- .../lint/style/use_default_parameter_last.rs | 292 +- .../lint/style/use_default_switch_clause.rs | 146 +- .../lint/style/use_enum_initializers.rs | 461 +- .../lint/style/use_explicit_length_check.rs | 758 +- .../lint/style/use_exponentiation_operator.rs | 557 +- .../Source/lint/style/use_export_type.rs | 761 +- .../lint/style/use_filenaming_convention.rs | 913 +- .../Source/lint/style/use_for_of.rs | 660 +- .../Source/lint/style/use_fragment_syntax.rs | 244 +- .../Source/lint/style/use_import_type.rs | 1739 +- .../lint/style/use_literal_enum_members.rs | 448 +- .../lint/style/use_naming_convention.rs | 3522 +- .../lint/style/use_node_assert_strict.rs | 150 +- .../lint/style/use_nodejs_import_protocol.rs | 201 +- .../Source/lint/style/use_number_namespace.rs | 474 +- .../Source/lint/style/use_numeric_literals.rs | 399 +- .../lint/style/use_self_closing_elements.rs | 371 +- .../lint/style/use_shorthand_array_type.rs | 456 +- .../Source/lint/style/use_shorthand_assign.rs | 290 +- .../lint/style/use_shorthand_function_type.rs | 432 +- .../lint/style/use_single_case_statement.rs | 207 +- .../lint/style/use_single_var_declarator.rs | 451 +- .../Source/lint/style/use_template.rs | 596 +- .../Source/lint/style/use_throw_new_error.rs | 282 +- .../Source/lint/style/use_throw_only_error.rs | 216 +- .../Source/lint/style/use_while.rs | 179 +- .../Source/lint/suspicious.rs | 132 +- .../no_approximative_numeric_constant.rs | 304 +- .../lint/suspicious/no_array_index_key.rs | 572 +- .../suspicious/no_assign_in_expressions.rs | 183 +- .../suspicious/no_async_promise_executor.rs | 184 +- .../Source/lint/suspicious/no_catch_assign.rs | 184 +- .../Source/lint/suspicious/no_class_assign.rs | 199 +- .../Source/lint/suspicious/no_comment_text.rs | 321 +- .../lint/suspicious/no_compare_neg_zero.rs | 298 +- .../lint/suspicious/no_confusing_labels.rs | 206 +- .../lint/suspicious/no_confusing_void_type.rs | 225 +- .../Source/lint/suspicious/no_console.rs | 223 +- .../Source/lint/suspicious/no_console_log.rs | 167 +- .../Source/lint/suspicious/no_const_enum.rs | 141 +- .../no_control_characters_in_regex.rs | 480 +- .../Source/lint/suspicious/no_debugger.rs | 117 +- .../lint/suspicious/no_double_equals.rs | 328 +- .../lint/suspicious/no_duplicate_case.rs | 242 +- .../suspicious/no_duplicate_class_members.rs | 437 +- .../lint/suspicious/no_duplicate_jsx_props.rs | 141 +- .../suspicious/no_duplicate_object_keys.rs | 611 +- .../suspicious/no_duplicate_parameters.rs | 385 +- .../suspicious/no_duplicate_test_hooks.rs | 395 +- .../suspicious/no_empty_block_statements.rs | 241 +- .../lint/suspicious/no_empty_interface.rs | 249 +- .../lint/suspicious/no_evolving_types.rs | 233 +- .../Source/lint/suspicious/no_explicit_any.rs | 171 +- .../lint/suspicious/no_exports_in_test.rs | 383 +- .../suspicious/no_extra_non_null_assertion.rs | 288 +- .../no_fallthrough_switch_clause.rs | 590 +- .../lint/suspicious/no_focused_tests.rs | 325 +- .../lint/suspicious/no_function_assign.rs | 283 +- .../lint/suspicious/no_global_assign.rs | 155 +- .../lint/suspicious/no_global_is_finite.rs | 218 +- .../lint/suspicious/no_global_is_nan.rs | 220 +- .../lint/suspicious/no_implicit_any_let.rs | 137 +- .../lint/suspicious/no_import_assign.rs | 235 +- .../Source/lint/suspicious/no_label_var.rs | 131 +- .../no_misleading_character_class.rs | 1285 +- .../suspicious/no_misleading_instantiator.rs | 442 +- .../lint/suspicious/no_misplaced_assertion.rs | 467 +- .../no_misrefactored_shorthand_assign.rs | 244 +- .../lint/suspicious/no_prototype_builtins.rs | 528 +- .../suspicious/no_react_specific_props.rs | 194 +- .../Source/lint/suspicious/no_redeclare.rs | 353 +- .../suspicious/no_redundant_use_strict.rs | 241 +- .../Source/lint/suspicious/no_self_compare.rs | 114 +- .../suspicious/no_shadow_restricted_names.rs | 119 +- .../lint/suspicious/no_skipped_tests.rs | 254 +- .../Source/lint/suspicious/no_sparse_array.rs | 202 +- .../no_suspicious_semicolon_in_jsx.rs | 190 +- .../lint/suspicious/no_then_property.rs | 833 +- .../no_unsafe_declaration_merging.rs | 165 +- .../lint/suspicious/no_unsafe_negation.rs | 298 +- .../Source/lint/suspicious/use_await.rs | 260 +- .../use_default_switch_clause_last.rs | 185 +- .../lint/suspicious/use_error_message.rs | 258 +- .../lint/suspicious/use_getter_return.rs | 340 +- .../Source/lint/suspicious/use_is_array.rs | 189 +- .../lint/suspicious/use_namespace_keyword.rs | 133 +- .../use_number_to_fixed_digits_argument.rs | 233 +- .../lint/suspicious/use_valid_typeof.rs | 445 +- crates/biome_js_analyze/Source/react/hooks.rs | 913 +- .../biome_js_analyze/Source/services/aria.rs | 77 +- .../Source/services/control_flow.rs | 37 +- .../services/control_flow/nodes/block.rs | 82 +- .../services/control_flow/nodes/break_stmt.rs | 121 +- .../control_flow/nodes/continue_stmt.rs | 98 +- .../services/control_flow/nodes/do_while.rs | 124 +- .../services/control_flow/nodes/for_in.rs | 84 +- .../services/control_flow/nodes/for_of.rs | 84 +- .../services/control_flow/nodes/for_stmt.rs | 173 +- .../services/control_flow/nodes/if_stmt.rs | 159 +- .../control_flow/nodes/return_stmt.rs | 22 +- .../services/control_flow/nodes/statement.rs | 26 +- .../control_flow/nodes/switch_stmt.rs | 183 +- .../services/control_flow/nodes/throw_stmt.rs | 22 +- .../services/control_flow/nodes/try_catch.rs | 230 +- .../services/control_flow/nodes/variable.rs | 34 +- .../services/control_flow/nodes/while_stmt.rs | 127 +- .../Source/services/control_flow/visitor.rs | 272 +- .../Source/services/manifest.rs | 140 +- .../Source/services/semantic.rs | 205 +- .../Source/syntax/correctness.rs | 18 +- .../no_duplicate_private_class_members.rs | 144 +- .../no_initializer_with_definite.rs | 73 +- .../correctness/no_super_without_extends.rs | 114 +- .../no_type_only_import_attributes.rs | 304 +- crates/biome_js_analyze/Source/utils/batch.rs | 886 +- crates/biome_js_analyze/Source/utils/regex.rs | 321 +- .../biome_js_analyze/Source/utils/rename.rs | 702 +- .../Source/utils/restricted_glob.rs | 702 +- .../Source/utils/restricted_regex.rs | 540 +- crates/biome_js_analyze/Source/utils/tests.rs | 288 +- .../Source/generated/node_factory.rs | 13171 ++- .../Source/generated/syntax_factory.rs | 20674 ++--- crates/biome_js_formatter/Source/comments.rs | 2 +- .../Source/context/trailing_commas.rs | 157 +- .../any/array_assignment_pattern_element.rs | 38 +- .../js/any/array_binding_pattern_element.rs | 30 +- .../Source/js/any/array_element.rs | 22 +- .../js/any/arrow_function_parameters.rs | 20 +- .../Source/js/any/assignment.rs | 34 +- .../Source/js/any/assignment_pattern.rs | 22 +- .../Source/js/any/binding.rs | 22 +- .../Source/js/any/binding_pattern.rs | 22 +- .../Source/js/any/call_argument.rs | 20 +- .../biome_js_formatter/Source/js/any/class.rs | 22 +- .../Source/js/any/class_member.rs | 52 +- .../Source/js/any/class_member_name.rs | 24 +- .../Source/js/any/combined_specifier.rs | 20 +- .../Source/js/any/constructor_parameter.rs | 22 +- .../Source/js/any/declaration.rs | 38 +- .../Source/js/any/declaration_clause.rs | 38 +- .../Source/js/any/decorator.rs | 26 +- .../Source/js/any/export_clause.rs | 34 +- .../js/any/export_default_declaration.rs | 36 +- .../Source/js/any/export_named_specifier.rs | 24 +- .../Source/js/any/expression.rs | 92 +- .../Source/js/any/for_in_or_of_initializer.rs | 20 +- .../Source/js/any/for_initializer.rs | 20 +- .../Source/js/any/formal_parameter.rs | 22 +- .../Source/js/any/function.rs | 24 +- .../Source/js/any/function_body.rs | 20 +- .../Source/js/any/import_assertion_entry.rs | 20 +- .../Source/js/any/import_clause.rs | 26 +- .../Source/js/any/in_property.rs | 20 +- .../Source/js/any/literal_expression.rs | 28 +- .../Source/js/any/method_modifier.rs | 24 +- .../biome_js_formatter/Source/js/any/mod.rs | 3 +- .../Source/js/any/module_item.rs | 22 +- .../Source/js/any/module_source.rs | 20 +- .../biome_js_formatter/Source/js/any/name.rs | 22 +- .../Source/js/any/named_import_specifier.rs | 26 +- .../any/object_assignment_pattern_member.rs | 44 +- .../js/any/object_binding_pattern_member.rs | 38 +- .../Source/js/any/object_member.rs | 30 +- .../Source/js/any/object_member_name.rs | 22 +- .../Source/js/any/parameter.rs | 22 +- .../Source/js/any/property_modifier.rs | 28 +- .../biome_js_formatter/Source/js/any/root.rs | 24 +- .../Source/js/any/statement.rs | 82 +- .../Source/js/any/switch_clause.rs | 20 +- .../Source/js/any/template_element.rs | 20 +- .../assignments/array_assignment_pattern.rs | 69 +- .../array_assignment_pattern_element.rs | 29 +- .../array_assignment_pattern_rest_element.rs | 30 +- .../assignments/computed_member_assignment.rs | 25 +- .../js/assignments/identifier_assignment.rs | 37 +- .../Source/js/assignments/mod.rs | 3 +- .../assignments/object_assignment_pattern.rs | 40 +- .../object_assignment_pattern_property.rs | 18 +- .../object_assignment_pattern_rest.rs | 24 +- ...t_assignment_pattern_shorthand_property.rs | 36 +- .../assignments/parenthesized_assignment.rs | 31 +- .../assignments/static_member_assignment.rs | 16 +- .../Source/js/auxiliary/accessor_modifier.rs | 11 +- .../Source/js/auxiliary/array_hole.rs | 8 +- .../Source/js/auxiliary/case_clause.rs | 139 +- .../Source/js/auxiliary/catch_clause.rs | 26 +- .../Source/js/auxiliary/decorator.rs | 14 +- .../Source/js/auxiliary/default_clause.rs | 93 +- .../Source/js/auxiliary/directive.rs | 32 +- .../Source/js/auxiliary/else_clause.rs | 41 +- .../Source/js/auxiliary/expression_snipped.rs | 18 +- .../Source/js/auxiliary/finally_clause.rs | 18 +- .../Source/js/auxiliary/function_body.rs | 67 +- .../Source/js/auxiliary/initializer_clause.rs | 52 +- .../Source/js/auxiliary/label.rs | 11 +- .../Source/js/auxiliary/metavariable.rs | 9 +- .../Source/js/auxiliary/mod.rs | 3 +- .../Source/js/auxiliary/module.rs | 98 +- .../Source/js/auxiliary/name.rs | 15 +- .../Source/js/auxiliary/private_name.rs | 18 +- .../js/auxiliary/reference_identifier.rs | 15 +- .../Source/js/auxiliary/script.rs | 97 +- .../Source/js/auxiliary/spread.rs | 18 +- .../Source/js/auxiliary/static_modifier.rs | 13 +- .../js/auxiliary/template_chunk_element.rs | 67 +- .../Source/js/auxiliary/template_element.rs | 465 +- .../auxiliary/variable_declaration_clause.rs | 34 +- .../js/auxiliary/variable_declarator.rs | 10 +- .../js/bindings/array_binding_pattern.rs | 51 +- .../bindings/array_binding_pattern_element.rs | 31 +- .../array_binding_pattern_rest_element.rs | 26 +- .../js/bindings/constructor_parameters.rs | 27 +- .../Source/js/bindings/formal_parameter.rs | 81 +- .../Source/js/bindings/identifier_binding.rs | 15 +- .../Source/js/bindings/mod.rs | 3 +- .../js/bindings/object_binding_pattern.rs | 26 +- .../object_binding_pattern_property.rs | 57 +- .../bindings/object_binding_pattern_rest.rs | 22 +- ...ject_binding_pattern_shorthand_property.rs | 36 +- .../Source/js/bindings/parameters.rs | 703 +- .../Source/js/bindings/rest_parameter.rs | 37 +- .../Source/js/bogus/bogus.rs | 3 +- .../Source/js/bogus/bogus_assignment.rs | 3 +- .../Source/js/bogus/bogus_binding.rs | 3 +- .../Source/js/bogus/bogus_expression.rs | 3 +- .../js/bogus/bogus_import_assertion_entry.rs | 3 +- .../Source/js/bogus/bogus_member.rs | 3 +- .../js/bogus/bogus_named_import_specifier.rs | 3 +- .../Source/js/bogus/bogus_parameter.rs | 3 +- .../Source/js/bogus/bogus_statement.rs | 3 +- .../biome_js_formatter/Source/js/bogus/mod.rs | 3 +- .../js/classes/constructor_class_member.rs | 21 +- .../Source/js/classes/empty_class_member.rs | 13 +- .../Source/js/classes/extends_clause.rs | 108 +- .../Source/js/classes/getter_class_member.rs | 59 +- .../Source/js/classes/method_class_member.rs | 406 +- .../Source/js/classes/mod.rs | 3 +- .../js/classes/property_class_member.rs | 291 +- .../Source/js/classes/setter_class_member.rs | 63 +- ...tatic_initialization_block_class_member.rs | 69 +- .../js/declarations/catch_declaration.rs | 98 +- .../js/declarations/class_declaration.rs | 23 +- .../class_export_default_declaration.rs | 35 +- .../declarations/for_variable_declaration.rs | 33 +- .../js/declarations/function_declaration.rs | 583 +- .../function_export_default_declaration.rs | 21 +- .../Source/js/declarations/mod.rs | 3 +- .../js/declarations/variable_declaration.rs | 30 +- .../Source/js/expressions/array_expression.rs | 206 +- .../expressions/arrow_function_expression.rs | 1679 +- .../js/expressions/assignment_expression.rs | 60 +- .../Source/js/expressions/await_expression.rs | 139 +- .../expressions/bigint_literal_expression.rs | 65 +- .../js/expressions/binary_expression.rs | 106 +- .../expressions/boolean_literal_expression.rs | 30 +- .../Source/js/expressions/call_arguments.rs | 2469 +- .../Source/js/expressions/call_expression.rs | 123 +- .../Source/js/expressions/class_expression.rs | 84 +- .../expressions/computed_member_expression.rs | 125 +- .../js/expressions/conditional_expression.rs | 141 +- .../js/expressions/function_expression.rs | 60 +- .../js/expressions/identifier_expression.rs | 24 +- .../js/expressions/import_call_expression.rs | 27 +- .../js/expressions/import_meta_expression.rs | 35 +- .../Source/js/expressions/in_expression.rs | 126 +- .../js/expressions/instanceof_expression.rs | 103 +- .../js/expressions/logical_expression.rs | 102 +- .../Source/js/expressions/mod.rs | 3 +- .../Source/js/expressions/new_expression.rs | 50 +- .../js/expressions/new_target_expression.rs | 35 +- .../js/expressions/null_literal_expression.rs | 24 +- .../expressions/number_literal_expression.rs | 50 +- .../js/expressions/object_expression.rs | 82 +- .../expressions/parenthesized_expression.rs | 92 +- .../js/expressions/post_update_expression.rs | 61 +- .../js/expressions/pre_update_expression.rs | 65 +- .../expressions/regex_literal_expression.rs | 92 +- .../js/expressions/sequence_expression.rs | 155 +- .../expressions/static_member_expression.rs | 330 +- .../expressions/string_literal_expression.rs | 86 +- .../Source/js/expressions/super_expression.rs | 20 +- .../js/expressions/template_expression.rs | 148 +- .../Source/js/expressions/this_expression.rs | 20 +- .../Source/js/expressions/unary_expression.rs | 130 +- .../Source/js/expressions/yield_argument.rs | 16 +- .../Source/js/expressions/yield_expression.rs | 92 +- .../array_assignment_pattern_element_list.rs | 20 +- .../array_binding_pattern_element_list.rs | 20 +- .../Source/js/lists/array_element_list.rs | 270 +- .../Source/js/lists/call_argument_list.rs | 33 +- .../Source/js/lists/class_member_list.rs | 19 +- .../js/lists/constructor_modifier_list.rs | 13 +- .../js/lists/constructor_parameter_list.rs | 27 +- .../Source/js/lists/decorator_list.rs | 227 +- .../Source/js/lists/directive_list.rs | 83 +- .../lists/export_named_from_specifier_list.rs | 21 +- .../js/lists/export_named_specifier_list.rs | 21 +- .../js/lists/import_assertion_entry_list.rs | 21 +- .../Source/js/lists/method_modifier_list.rs | 12 +- .../biome_js_formatter/Source/js/lists/mod.rs | 3 +- .../Source/js/lists/module_item_list.rs | 36 +- .../js/lists/named_import_specifier_list.rs | 21 +- ...object_assignment_pattern_property_list.rs | 78 +- .../object_binding_pattern_property_list.rs | 73 +- .../Source/js/lists/object_member_list.rs | 28 +- .../Source/js/lists/parameter_list.rs | 236 +- .../Source/js/lists/property_modifier_list.rs | 12 +- .../Source/js/lists/statement_list.rs | 33 +- .../Source/js/lists/switch_case_list.rs | 19 +- .../Source/js/lists/template_element_list.rs | 376 +- .../js/lists/variable_declarator_list.rs | 94 +- crates/biome_js_formatter/Source/js/mod.rs | 3 +- .../js/module/default_import_specifier.rs | 13 +- .../Source/js/module/export.rs | 25 +- .../Source/js/module/export_as_clause.rs | 16 +- .../export_default_declaration_clause.rs | 28 +- .../export_default_expression_clause.rs | 44 +- .../Source/js/module/export_from_clause.rs | 65 +- .../Source/js/module/export_named_clause.rs | 99 +- .../js/module/export_named_from_clause.rs | 119 +- .../js/module/export_named_from_specifier.rs | 36 +- .../export_named_shorthand_specifier.rs | 27 +- .../js/module/export_named_specifier.rs | 37 +- .../Source/js/module/import.rs | 35 +- .../Source/js/module/import_assertion.rs | 89 +- .../js/module/import_assertion_entry.rs | 102 +- .../Source/js/module/import_bare_clause.rs | 23 +- .../js/module/import_combined_clause.rs | 61 +- .../Source/js/module/import_default_clause.rs | 59 +- .../Source/js/module/import_named_clause.rs | 184 +- .../js/module/import_namespace_clause.rs | 59 +- .../Source/js/module/literal_export_name.rs | 32 +- .../Source/js/module/mod.rs | 3 +- .../Source/js/module/module_source.rs | 31 +- .../js/module/named_import_specifier.rs | 36 +- .../js/module/named_import_specifiers.rs | 75 +- .../js/module/namespace_import_specifier.rs | 36 +- .../shorthand_named_import_specifier.rs | 32 +- .../Source/js/objects/computed_member_name.rs | 27 +- .../Source/js/objects/getter_object_member.rs | 53 +- .../Source/js/objects/literal_member_name.rs | 40 +- .../Source/js/objects/method_object_member.rs | 11 +- .../Source/js/objects/mod.rs | 3 +- .../js/objects/private_class_member_name.rs | 18 +- .../js/objects/property_object_member.rs | 11 +- .../Source/js/objects/setter_object_member.rs | 57 +- .../shorthand_property_object_member.rs | 23 +- .../Source/js/statements/block_statement.rs | 223 +- .../Source/js/statements/break_statement.rs | 27 +- .../js/statements/continue_statement.rs | 63 +- .../js/statements/debugger_statement.rs | 50 +- .../js/statements/do_while_statement.rs | 91 +- .../Source/js/statements/empty_statement.rs | 88 +- .../js/statements/expression_statement.rs | 269 +- .../Source/js/statements/for_in_statement.rs | 78 +- .../Source/js/statements/for_of_statement.rs | 84 +- .../Source/js/statements/for_statement.rs | 140 +- .../Source/js/statements/if_statement.rs | 159 +- .../Source/js/statements/labeled_statement.rs | 35 +- .../Source/js/statements/mod.rs | 3 +- .../Source/js/statements/return_statement.rs | 249 +- .../Source/js/statements/switch_statement.rs | 70 +- .../Source/js/statements/throw_statement.rs | 19 +- .../js/statements/try_finally_statement.rs | 27 +- .../Source/js/statements/try_statement.rs | 28 +- .../js/statements/variable_statement.rs | 27 +- .../Source/js/statements/while_statement.rs | 43 +- .../Source/js/statements/with_statement.rs | 41 +- .../Source/jsx/any/attribute.rs | 20 +- .../Source/jsx/any/attribute_name.rs | 20 +- .../Source/jsx/any/attribute_value.rs | 22 +- .../Source/jsx/any/child.rs | 28 +- .../Source/jsx/any/element_name.rs | 24 +- .../biome_js_formatter/Source/jsx/any/mod.rs | 3 +- .../biome_js_formatter/Source/jsx/any/name.rs | 20 +- .../Source/jsx/any/object_name.rs | 22 +- .../biome_js_formatter/Source/jsx/any/tag.rs | 22 +- .../Source/jsx/attribute/attribute.rs | 12 +- .../attribute/attribute_initializer_clause.rs | 20 +- .../attribute/expression_attribute_value.rs | 130 +- .../Source/jsx/attribute/mod.rs | 3 +- .../Source/jsx/attribute/spread_attribute.rs | 97 +- .../Source/jsx/auxiliary/expression_child.rs | 142 +- .../Source/jsx/auxiliary/mod.rs | 3 +- .../Source/jsx/auxiliary/name.rs | 12 +- .../Source/jsx/auxiliary/namespace_name.rs | 16 +- .../jsx/auxiliary/reference_identifier.rs | 10 +- .../Source/jsx/auxiliary/spread_child.rs | 98 +- .../Source/jsx/auxiliary/string.rs | 26 +- .../Source/jsx/auxiliary/text.rs | 14 +- .../Source/jsx/expressions/mod.rs | 3 +- .../Source/jsx/expressions/tag_expression.rs | 179 +- .../Source/jsx/lists/attribute_list.rs | 24 +- .../Source/jsx/lists/child_list.rs | 1409 +- .../Source/jsx/lists/mod.rs | 3 +- crates/biome_js_formatter/Source/jsx/mod.rs | 3 +- .../Source/jsx/objects/member_name.rs | 16 +- .../Source/jsx/objects/mod.rs | 3 +- .../Source/jsx/tag/closing_element.rs | 92 +- .../Source/jsx/tag/closing_fragment.rs | 94 +- .../Source/jsx/tag/element.rs | 431 +- .../Source/jsx/tag/fragment.rs | 74 +- .../biome_js_formatter/Source/jsx/tag/mod.rs | 3 +- .../Source/jsx/tag/opening_element.rs | 486 +- .../Source/jsx/tag/opening_fragment.rs | 73 +- .../Source/jsx/tag/self_closing_element.rs | 103 +- .../Source/ts/any/enum_member_name.rs | 20 +- .../any/external_module_declaration_body.rs | 32 +- .../Source/ts/any/identifier_binding.rs | 20 +- .../Source/ts/any/index_signature_modifier.rs | 20 +- .../ts/any/method_signature_modifier.rs | 26 +- .../biome_js_formatter/Source/ts/any/mod.rs | 3 +- .../Source/ts/any/module_name.rs | 20 +- .../Source/ts/any/module_reference.rs | 20 +- .../biome_js_formatter/Source/ts/any/name.rs | 20 +- .../Source/ts/any/property_annotation.rs | 22 +- .../ts/any/property_parameter_modifier.rs | 22 +- .../ts/any/property_signature_annotation.rs | 28 +- .../ts/any/property_signature_modifier.rs | 32 +- .../Source/ts/any/return_type.rs | 22 +- .../Source/ts/any/template_element.rs | 20 +- .../Source/ts/any/ts_type.rs | 88 +- .../Source/ts/any/tuple_type_element.rs | 24 +- .../Source/ts/any/type_member.rs | 32 +- .../Source/ts/any/type_parameter_modifier.rs | 22 +- .../ts/any/type_predicate_parameter_name.rs | 20 +- .../Source/ts/any/variable_annotation.rs | 20 +- .../Source/ts/assignments/as_assignment.rs | 65 +- .../Source/ts/assignments/mod.rs | 3 +- .../non_null_assertion_assignment.rs | 37 +- .../ts/assignments/satisfies_assignment.rs | 56 +- .../assignments/type_assertion_assignment.rs | 79 +- .../Source/ts/auxiliary/abstract_modifier.rs | 15 +- .../ts/auxiliary/accessibility_modifier.rs | 15 +- .../Source/ts/auxiliary/asserts_condition.rs | 15 +- .../auxiliary/call_signature_type_member.rs | 47 +- .../Source/ts/auxiliary/const_modifier.rs | 11 +- .../construct_signature_type_member.rs | 58 +- .../Source/ts/auxiliary/declaration_module.rs | 110 +- .../Source/ts/auxiliary/declare_modifier.rs | 15 +- .../ts/auxiliary/default_type_clause.rs | 12 +- .../auxiliary/definite_property_annotation.rs | 26 +- .../auxiliary/definite_variable_annotation.rs | 26 +- .../empty_external_module_declaration_body.rs | 29 +- .../Source/ts/auxiliary/enum_member.rs | 19 +- .../ts/auxiliary/external_module_reference.rs | 41 +- .../auxiliary/getter_signature_type_member.rs | 57 +- .../Source/ts/auxiliary/implements_clause.rs | 33 +- .../Source/ts/auxiliary/in_modifier.rs | 11 +- .../auxiliary/index_signature_type_member.rs | 59 +- .../ts/auxiliary/mapped_type_as_clause.rs | 12 +- .../mapped_type_optional_modifier_clause.rs | 32 +- .../mapped_type_readonly_modifier_clause.rs | 32 +- .../auxiliary/method_signature_type_member.rs | 36 +- .../Source/ts/auxiliary/mod.rs | 3 +- .../Source/ts/auxiliary/module_block.rs | 42 +- .../ts/auxiliary/named_tuple_type_element.rs | 44 +- .../auxiliary/optional_property_annotation.rs | 27 +- .../auxiliary/optional_tuple_type_element.rs | 23 +- .../Source/ts/auxiliary/out_modifier.rs | 11 +- .../Source/ts/auxiliary/override_modifier.rs | 15 +- .../property_signature_type_member.rs | 53 +- .../ts/auxiliary/qualified_module_name.rs | 19 +- .../Source/ts/auxiliary/qualified_name.rs | 19 +- .../Source/ts/auxiliary/readonly_modifier.rs | 15 +- .../ts/auxiliary/rest_tuple_type_element.rs | 19 +- .../ts/auxiliary/return_type_annotation.rs | 15 +- .../auxiliary/setter_signature_type_member.rs | 61 +- .../ts/auxiliary/template_chunk_element.rs | 19 +- .../Source/ts/auxiliary/template_element.rs | 36 +- .../Source/ts/auxiliary/type_annotation.rs | 16 +- .../ts/auxiliary/type_constraint_clause.rs | 32 +- .../ts/auxiliary/type_parameter_name.rs | 12 +- .../Source/ts/bindings/identifier_binding.rs | 12 +- .../ts/bindings/index_signature_parameter.rs | 23 +- .../Source/ts/bindings/mod.rs | 3 +- .../Source/ts/bindings/property_parameter.rs | 39 +- .../Source/ts/bindings/this_parameter.rs | 15 +- .../Source/ts/bindings/type_parameter.rs | 47 +- .../Source/ts/bindings/type_parameters.rs | 68 +- .../Source/ts/bogus/bogus_type.rs | 3 +- .../biome_js_formatter/Source/ts/bogus/mod.rs | 3 +- .../constructor_signature_class_member.rs | 52 +- .../Source/ts/classes/extends_clause.rs | 25 +- .../classes/getter_signature_class_member.rs | 64 +- .../classes/index_signature_class_member.rs | 60 +- ...ialized_property_signature_class_member.rs | 47 +- .../classes/method_signature_class_member.rs | 45 +- .../Source/ts/classes/mod.rs | 3 +- .../property_signature_class_member.rs | 45 +- .../classes/setter_signature_class_member.rs | 67 +- .../declare_function_declaration.rs | 36 +- ...are_function_export_default_declaration.rs | 37 +- .../ts/declarations/enum_declaration.rs | 82 +- .../external_module_declaration.rs | 71 +- .../ts/declarations/global_declaration.rs | 13 +- .../declarations/import_equals_declaration.rs | 62 +- .../ts/declarations/interface_declaration.rs | 217 +- .../Source/ts/declarations/mod.rs | 3 +- .../ts/declarations/module_declaration.rs | 31 +- .../ts/declarations/type_alias_declaration.rs | 35 +- .../Source/ts/expressions/as_expression.rs | 179 +- .../ts/expressions/import_type_arguments.rs | 37 +- .../expressions/instantiation_expression.rs | 32 +- .../Source/ts/expressions/mod.rs | 3 +- .../non_null_assertion_expression.rs | 37 +- .../ts/expressions/satisfies_expression.rs | 169 +- .../Source/ts/expressions/type_arguments.rs | 141 +- .../expressions/type_assertion_expression.rs | 163 +- .../Source/ts/lists/enum_member_list.rs | 31 +- .../ts/lists/index_signature_modifier_list.rs | 17 +- .../lists/intersection_type_element_list.rs | 92 +- .../lists/method_signature_modifier_list.rs | 12 +- .../biome_js_formatter/Source/ts/lists/mod.rs | 3 +- .../lists/property_parameter_modifier_list.rs | 16 +- .../lists/property_signature_modifier_list.rs | 12 +- .../Source/ts/lists/template_element_list.rs | 12 +- .../ts/lists/tuple_type_element_list.rs | 26 +- .../Source/ts/lists/type_argument_list.rs | 21 +- .../Source/ts/lists/type_list.rs | 23 +- .../Source/ts/lists/type_member_list.rs | 116 +- .../Source/ts/lists/type_parameter_list.rs | 41 +- .../ts/lists/type_parameter_modifier_list.rs | 30 +- .../ts/lists/union_type_variant_list.rs | 459 +- crates/biome_js_formatter/Source/ts/mod.rs | 3 +- .../ts/module/export_as_namespace_clause.rs | 46 +- .../ts/module/export_assignment_clause.rs | 37 +- .../Source/ts/module/export_declare_clause.rs | 18 +- .../Source/ts/module/import_type.rs | 48 +- .../Source/ts/module/import_type_assertion.rs | 87 +- .../ts/module/import_type_assertion_block.rs | 28 +- .../Source/ts/module/import_type_qualifier.rs | 15 +- .../Source/ts/module/mod.rs | 3 +- .../ts/objects/literal_enum_member_name.rs | 33 +- .../Source/ts/objects/mod.rs | 3 +- .../Source/ts/statements/declare_statement.rs | 18 +- .../Source/ts/statements/mod.rs | 3 +- .../Source/ts/types/any_type.rs | 12 +- .../Source/ts/types/array_type.rs | 23 +- .../Source/ts/types/asserts_return_type.rs | 38 +- .../Source/ts/types/bigint_literal_type.rs | 51 +- .../Source/ts/types/bigint_type.rs | 12 +- .../Source/ts/types/boolean_literal_type.rs | 12 +- .../Source/ts/types/boolean_type.rs | 12 +- .../Source/ts/types/conditional_type.rs | 127 +- .../Source/ts/types/constructor_type.rs | 135 +- .../Source/ts/types/function_type.rs | 145 +- .../Source/ts/types/indexed_access_type.rs | 37 +- .../Source/ts/types/infer_type.rs | 123 +- .../Source/ts/types/intersection_type.rs | 73 +- .../Source/ts/types/mapped_type.rs | 183 +- .../biome_js_formatter/Source/ts/types/mod.rs | 3 +- .../Source/ts/types/never_type.rs | 12 +- .../Source/ts/types/non_primitive_type.rs | 12 +- .../Source/ts/types/null_literal_type.rs | 12 +- .../Source/ts/types/number_literal_type.rs | 21 +- .../Source/ts/types/number_type.rs | 12 +- .../Source/ts/types/object_type.rs | 19 +- .../Source/ts/types/parenthesized_type.rs | 22 +- .../Source/ts/types/predicate_return_type.rs | 28 +- .../Source/ts/types/reference_type.rs | 15 +- .../Source/ts/types/string_literal_type.rs | 28 +- .../Source/ts/types/string_type.rs | 12 +- .../Source/ts/types/symbol_type.rs | 12 +- .../Source/ts/types/template_literal_type.rs | 26 +- .../Source/ts/types/this_type.rs | 12 +- .../Source/ts/types/tuple_type.rs | 39 +- .../Source/ts/types/type_operator_type.rs | 47 +- .../Source/ts/types/typeof_type.rs | 78 +- .../Source/ts/types/undefined_type.rs | 12 +- .../Source/ts/types/union_type.rs | 361 +- .../Source/ts/types/unknown_type.rs | 12 +- .../Source/ts/types/void_type.rs | 12 +- .../biome_js_formatter/Source/utils/array.rs | 193 +- .../Source/utils/assignment_like.rs | 2744 +- .../Source/utils/conditional.rs | 1484 +- .../utils/format_binary_like_expression.rs | 1021 +- .../Source/utils/format_class.rs | 316 +- .../Source/utils/format_modifiers.rs | 221 +- .../utils/format_node_without_comments.rs | 364 +- .../Source/utils/function_body.rs | 96 +- crates/biome_js_formatter/Source/utils/jsx.rs | 1324 +- .../Source/utils/member_chain/chain_member.rs | 332 +- .../Source/utils/member_chain/groups.rs | 527 +- .../Source/utils/member_chain/mod.rs | 1073 +- .../utils/member_chain/simple_argument.rs | 701 +- crates/biome_js_formatter/Source/utils/mod.rs | 389 +- .../biome_js_formatter/Source/utils/object.rs | 96 +- .../Source/utils/object_like.rs | 120 +- .../Source/utils/object_pattern_like.rs | 410 +- .../Source/utils/quickcheck_utils.rs | 44 +- .../Source/utils/string_utils.rs | 1060 +- .../Source/utils/test_each_template.rs | 517 +- .../Source/utils/typescript.rs | 138 +- crates/biome_js_parser/Source/lexer/errors.rs | 6 +- crates/biome_js_parser/Source/lexer/mod.rs | 4494 +- crates/biome_js_parser/Source/lexer/tests.rs | 2259 +- .../Source/parser/rewrite_parser.rs | 257 +- .../parser/single_token_parse_recovery.rs | 121 +- .../Source/syntax/assignment.rs | 811 +- .../Source/syntax/auxiliary.rs | 313 +- .../biome_js_parser/Source/syntax/binding.rs | 537 +- crates/biome_js_parser/Source/syntax/class.rs | 4909 +- crates/biome_js_parser/Source/syntax/expr.rs | 3686 +- .../biome_js_parser/Source/syntax/function.rs | 2452 +- .../Source/syntax/js_parse_error.rs | 366 +- .../Source/syntax/jsx/jsx_parse_errors.rs | 36 +- .../biome_js_parser/Source/syntax/jsx/mod.rs | 979 +- .../Source/syntax/metavariable.rs | 30 +- .../biome_js_parser/Source/syntax/module.rs | 2431 +- .../biome_js_parser/Source/syntax/object.rs | 896 +- .../biome_js_parser/Source/syntax/pattern.rs | 553 +- .../biome_js_parser/Source/syntax/program.rs | 72 +- crates/biome_js_parser/Source/syntax/stmt.rs | 3120 +- .../Source/syntax/typescript.rs | 332 +- .../Source/syntax/typescript/statement.rs | 776 +- .../syntax/typescript/ts_parse_error.rs | 160 +- .../Source/syntax/typescript/types.rs | 2835 +- .../Source/semantic_model/binding.rs | 235 +- .../Source/semantic_model/builder.rs | 701 +- .../Source/semantic_model/closure.rs | 622 +- .../Source/semantic_model/globals.rs | 46 +- .../Source/semantic_model/import.rs | 98 +- .../Source/semantic_model/is_constant.rs | 75 +- .../Source/semantic_model/model.rs | 774 +- .../Source/semantic_model/reference.rs | 390 +- .../Source/semantic_model/scope.rs | 300 +- .../Source/semantic_model/tests.rs | 458 +- crates/biome_js_syntax/Source/export_ext.rs | 5 +- .../biome_js_syntax/Source/generated/kind.rs | 1634 +- .../Source/generated/macros.rs | 3026 +- .../biome_js_syntax/Source/generated/nodes.rs | 65877 +++++++--------- .../Source/generated/nodes_mut.rs | 11346 ++- .../Source/parentheses/assignment.rs | 187 +- .../Source/parentheses/expression.rs | 1670 +- .../biome_js_syntax/Source/parentheses/mod.rs | 73 +- .../Source/parentheses/tstype.rs | 355 +- .../Source/transformers/ts_enum.rs | 493 +- .../Source/assists/source.rs | 12 +- .../Source/assists/source/use_sorted_keys.rs | 194 +- .../Source/lint/suspicious.rs | 12 +- .../suspicious/no_duplicate_object_keys.rs | 181 +- .../Source/generated/node_factory.rs | 259 +- .../Source/generated/syntax_factory.rs | 520 +- .../Source/json/any/mod.rs | 3 +- .../Source/json/any/value.rs | 30 +- .../Source/json/auxiliary/member.rs | 31 +- .../Source/json/auxiliary/member_name.rs | 10 +- .../Source/json/auxiliary/mod.rs | 3 +- .../Source/json/auxiliary/root.rs | 47 +- .../Source/json/bogus/bogus.rs | 3 +- .../Source/json/bogus/bogus_value.rs | 3 +- .../Source/json/bogus/mod.rs | 3 +- .../Source/json/lists/array_element_list.rs | 157 +- .../Source/json/lists/member_list.rs | 27 +- .../Source/json/lists/mod.rs | 3 +- .../biome_json_formatter/Source/json/mod.rs | 3 +- .../Source/json/value/array_value.rs | 49 +- .../Source/json/value/boolean_value.rs | 9 +- .../Source/json/value/mod.rs | 3 +- .../Source/json/value/null_value.rs | 9 +- .../Source/json/value/number_value.rs | 9 +- .../Source/json/value/object_value.rs | 88 +- .../Source/json/value/string_value.rs | 10 +- crates/biome_json_parser/Source/lexer/mod.rs | 1829 +- .../biome_json_parser/Source/lexer/tests.rs | 587 +- .../Source/generated/kind.rs | 178 +- .../Source/generated/macros.rs | 142 +- .../Source/generated/nodes.rs | 1803 +- .../Source/generated/nodes_mut.rs | 177 +- .../biome_lsp/Source/converters/from_proto.rs | 48 +- .../biome_lsp/Source/converters/line_index.rs | 243 +- crates/biome_lsp/Source/converters/mod.rs | 288 +- .../biome_lsp/Source/converters/to_proto.rs | 54 +- crates/biome_lsp/Source/handlers/analysis.rs | 667 +- .../biome_lsp/Source/handlers/formatting.rs | 334 +- crates/biome_lsp/Source/handlers/rename.rs | 88 +- .../Source/handlers/text_document.rs | 120 +- .../biome_lsp/Source/requests/syntax_tree.rs | 19 +- .../Source/generated/node_factory.rs | 531 +- .../Source/generated/syntax_factory.rs | 970 +- .../biome_markdown_parser/Source/lexer/mod.rs | 707 +- .../Source/lexer/tests.rs | 135 +- .../Source/syntax/thematic_break_block.rs | 25 +- .../Source/generated/kind.rs | 254 +- .../Source/generated/macros.rs | 254 +- .../Source/generated/nodes.rs | 4101 +- .../Source/generated/nodes_mut.rs | 357 +- .../Source/analyzers/indent_size.rs | 104 +- .../Source/analyzers/nursery_rules.rs | 608 +- .../biome_migrate/Source/analyzers/schema.rs | 133 +- .../Source/analyzers/trailing_comma.rs | 104 +- .../biome_project/Source/license/generated.rs | 50 +- crates/biome_project/Source/license/mod.rs | 24 +- .../Source/node_js_project/mod.rs | 110 +- .../Source/node_js_project/package_json.rs | 263 +- .../Source/node_js_project/tsconfig_json.rs | 18 +- crates/biome_rowan/Source/ast/batch.rs | 1264 +- crates/biome_rowan/Source/ast/mod.rs | 2021 +- crates/biome_rowan/Source/ast/mutation.rs | 400 +- crates/biome_rowan/Source/cursor/element.rs | 237 +- crates/biome_rowan/Source/cursor/node.rs | 1650 +- crates/biome_rowan/Source/cursor/token.rs | 459 +- crates/biome_rowan/Source/cursor/trivia.rs | 265 +- crates/biome_rowan/Source/green/element.rs | 116 +- crates/biome_rowan/Source/green/node.rs | 800 +- crates/biome_rowan/Source/green/node_cache.rs | 863 +- crates/biome_rowan/Source/green/token.rs | 347 +- crates/biome_rowan/Source/green/trivia.rs | 277 +- crates/biome_rowan/Source/syntax/element.rs | 231 +- crates/biome_rowan/Source/syntax/node.rs | 1917 +- crates/biome_rowan/Source/syntax/rewriter.rs | 249 +- crates/biome_rowan/Source/syntax/token.rs | 1126 +- crates/biome_rowan/Source/syntax/trivia.rs | 1429 +- .../Source/syntax_factory/parsed_children.rs | 172 +- .../Source/syntax_factory/raw_syntax.rs | 273 +- .../biome_service/Source/documentation/mod.rs | 161 +- .../Source/file_handlers/astro.rs | 244 +- .../biome_service/Source/file_handlers/css.rs | 1204 +- .../Source/file_handlers/graphql.rs | 1112 +- .../Source/file_handlers/grit.rs | 411 +- .../Source/file_handlers/html.rs | 309 +- .../Source/file_handlers/javascript.rs | 1712 +- .../Source/file_handlers/json.rs | 1224 +- .../biome_service/Source/file_handlers/mod.rs | 2129 +- .../Source/file_handlers/svelte.rs | 258 +- .../biome_service/Source/file_handlers/vue.rs | 259 +- crates/biome_service/Source/matcher/mod.rs | 357 +- .../biome_service/Source/matcher/pattern.rs | 1856 +- .../biome_service/Source/workspace/client.rs | 430 +- .../biome_service/Source/workspace/server.rs | 1845 +- .../Source/generated/node_factory.rs | 418 +- .../Source/generated/syntax_factory.rs | 794 +- crates/biome_yaml_parser/Source/lexer/mod.rs | 706 +- .../biome_yaml_parser/Source/lexer/tests.rs | 266 +- .../Source/generated/kind.rs | 232 +- .../Source/generated/macros.rs | 206 +- .../Source/generated/nodes.rs | 2821 +- .../Source/generated/nodes_mut.rs | 279 +- xtask/coverage/Source/js/test262.rs | 369 +- xtask/coverage/Source/jsx/jsx_babel.rs | 174 +- xtask/coverage/Source/symbols/msts.rs | 531 +- xtask/coverage/Source/symbols/utils.rs | 70 +- xtask/coverage/Source/ts/ts_babel.rs | 222 +- xtask/coverage/Source/ts/ts_microsoft.rs | 440 +- xtask/rules_check/Source/lib.rs | 1 - 1935 files changed, 298798 insertions(+), 333564 deletions(-) diff --git a/crates/biome_analyze/Source/categories.rs b/crates/biome_analyze/Source/categories.rs index a722de224ca7..fc8f43a26b03 100644 --- a/crates/biome_analyze/Source/categories.rs +++ b/crates/biome_analyze/Source/categories.rs @@ -85,34 +85,20 @@ impl ActionCategory { }, ActionCategory::Refactor(RefactorKind::None) => Cow::Borrowed("refactor.biome"), - ActionCategory::Refactor(RefactorKind::Extract) => { - Cow::Borrowed("refactor.extract.biome") - }, + ActionCategory::Refactor(RefactorKind::Extract) => Cow::Borrowed("refactor.extract.biome"), - ActionCategory::Refactor(RefactorKind::Inline) => { - Cow::Borrowed("refactor.inline.biome") - }, + ActionCategory::Refactor(RefactorKind::Inline) => Cow::Borrowed("refactor.inline.biome"), - ActionCategory::Refactor(RefactorKind::Rewrite) => { - Cow::Borrowed("refactor.rewrite.biome") - }, + ActionCategory::Refactor(RefactorKind::Rewrite) => Cow::Borrowed("refactor.rewrite.biome"), - ActionCategory::Refactor(RefactorKind::Other(tag)) => { - Cow::Owned(format!("refactor.{tag}.biome")) - }, + ActionCategory::Refactor(RefactorKind::Other(tag)) => Cow::Owned(format!("refactor.{tag}.biome")), ActionCategory::Source(SourceActionKind::None) => Cow::Borrowed("source.biome"), - ActionCategory::Source(SourceActionKind::FixAll) => { - Cow::Borrowed("source.fixAll.biome") - }, + ActionCategory::Source(SourceActionKind::FixAll) => Cow::Borrowed("source.fixAll.biome"), - ActionCategory::Source(SourceActionKind::OrganizeImports) => { - Cow::Borrowed("source.organizeImports.biome") - }, + ActionCategory::Source(SourceActionKind::OrganizeImports) => Cow::Borrowed("source.organizeImports.biome"), - ActionCategory::Source(SourceActionKind::Other(tag)) => { - Cow::Owned(format!("source.{tag}.biome")) - }, + ActionCategory::Source(SourceActionKind::Other(tag)) => Cow::Owned(format!("source.{tag}.biome")), ActionCategory::Other(tag) => Cow::Owned(format!("{tag}.biome")), } @@ -218,9 +204,7 @@ impl RuleCategories { /// Checks whether the current categories contain a specific /// [RuleCategories] - pub fn contains(&self, other:impl Into) -> bool { - self.0.contains(other.into().0) - } + pub fn contains(&self, other:impl Into) -> bool { self.0.contains(other.into().0) } } impl Default for RuleCategories { @@ -237,9 +221,7 @@ impl From for RuleCategories { RuleCategory::Syntax => RuleCategories(BitFlags::from_flag(Categories::Syntax)), RuleCategory::Lint => RuleCategories(BitFlags::from_flag(Categories::Lint)), RuleCategory::Action => RuleCategories(BitFlags::from_flag(Categories::Action)), - RuleCategory::Transformation => { - RuleCategories(BitFlags::from_flag(Categories::Transformation)) - }, + RuleCategory::Transformation => RuleCategories(BitFlags::from_flag(Categories::Transformation)), } } } @@ -285,9 +267,7 @@ impl<'de> serde::Deserialize<'de> for RuleCategories { impl<'de> de::Visitor<'de> for Visitor { type Value = RuleCategories; - fn expecting(&self, formatter:&mut Formatter) -> fmt::Result { - write!(formatter, "RuleCategories") - } + fn expecting(&self, formatter:&mut Formatter) -> fmt::Result { write!(formatter, "RuleCategories") } fn visit_seq(self, mut seq:A) -> Result where diff --git a/crates/biome_analyze/Source/context.rs b/crates/biome_analyze/Source/context.rs index 07c85d67e4eb..7155071ab0ee 100644 --- a/crates/biome_analyze/Source/context.rs +++ b/crates/biome_analyze/Source/context.rs @@ -67,9 +67,7 @@ where pub fn group(&self) -> &'static str { ::NAME } /// Returns the category that belongs to the current rule - pub fn category(&self) -> RuleCategory { - <::Category as GroupCategory>::CATEGORY - } + pub fn category(&self) -> RuleCategory { <::Category as GroupCategory>::CATEGORY } /// Returns a clone of the AST root pub fn root(&self) -> RuleRoot { self.root.clone() } @@ -146,17 +144,13 @@ where pub fn options(&self) -> &R::Options { self.options } /// Returns the JSX runtime in use. - pub fn jsx_runtime(&self) -> JsxRuntime { - self.jsx_runtime.expect("jsx_runtime should be provided") - } + pub fn jsx_runtime(&self) -> JsxRuntime { self.jsx_runtime.expect("jsx_runtime should be provided") } /// Checks whether the provided text belongs to globals pub fn is_global(&self, text:&str) -> bool { self.globals.contains(&text) } /// Returns the source type of the current file - pub fn source_type(&self) -> &T { - self.bag.get_service::().expect("Source type is not registered") - } + pub fn source_type(&self) -> &T { self.bag.get_service::().expect("Source type is not registered") } /// The file path of the current file pub fn file_path(&self) -> &Path { self.file_path } diff --git a/crates/biome_analyze/Source/diagnostics.rs b/crates/biome_analyze/Source/diagnostics.rs index cad4052d52c2..b607f4b1a0d2 100644 --- a/crates/biome_analyze/Source/diagnostics.rs +++ b/crates/biome_analyze/Source/diagnostics.rs @@ -66,9 +66,7 @@ impl Diagnostic for AnalyzerDiagnostic { fn message(&self, fmt:&mut biome_console::fmt::Formatter<'_>) -> std::io::Result<()> { match &self.kind { - DiagnosticKind::Rule(rule_diagnostic) => { - biome_console::fmt::Display::fmt(&rule_diagnostic.message, fmt) - }, + DiagnosticKind::Rule(rule_diagnostic) => biome_console::fmt::Display::fmt(&rule_diagnostic.message, fmt), DiagnosticKind::Raw(error) => error.message(fmt), } @@ -90,9 +88,7 @@ impl Diagnostic for AnalyzerDiagnostic { fn location(&self) -> Location<'_> { match &self.kind { - DiagnosticKind::Rule(rule_diagnostic) => { - Location::builder().span(&rule_diagnostic.span).build() - }, + DiagnosticKind::Rule(rule_diagnostic) => Location::builder().span(&rule_diagnostic.span).build(), DiagnosticKind::Raw(error) => error.location(), } @@ -115,9 +111,7 @@ impl Diagnostic for AnalyzerDiagnostic { impl AnalyzerDiagnostic { /// Creates a diagnostic from a generic [Error] - pub fn from_error(error:Error) -> Self { - Self { kind:DiagnosticKind::Raw(error), code_suggestion_list:vec![] } - } + pub fn from_error(error:Error) -> Self { Self { kind:DiagnosticKind::Raw(error), code_suggestion_list:vec![] } } pub fn get_span(&self) -> Option { match &self.kind { @@ -136,9 +130,7 @@ impl AnalyzerDiagnostic { DiagnosticKind::Rule(rule_diagnostic) }, - DiagnosticKind::Raw(error) => { - DiagnosticKind::Raw(error.with_tags(DiagnosticTags::FIXABLE)) - }, + DiagnosticKind::Raw(error) => DiagnosticKind::Raw(error.with_tags(DiagnosticTags::FIXABLE)), }; self.code_suggestion_list.push(suggestion); @@ -198,10 +190,7 @@ impl std::fmt::Display for RuleError { }, RuleError::ReplacedRootWithNonRootError { rule_name: None } => { - std::write!( - fmt, - "a code action replaced the root of the file with a non-root node." - ) + std::write!(fmt, "a code action replaced the root of the file with a non-root node.") }, } } @@ -218,10 +207,7 @@ impl biome_console::fmt::Display for RuleError { }, RuleError::ReplacedRootWithNonRootError { rule_name: None } => { - std::write!( - fmt, - "a code action replaced the root of the file with a non-root node." - ) + std::write!(fmt, "a code action replaced the root of the file with a non-root node.") }, } } diff --git a/crates/biome_analyze/Source/lib.rs b/crates/biome_analyze/Source/lib.rs index 7f98a4cae370..81e94846deaa 100644 --- a/crates/biome_analyze/Source/lib.rs +++ b/crates/biome_analyze/Source/lib.rs @@ -27,14 +27,7 @@ mod visitor; // Re-exported for use in the `declare_group` macro use biome_console::markup; pub use biome_diagnostics::category_concat; -use biome_diagnostics::{ - Applicability, - Diagnostic, - DiagnosticExt, - DiagnosticTags, - Severity, - category, -}; +use biome_diagnostics::{Applicability, Diagnostic, DiagnosticExt, DiagnosticTags, Severity, category}; use biome_rowan::{ AstNode, BatchMutation, @@ -154,11 +147,7 @@ where /// Registers a [Visitor] to be executed as part of a given `phase` of the /// analyzer run - pub fn add_visitor( - &mut self, - phase:Phases, - visitor:Box + 'analyzer>, - ) { + pub fn add_visitor(&mut self, phase:Phases, visitor:Box + 'analyzer>) { self.phases.entry(phase).or_default().push(visitor); } @@ -224,8 +213,8 @@ where SuppressionDiagnostic::new( category!("suppressions/unused"), suppression.comment_span, - "Suppression comment has no effect. Remove the suppression or make sure you \ - are suppressing the correct rule.", + "Suppression comment has no effect. Remove the suppression or make sure you are suppressing the \ + correct rule.", ) }); @@ -378,9 +367,7 @@ where for (index, piece) in token.leading_trivia().pieces().enumerate() { if matches!( piece.kind(), - TriviaPieceKind::Newline - | TriviaPieceKind::MultiLineComment - | TriviaPieceKind::Skipped + TriviaPieceKind::Newline | TriviaPieceKind::MultiLineComment | TriviaPieceKind::Skipped ) { self.bump_line_index(piece.text(), piece.text_range()); } @@ -395,9 +382,7 @@ where for (index, piece) in token.trailing_trivia().pieces().enumerate() { if matches!( piece.kind(), - TriviaPieceKind::Newline - | TriviaPieceKind::MultiLineComment - | TriviaPieceKind::Skipped + TriviaPieceKind::Newline | TriviaPieceKind::MultiLineComment | TriviaPieceKind::Skipped ) { self.bump_line_index(piece.text(), piece.text_range()); } @@ -431,8 +416,7 @@ where // search over all the previously seen suppressions to find one // with a matching range let suppression = self.line_suppressions.last_mut().filter(|suppression| { - suppression.line_index == *self.line_index - && suppression.text_range.start() <= start + suppression.line_index == *self.line_index && suppression.text_range.start() <= start }); let suppression = match suppression { @@ -553,9 +537,7 @@ where let key = match group_rule { None => self.metadata.find_group(rule).map(RuleFilter::from), - Some((group, rule)) => { - self.metadata.find_rule(group, rule).map(RuleFilter::from) - }, + Some((group, rule)) => self.metadata.find_rule(group, rule).map(RuleFilter::from), }; match (key, instance) { @@ -574,10 +556,7 @@ where SuppressionDiagnostic::new( category!("suppressions/unknownRule"), range, - format_args!( - "Unknown lint rule {group}/{rule} in suppression \ - comment" - ), + format_args!("Unknown lint rule {group}/{rule} in suppression comment"), ) }, @@ -585,9 +564,7 @@ where SuppressionDiagnostic::new( category!("suppressions/unknownGroup"), range, - format_args!( - "Unknown lint rule group {rule} in suppression comment" - ), + format_args!("Unknown lint rule group {rule} in suppression comment"), ) }, } @@ -619,8 +596,7 @@ where .with_tags(DiagnosticTags::DEPRECATED_CODE) }); - let signal = signal - .with_action(|| update_suppression(self.root, token, is_leading, index, text)); + let signal = signal.with_action(|| update_suppression(self.root, token, is_leading, index, text)); (self.emit_signal)(&signal)?; } @@ -635,9 +611,7 @@ where // If the last suppression was on the same or previous line, extend its // range and set of suppressed rules with the content for the new suppression if let Some(last_suppression) = self.line_suppressions.last_mut() { - if last_suppression.line_index == line_index - || last_suppression.line_index + 1 == line_index - { + if last_suppression.line_index == line_index || last_suppression.line_index + 1 == line_index { last_suppression.line_index = line_index; last_suppression.text_range = last_suppression.text_range.cover(range); @@ -682,9 +656,8 @@ where for (index, _) in text.match_indices('\n') { if let Some(last_suppression) = self.line_suppressions.last_mut() { if last_suppression.line_index == *self.line_index { - let index = TextSize::try_from(index).expect( - "integer overflow while converting a suppression line to `TextSize`", - ); + let index = TextSize::try_from(index) + .expect("integer overflow while converting a suppression line to `TextSize`"); let range = TextRange::at(range.start(), index); @@ -707,9 +680,7 @@ where } } -fn create_suppression_comment_action( - token:&SyntaxToken, -) -> Option> { +fn create_suppression_comment_action(token:&SyntaxToken) -> Option> { let first_node = token.parent()?; let mut new_leading_trivia = vec![]; @@ -744,12 +715,7 @@ fn create_suppression_comment_action( token_text.push_str(piece.text()); } - let new_token = SyntaxToken::new_detached( - token.kind(), - &token_text, - new_leading_trivia, - new_trailing_trivia, - ); + let new_token = SyntaxToken::new_detached(token.kind(), &token_text, new_leading_trivia, new_trailing_trivia); mutation.replace_token_discard_trivia(token.clone(), new_token); @@ -915,9 +881,7 @@ impl<'a> RuleFilter<'a> { R: Rule, { match self { RuleFilter::Group(group) => group == ::NAME, - RuleFilter::Rule(group, rule) => { - group == ::NAME && rule == R::METADATA.name - }, + RuleFilter::Rule(group, rule) => group == ::NAME && rule == R::METADATA.name, } } } diff --git a/crates/biome_analyze/Source/matcher.rs b/crates/biome_analyze/Source/matcher.rs index 2491fdf0e9a1..ee340e2af65d 100644 --- a/crates/biome_analyze/Source/matcher.rs +++ b/crates/biome_analyze/Source/matcher.rs @@ -133,9 +133,7 @@ pub struct SignalEntry<'phase, L:Language> { // SignalEntry is ordered based on the starting point of its `text_range` impl<'phase, L:Language> Ord for SignalEntry<'phase, L> { - fn cmp(&self, other:&Self) -> Ordering { - other.text_range.start().cmp(&self.text_range.start()) - } + fn cmp(&self, other:&Self) -> Ordering { other.text_range.start().cmp(&self.text_range.start()) } } impl<'phase, L:Language> PartialOrd for SignalEntry<'phase, L> { @@ -266,12 +264,7 @@ mod tests { builder.finish_node(); - builder.token_with_trivia( - RawLanguageKind::SEMICOLON_TOKEN, - ";\n", - &[], - &[TriviaPiece::newline(1)], - ); + builder.token_with_trivia(RawLanguageKind::SEMICOLON_TOKEN, ";\n", &[], &[TriviaPiece::newline(1)]); builder.start_node(RawLanguageKind::LITERAL_EXPRESSION); @@ -284,12 +277,7 @@ mod tests { builder.finish_node(); - builder.token_with_trivia( - RawLanguageKind::SEMICOLON_TOKEN, - ";\n", - &[], - &[TriviaPiece::newline(1)], - ); + builder.token_with_trivia(RawLanguageKind::SEMICOLON_TOKEN, ";\n", &[], &[TriviaPiece::newline(1)]); builder.start_node(RawLanguageKind::LITERAL_EXPRESSION); @@ -302,12 +290,7 @@ mod tests { builder.finish_node(); - builder.token_with_trivia( - RawLanguageKind::SEMICOLON_TOKEN, - ";\n", - &[], - &[TriviaPiece::newline(1)], - ); + builder.token_with_trivia(RawLanguageKind::SEMICOLON_TOKEN, ";\n", &[], &[TriviaPiece::newline(1)]); builder.start_node(RawLanguageKind::LITERAL_EXPRESSION); @@ -320,12 +303,7 @@ mod tests { builder.finish_node(); - builder.token_with_trivia( - RawLanguageKind::SEMICOLON_TOKEN, - ";\n", - &[], - &[TriviaPiece::newline(1)], - ); + builder.token_with_trivia(RawLanguageKind::SEMICOLON_TOKEN, ";\n", &[], &[TriviaPiece::newline(1)]); builder.token_with_trivia( RawLanguageKind::SEMICOLON_TOKEN, @@ -357,9 +335,7 @@ mod tests { ControlFlow::Continue(()) }; - fn parse_suppression_comment( - comment:&'_ str, - ) -> Vec, Infallible>> { + fn parse_suppression_comment(comment:&'_ str) -> Vec, Infallible>> { comment .trim_start_matches("//") .split(' ') diff --git a/crates/biome_analyze/Source/options.rs b/crates/biome_analyze/Source/options.rs index c24bc0711e20..489d603c476b 100644 --- a/crates/biome_analyze/Source/options.rs +++ b/crates/biome_analyze/Source/options.rs @@ -41,9 +41,7 @@ pub struct AnalyzerRules(FxHashMap); impl AnalyzerRules { /// It tracks the options of a specific rule - pub fn push_rule(&mut self, rule_key:RuleKey, options:RuleOptions) { - self.0.insert(rule_key, options); - } + pub fn push_rule(&mut self, rule_key:RuleKey, options:RuleOptions) { self.0.insert(rule_key, options); } /// It retrieves the options of a stored rule, given its name pub fn get_rule_options(&self, rule_key:&RuleKey) -> Option<&O> { @@ -90,9 +88,7 @@ pub struct AnalyzerOptions { } impl AnalyzerOptions { - pub fn globals(&self) -> Vec<&str> { - self.configuration.globals.iter().map(|global| global.as_str()).collect() - } + pub fn globals(&self) -> Vec<&str> { self.configuration.globals.iter().map(|global| global.as_str()).collect() } pub fn jsx_runtime(&self) -> Option { self.configuration.jsx_runtime } diff --git a/crates/biome_analyze/Source/query.rs b/crates/biome_analyze/Source/query.rs index 3d14410cdef5..603afa295415 100644 --- a/crates/biome_analyze/Source/query.rs +++ b/crates/biome_analyze/Source/query.rs @@ -17,10 +17,7 @@ pub trait Queryable: Sized { /// Registers one or more [Visitor] that will emit `Self::Input` query /// matches during the analyzer run - fn build_visitor( - analyzer:&mut impl AddVisitor, - root:&::Root, - ); + fn build_visitor(analyzer:&mut impl AddVisitor, root:&::Root); /// Returns the type of query matches this [Queryable] expects as inputs /// diff --git a/crates/biome_analyze/Source/registry.rs b/crates/biome_analyze/Source/registry.rs index d8e7dbfe7728..a4158ea75e1f 100644 --- a/crates/biome_analyze/Source/registry.rs +++ b/crates/biome_analyze/Source/registry.rs @@ -109,10 +109,7 @@ pub struct RuleRegistry { } impl RuleRegistry { - pub fn builder<'a>( - filter:&'a AnalysisFilter<'a>, - root:&'a L::Root, - ) -> RuleRegistryBuilder<'a, L> { + pub fn builder<'a>(filter:&'a AnalysisFilter<'a>, root:&'a L::Root) -> RuleRegistryBuilder<'a, L> { RuleRegistryBuilder { filter, root, @@ -186,10 +183,9 @@ impl RegistryVisitor for RuleRegistryBuilder< .or_insert_with(|| TypeRules::SyntaxRules { rules:Vec::new() }) else { unreachable!( - "the SyntaxNode type has already been registered as a TypeRules instead \ - of a SyntaxRules, this is generally caused by an implementation of \ - `Queryable::key` returning a `QueryKey::TypeId` with the type ID of \ - `SyntaxNode`" + "the SyntaxNode type has already been registered as a TypeRules instead of a SyntaxRules, \ + this is generally caused by an implementation of `Queryable::key` returning a \ + `QueryKey::TypeId` with the type ID of `SyntaxNode`" ) }; @@ -222,10 +218,9 @@ impl RegistryVisitor for RuleRegistryBuilder< .or_insert_with(|| TypeRules::TypeRules { rules:Vec::new() }) else { unreachable!( - "the query type has already been registered as a SyntaxRules instead of a \ - TypeRules, this is generally caused by an implementation of \ - `Queryable::key` returning a `QueryKey::TypeId` with the type ID of \ - `SyntaxNode`" + "the query type has already been registered as a SyntaxRules instead of a TypeRules, this is \ + generally caused by an implementation of `Queryable::key` returning a `QueryKey::TypeId` \ + with the type ID of `SyntaxNode`" ) }; @@ -257,9 +252,7 @@ type BuilderResult = ( ); impl RuleRegistryBuilder<'_, L> { - pub fn build(self) -> BuilderResult { - (self.registry, self.services, self.diagnostics, self.visitors) - } + pub fn build(self) -> BuilderResult { (self.registry, self.services, self.diagnostics, self.visitors) } } impl QueryMatcher for RuleRegistry { @@ -429,8 +422,7 @@ impl RegistryRule { }; for result in R::run(&ctx) { - let text_range = - R::text_range(&ctx, &result).unwrap_or_else(|| params.query.text_range()); + let text_range = R::text_range(&ctx, &result).unwrap_or_else(|| params.query.text_range()); R::suppressed_nodes(&ctx, &result, &mut state.suppressions); @@ -445,12 +437,9 @@ impl RegistryRule { params.options, )); - params.signal_queue.push(SignalEntry { - signal, - rule:RuleKey::rule::(), - instances, - text_range, - }); + params + .signal_queue + .push(SignalEntry { signal, rule:RuleKey::rule::(), instances, text_range }); } Ok(()) diff --git a/crates/biome_analyze/Source/rule.rs b/crates/biome_analyze/Source/rule.rs index 630058c51259..80411306016b 100644 --- a/crates/biome_analyze/Source/rule.rs +++ b/crates/biome_analyze/Source/rule.rs @@ -152,9 +152,7 @@ pub enum RuleSource { } impl PartialEq for RuleSource { - fn eq(&self, other:&Self) -> bool { - std::mem::discriminant(self) == std::mem::discriminant(other) - } + fn eq(&self, other:&Self) -> bool { std::mem::discriminant(self) == std::mem::discriminant(other) } } impl std::fmt::Display for RuleSource { @@ -293,9 +291,7 @@ impl RuleSource { } } - pub fn as_url_and_rule_name(&self) -> (String, &'static str) { - (self.to_rule_url(), self.as_rule_name()) - } + pub fn as_url_and_rule_name(&self) -> (String, &'static str) { (self.to_rule_url(), self.as_rule_name()) } /// Original ESLint rule pub const fn is_eslint(&self) -> bool { matches!(self, Self::Eslint(_)) } @@ -324,12 +320,7 @@ impl RuleSourceKind { } impl RuleMetadata { - pub const fn new( - version:&'static str, - name:&'static str, - docs:&'static str, - language:&'static str, - ) -> Self { + pub const fn new(version:&'static str, name:&'static str, docs:&'static str, language:&'static str) -> Self { Self { deprecated:None, version, @@ -388,13 +379,9 @@ impl RuleMetadata { pub fn action_category(&self, category:RuleCategory, group:&'static str) -> ActionCategory { match category { - RuleCategory::Lint => { - ActionCategory::QuickFix(Cow::Owned(format!("{}.{}", group, self.name))) - }, + RuleCategory::Lint => ActionCategory::QuickFix(Cow::Owned(format!("{}.{}", group, self.name))), - RuleCategory::Action => { - ActionCategory::Source(SourceActionKind::Other(Cow::Borrowed(self.name))) - }, + RuleCategory::Action => ActionCategory::Source(SourceActionKind::Other(Cow::Borrowed(self.name))), RuleCategory::Syntax | RuleCategory::Transformation => unimplemented!(""), } @@ -781,11 +768,10 @@ macro_rules! impl_group_language { } impl_group_language!( - T00, T01, T02, T03, T04, T05, T06, T07, T08, T09, T10, T11, T12, T13, T14, T15, T16, T17, T18, - T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, - T38, T39, T40, T41, T42, T43, T44, T45, T46, T47, T48, T49, T50, T51, T52, T53, T54, T55, T56, - T57, T58, T59, T60, T61, T62, T63, T64, T65, T66, T67, T68, T69, T70, T71, T72, T73, T74, T75, - T76, T77, T78, T79, T80, T81, T82, T83, T84, T85, T86, T87, T88, T89 + T00, T01, T02, T03, T04, T05, T06, T07, T08, T09, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, + T23, T24, T25, T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45, + T46, T47, T48, T49, T50, T51, T52, T53, T54, T55, T56, T57, T58, T59, T60, T61, T62, T63, T64, T65, T66, T67, T68, + T69, T70, T71, T72, T73, T74, T75, T76, T77, T78, T79, T80, T81, T82, T83, T84, T85, T86, T87, T88, T89 ); /// Trait implemented by all analysis rules: declares interest to a certain @@ -839,9 +825,7 @@ pub trait Rule: RuleMeta + Sized { /// *Note: For `noUnusedVariables` the above may not seem very useful (and /// indeed it's not implemented), but for rules such as /// `useExhaustiveDependencies` this is actually desirable.* - fn instances_for_signal(_signal:&Self::State) -> Box<[Box]> { - Vec::new().into_boxed_slice() - } + fn instances_for_signal(_signal:&Self::State) -> Box<[Box]> { Vec::new().into_boxed_slice() } /// Used by the analyzer to associate a range of source text to a signal in /// order to support suppression comments. @@ -905,10 +889,7 @@ pub trait Rule: RuleMeta + Sized { /// from a signal raised by `run` /// /// The default implementation returns None - fn action( - ctx:&RuleContext, - state:&Self::State, - ) -> Option>> { + fn action(ctx:&RuleContext, state:&Self::State) -> Option>> { let (..) = (ctx, state); None @@ -927,8 +908,7 @@ pub trait Rule: RuleMeta + Sized { // if the rule belongs to `Lint`, we auto generate an action to suppress the // rule if ::Category::CATEGORY == RuleCategory::Lint { - let rule_category = - format!("lint/{}/{}", ::NAME, Self::METADATA.name); + let rule_category = format!("lint/{}/{}", ::NAME, Self::METADATA.name); let suppression_text = format!("biome-ignore {rule_category}"); @@ -946,22 +926,14 @@ pub trait Rule: RuleMeta + Sized { suppression_reason:suppression_reason.unwrap_or(""), }); - Some(SuppressAction { - mutation, - message:markup! { "Suppress rule " {rule_category} }.to_owned(), - }) + Some(SuppressAction { mutation, message:markup! { "Suppress rule " {rule_category} }.to_owned() }) } else { None } } /// Returns a mutation to apply to the code - fn transform( - _ctx:&RuleContext, - _state:&Self::State, - ) -> Option>> { - None - } + fn transform(_ctx:&RuleContext, _state:&Self::State) -> Option>> { None } } /// Diagnostic object returned by a single analysis rule @@ -1009,8 +981,7 @@ impl Advices for RuleAdvice { } if let Some(suggestion_list) = &self.suggestion_list { - visitor - .record_log(LogCategory::Info, &markup! { {suggestion_list.message} }.to_owned())?; + visitor.record_log(LogCategory::Info, &markup! { {suggestion_list.message} }.to_owned())?; let list:Vec<_> = suggestion_list .list @@ -1110,11 +1081,7 @@ impl RuleDiagnostic { /// It creates a new footer note which contains a message and a list of /// possible suggestions. Useful when there's need to suggest a list of /// things inside a diagnostic. - pub fn footer_list( - mut self, - message:impl Display, - list:impl IntoIterator, - ) -> Self { + pub fn footer_list(mut self, message:impl Display, list:impl IntoIterator) -> Self { self.rule_advice.suggestion_list = Some(SuggestionList { message:markup! { {message} }.to_owned(), list:list.into_iter().map(|msg| markup! {{msg}}.to_owned()).collect(), diff --git a/crates/biome_analyze/Source/services.rs b/crates/biome_analyze/Source/services.rs index f6fd760c30b1..c2641b31f7ec 100644 --- a/crates/biome_analyze/Source/services.rs +++ b/crates/biome_analyze/Source/services.rs @@ -36,10 +36,7 @@ impl MissingServicesDiagnostic { pub trait FromServices: Sized { #[allow(clippy::result_large_err)] - fn from_services( - rule_key:&RuleKey, - services:&ServiceBag, - ) -> Result; + fn from_services(rule_key:&RuleKey, services:&ServiceBag) -> Result; } #[derive(Debug, Default)] @@ -64,7 +61,5 @@ impl ServiceBag { } impl FromServices for () { - fn from_services(_:&RuleKey, _:&ServiceBag) -> Result { - Ok(()) - } + fn from_services(_:&RuleKey, _:&ServiceBag) -> Result { Ok(()) } } diff --git a/crates/biome_analyze/Source/signals.rs b/crates/biome_analyze/Source/signals.rs index 3a0e119080b4..6f88b8e57e1f 100644 --- a/crates/biome_analyze/Source/signals.rs +++ b/crates/biome_analyze/Source/signals.rs @@ -39,13 +39,7 @@ pub struct DiagnosticSignal { } impl - DiagnosticSignal< - D, - fn() -> Option>, - L, - T, - fn() -> Option>, - > + DiagnosticSignal Option>, L, T, fn() -> Option>> where D: Fn() -> T, Error: From, @@ -229,9 +223,7 @@ impl AnalyzerActionIter { } /// Returns an iterator that yields [CodeAction] - pub fn into_code_action_iter(self) -> CodeActionIter { - CodeActionIter { iter:self.analyzer_actions } - } + pub fn into_code_action_iter(self) -> CodeActionIter { CodeActionIter { iter:self.analyzer_actions } } } pub struct AnalyzerTransformationIter { @@ -294,9 +286,7 @@ where query_result:<::Query as Queryable>::Output, state:R::State, services:&'phase ServiceBag, - suppression_action:&'phase dyn SuppressionAction< - Language = <::Query as Queryable>::Language, - >, + suppression_action:&'phase dyn SuppressionAction::Query as Queryable>::Language>, options:&'phase AnalyzerOptions, ) -> Self { Self { root, query_result, state, services, suppression_action, options } diff --git a/crates/biome_analyze/Source/suppression_action.rs b/crates/biome_analyze/Source/suppression_action.rs index dad813ffd5f2..7324a88e08fa 100644 --- a/crates/biome_analyze/Source/suppression_action.rs +++ b/crates/biome_analyze/Source/suppression_action.rs @@ -19,17 +19,12 @@ pub trait SuppressionAction { // considering that our suppression system works via lines, we need to look for // the first newline, so we can place the comment there - let apply_suppression = original_token.as_ref().and_then(|original_token| { - self.find_token_to_apply_suppression(original_token.clone()) - }); + let apply_suppression = original_token + .as_ref() + .and_then(|original_token| self.find_token_to_apply_suppression(original_token.clone())); if let Some(apply_suppression) = apply_suppression { - self.apply_suppression( - mutation, - apply_suppression, - suppression_text, - suppression_reason, - ); + self.apply_suppression(mutation, apply_suppression, suppression_text, suppression_reason); } } @@ -60,12 +55,11 @@ pub trait SuppressionAction { TokenAtOffset::None => None, TokenAtOffset::Single(token) => Some(token), TokenAtOffset::Between(left_token, right_token) => { - let chosen_token = - if right_token.text_range().start() == diagnostic_text_range.start() { - right_token - } else { - left_token - }; + let chosen_token = if right_token.text_range().start() == diagnostic_text_range.start() { + right_token + } else { + left_token + }; Some(chosen_token) }, diff --git a/crates/biome_analyze/Source/syntax.rs b/crates/biome_analyze/Source/syntax.rs index 6f8f3e9a21d5..7210fc48bbcb 100644 --- a/crates/biome_analyze/Source/syntax.rs +++ b/crates/biome_analyze/Source/syntax.rs @@ -25,18 +25,13 @@ where type Output = N; type Services = (); - fn build_visitor( - analyzer:&mut impl AddVisitor, - _:&::Root, - ) { + fn build_visitor(analyzer:&mut impl AddVisitor, _:&::Root) { analyzer.add_visitor(Phases::Syntax, SyntaxVisitor::default); } fn key() -> QueryKey { QueryKey::Syntax(N::KIND_SET) } - fn unwrap_match(_:&ServiceBag, node:&Self::Input) -> Self::Output { - N::unwrap_cast(node.clone()) - } + fn unwrap_match(_:&ServiceBag, node:&Self::Input) -> Self::Output { N::unwrap_cast(node.clone()) } } impl QueryMatch for SyntaxNode { @@ -164,8 +159,7 @@ mod tests { let mut matcher = BufferMatcher::default(); - let mut emit_signal = - |_:&dyn AnalyzerSignal| -> ControlFlow { unreachable!() }; + let mut emit_signal = |_:&dyn AnalyzerSignal| -> ControlFlow { unreachable!() }; let metadata = MetadataRegistry::default(); diff --git a/crates/biome_analyze/Source/visitor.rs b/crates/biome_analyze/Source/visitor.rs index f2304e0f67d1..228f1e3c558b 100644 --- a/crates/biome_analyze/Source/visitor.rs +++ b/crates/biome_analyze/Source/visitor.rs @@ -53,11 +53,7 @@ pub struct VisitorFinishContext<'a, L:Language> { pub trait Visitor { type Language: Language; - fn visit( - &mut self, - event:&WalkEvent>, - ctx:VisitorContext, - ); + fn visit(&mut self, event:&WalkEvent>, ctx:VisitorContext); fn finish(self: Box, ctx:VisitorFinishContext) { let _ = ctx; } } @@ -73,11 +69,7 @@ pub trait Visitor { pub trait NodeVisitor: Sized { type Node: AstNode; - fn enter( - node:Self::Node, - ctx:&mut VisitorContext>, - stack:&mut V, - ) -> Self; + fn enter(node:Self::Node, ctx:&mut VisitorContext>, stack:&mut V) -> Self; fn exit(self, node:Self::Node, ctx:&mut VisitorContext>, stack:&mut V); } diff --git a/crates/biome_aria/Source/lib.rs b/crates/biome_aria/Source/lib.rs index 25604560f835..8ee6e119786f 100644 --- a/crates/biome_aria/Source/lib.rs +++ b/crates/biome_aria/Source/lib.rs @@ -11,9 +11,11 @@ pub trait Element { /// returns the first attribute with a name that matches `matcher`. fn find_attribute_by_name(&self, matcher:impl Fn(&str) -> bool) -> Option { - self.attributes().find_map(|attribute| { - if matcher(attribute.name()?.as_ref()) { Some(attribute) } else { None } - }) + self.attributes().find_map( + |attribute| { + if matcher(attribute.name()?.as_ref()) { Some(attribute) } else { None } + }, + ) } } diff --git a/crates/biome_aria/Source/properties.rs b/crates/biome_aria/Source/properties.rs index e1c4f96ae8f7..4f85945662d8 100644 --- a/crates/biome_aria/Source/properties.rs +++ b/crates/biome_aria/Source/properties.rs @@ -432,20 +432,16 @@ pub trait AriaPropertyDefinition: Debug { match self.property_type() { AriaPropertyTypeEnum::String => true, AriaPropertyTypeEnum::Id => is_valid_html_id(input_value), - AriaPropertyTypeEnum::Idlist => { - input_value.split_ascii_whitespace().all(is_valid_html_id) - }, + AriaPropertyTypeEnum::Idlist => input_value.split_ascii_whitespace().all(is_valid_html_id), // A numerical value without a fractional component. AriaPropertyTypeEnum::Integer => input_value.parse::().is_ok(), AriaPropertyTypeEnum::Number => input_value.parse::().is_ok(), AriaPropertyTypeEnum::Boolean => matches!(input_value, "false" | "true"), - AriaPropertyTypeEnum::Token => { - self.values().any(|allowed_token| *allowed_token == input_value) - }, + AriaPropertyTypeEnum::Token => self.values().any(|allowed_token| *allowed_token == input_value), AriaPropertyTypeEnum::Tokenlist => { - input_value.split_ascii_whitespace().all(|input_token| { - self.values().any(|allowed_token| allowed_token.trim() == input_token) - }) + input_value + .split_ascii_whitespace() + .all(|input_token| self.values().any(|allowed_token| allowed_token.trim() == input_token)) }, AriaPropertyTypeEnum::Tristate => matches!(input_value, "false" | "true" | "mixed"), @@ -461,6 +457,4 @@ pub trait AriaPropertyDefinition: Debug { /// Whitespaces are usedd to separate two identifier in a list of identifiers. /// /// See https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id#syntax -fn is_valid_html_id(id:&str) -> bool { - !id.is_empty() && !id.bytes().any(|b| b.is_ascii_whitespace()) -} +fn is_valid_html_id(id:&str) -> bool { !id.is_empty() && !id.bytes().any(|b| b.is_ascii_whitespace()) } diff --git a/crates/biome_aria/Source/roles.rs b/crates/biome_aria/Source/roles.rs index 07bf364c1860..619ae11775e9 100644 --- a/crates/biome_aria/Source/roles.rs +++ b/crates/biome_aria/Source/roles.rs @@ -117,8 +117,8 @@ impl AriaRoles { } }, Some( - "color" | "date" | "datetime-local" | "file" | "hidden" | "month" - | "password" | "time" | "week", + "color" | "date" | "datetime-local" | "file" | "hidden" | "month" | "password" | "time" + | "week", ) => { return None; }, @@ -152,9 +152,7 @@ impl AriaRoles { AriaRole::Img } else { let has_accessible_name = elt - .find_attribute_by_name(|n| { - matches!(n, "aria-labelledby" | "aria-label" | "title") - }) + .find_attribute_by_name(|n| matches!(n, "aria-labelledby" | "aria-label" | "title")) .is_some(); if has_accessible_name { AriaRole::Img } else { AriaRole::Presentation } @@ -166,19 +164,13 @@ impl AriaRoles { }, "section" => { let has_accessible_name = elt - .find_attribute_by_name(|n| { - matches!(n, "aria-labelledby" | "aria-label" | "title") - }) + .find_attribute_by_name(|n| matches!(n, "aria-labelledby" | "aria-label" | "title")) .is_some(); if has_accessible_name { AriaRole::Region } else { AriaRole::Generic } }, "select" => { - let size = match elt - .find_attribute_by_name(|n| n == "size") - .as_ref() - .and_then(|a| a.value()) - { + let size = match elt.find_attribute_by_name(|n| n == "size").as_ref().and_then(|a| a.value()) { Some(size) => size.as_ref().parse::().ok()?, None => 0, }; @@ -189,8 +181,9 @@ impl AriaRoles { AriaRole::Listbox } }, - "b" | "bdi" | "bdo" | "body" | "data" | "div" | "i" | "q" | "samp" | "small" - | "span" | "u" | "pre" => AriaRole::Generic, + "b" | "bdi" | "bdo" | "body" | "data" | "div" | "i" | "q" | "samp" | "small" | "span" | "u" | "pre" => { + AriaRole::Generic + }, "header" | "footer" => { // This crate does not support checking a descendant of an element. // header (maybe BannerRole): https://www.w3.org/WAI/ARIA/apg/patterns/landmarks/examples/banner.html @@ -225,8 +218,8 @@ impl AriaRoles { Some("svg") => true, // Elements without any concept Some( - "body" | "br" | "details" | "dir" | "frame" | "iframe" | "label" | "mark" - | "marquee" | "menu" | "meter" | "optgroup" | "pre" | "progress" | "ruby", + "body" | "br" | "details" | "dir" | "frame" | "iframe" | "label" | "mark" | "marquee" | "menu" + | "meter" | "optgroup" | "pre" | "progress" | "ruby", ) => true, // `` is not interactive. // `type=hidden` is not represented as concept information. @@ -263,9 +256,7 @@ impl AriaRoles { // ref: https://html.spec.whatwg.org/multipage/semantics.html#embedded-content Some("canvas" | "embed" | "iframe" | "video" | "audio") => true, // No corresponding role - Some("input" | "dl" | "label" | "legend" | "ruby" | "pre" | "figcaption" | "br") => { - true - }, + Some("input" | "dl" | "label" | "legend" | "ruby" | "pre" | "figcaption" | "br") => true, Some("s" | "hgroup") => false, // FIXME: should we add `link`? diff --git a/crates/biome_aria_metadata/Source/lib.rs b/crates/biome_aria_metadata/Source/lib.rs index 38bf911b5eb8..7b829e1a27c2 100644 --- a/crates/biome_aria_metadata/Source/lib.rs +++ b/crates/biome_aria_metadata/Source/lib.rs @@ -3,34 +3,30 @@ use std::str::FromStr; include!(concat!(env!("OUT_DIR"), "/roles_and_attributes.rs")); pub const ISO_COUNTRIES:[&str; 233] = [ - "AF", "AL", "DZ", "AS", "AD", "AO", "AI", "AQ", "AG", "AR", "AM", "AW", "AU", "AT", "AZ", "BS", - "BH", "BD", "BB", "BY", "BE", "BZ", "BJ", "BM", "BT", "BO", "BA", "BW", "BR", "IO", "VG", "BN", - "BG", "BF", "MM", "BI", "KH", "CM", "CA", "CV", "KY", "CF", "TD", "CL", "CN", "CX", "CC", "CO", - "KM", "CK", "CR", "HR", "CU", "CY", "CZ", "CD", "DK", "DJ", "DM", "DO", "EC", "EG", "SV", "GQ", - "ER", "EE", "ET", "FK", "FO", "FJ", "FI", "FR", "PF", "GA", "GM", "GE", "DE", "GH", "GI", "GR", - "GL", "GD", "GU", "GT", "GN", "GW", "GY", "HT", "VA", "HN", "HK", "HU", "IS", "IN", "ID", "IR", - "IQ", "IE", "IM", "IL", "IT", "CI", "JM", "JP", "JE", "JO", "KZ", "KE", "KI", "KW", "KG", "LA", - "LV", "LB", "LS", "LR", "LY", "LI", "LT", "LU", "MO", "MK", "MG", "MW", "MY", "MV", "ML", "MT", - "MH", "MR", "MU", "YT", "MX", "FM", "MD", "MC", "MN", "ME", "MS", "MA", "MZ", "NA", "NR", "NP", - "NL", "AN", "NC", "NZ", "NI", "NE", "NG", "NU", "KP", "MP", "NO", "OM", "PK", "PW", "PA", "PG", - "PY", "PE", "PH", "PN", "PL", "PT", "PR", "QA", "CG", "RO", "RU", "RW", "BL", "SH", "KN", "LC", - "MF", "PM", "VC", "WS", "SM", "ST", "SA", "SN", "RS", "SC", "SL", "SG", "SK", "SI", "SB", "SO", - "ZA", "KR", "ES", "LK", "SD", "SR", "SJ", "SZ", "SE", "CH", "SY", "TW", "TJ", "TZ", "TH", "TL", - "TG", "TK", "TO", "TT", "TN", "TR", "TM", "TC", "TV", "UG", "UA", "AE", "GB", "US", "UY", "VI", - "UZ", "VU", "VE", "VN", "WF", "EH", "YE", "ZM", "ZW", + "AF", "AL", "DZ", "AS", "AD", "AO", "AI", "AQ", "AG", "AR", "AM", "AW", "AU", "AT", "AZ", "BS", "BH", "BD", "BB", + "BY", "BE", "BZ", "BJ", "BM", "BT", "BO", "BA", "BW", "BR", "IO", "VG", "BN", "BG", "BF", "MM", "BI", "KH", "CM", + "CA", "CV", "KY", "CF", "TD", "CL", "CN", "CX", "CC", "CO", "KM", "CK", "CR", "HR", "CU", "CY", "CZ", "CD", "DK", + "DJ", "DM", "DO", "EC", "EG", "SV", "GQ", "ER", "EE", "ET", "FK", "FO", "FJ", "FI", "FR", "PF", "GA", "GM", "GE", + "DE", "GH", "GI", "GR", "GL", "GD", "GU", "GT", "GN", "GW", "GY", "HT", "VA", "HN", "HK", "HU", "IS", "IN", "ID", + "IR", "IQ", "IE", "IM", "IL", "IT", "CI", "JM", "JP", "JE", "JO", "KZ", "KE", "KI", "KW", "KG", "LA", "LV", "LB", + "LS", "LR", "LY", "LI", "LT", "LU", "MO", "MK", "MG", "MW", "MY", "MV", "ML", "MT", "MH", "MR", "MU", "YT", "MX", + "FM", "MD", "MC", "MN", "ME", "MS", "MA", "MZ", "NA", "NR", "NP", "NL", "AN", "NC", "NZ", "NI", "NE", "NG", "NU", + "KP", "MP", "NO", "OM", "PK", "PW", "PA", "PG", "PY", "PE", "PH", "PN", "PL", "PT", "PR", "QA", "CG", "RO", "RU", + "RW", "BL", "SH", "KN", "LC", "MF", "PM", "VC", "WS", "SM", "ST", "SA", "SN", "RS", "SC", "SL", "SG", "SK", "SI", + "SB", "SO", "ZA", "KR", "ES", "LK", "SD", "SR", "SJ", "SZ", "SE", "CH", "SY", "TW", "TJ", "TZ", "TH", "TL", "TG", + "TK", "TO", "TT", "TN", "TR", "TM", "TC", "TV", "UG", "UA", "AE", "GB", "US", "UY", "VI", "UZ", "VU", "VE", "VN", + "WF", "EH", "YE", "ZM", "ZW", ]; pub const ISO_LANGUAGES:[&str; 150] = [ - "ab", "aa", "af", "sq", "am", "ar", "an", "hy", "as", "ay", "az", "ba", "eu", "bn", "dz", "bh", - "bi", "br", "bg", "my", "be", "km", "ca", "zh", "zh-Hans", "zh-Hant", "co", "hr", "cs", "da", - "nl", "en", "eo", "et", "fo", "fa", "fj", "fi", "fr", "fy", "gl", "gd", "gv", "ka", "de", "el", - "kl", "gn", "gu", "ht", "ha", "he", "iw", "hi", "hu", "is", "io", "id", "in", "ia", "ie", "iu", - "ik", "ga", "it", "ja", "jv", "kn", "ks", "kk", "rw", "ky", "rn", "ko", "ku", "lo", "la", "lv", - "li", "ln", "lt", "mk", "mg", "ms", "ml", "mt", "mi", "mr", "mo", "mn", "na", "ne", "no", "oc", - "or", "om", "ps", "pl", "pt", "pa", "qu", "rm", "ro", "ru", "sm", "sg", "sa", "sr", "sh", "st", - "tn", "sn", "ii", "sd", "si", "ss", "sk", "sl", "so", "es", "su", "sw", "sv", "tl", "tg", "ta", - "tt", "te", "th", "bo", "ti", "to", "ts", "tr", "tk", "tw", "ug", "uk", "ur", "uz", "vi", "vo", - "wa", "cy", "wo", "xh", "yi", "ji", "yo", "zu", + "ab", "aa", "af", "sq", "am", "ar", "an", "hy", "as", "ay", "az", "ba", "eu", "bn", "dz", "bh", "bi", "br", "bg", + "my", "be", "km", "ca", "zh", "zh-Hans", "zh-Hant", "co", "hr", "cs", "da", "nl", "en", "eo", "et", "fo", "fa", + "fj", "fi", "fr", "fy", "gl", "gd", "gv", "ka", "de", "el", "kl", "gn", "gu", "ht", "ha", "he", "iw", "hi", "hu", + "is", "io", "id", "in", "ia", "ie", "iu", "ik", "ga", "it", "ja", "jv", "kn", "ks", "kk", "rw", "ky", "rn", "ko", + "ku", "lo", "la", "lv", "li", "ln", "lt", "mk", "mg", "ms", "ml", "mt", "mi", "mr", "mo", "mn", "na", "ne", "no", + "oc", "or", "om", "ps", "pl", "pt", "pa", "qu", "rm", "ro", "ru", "sm", "sg", "sa", "sr", "sh", "st", "tn", "sn", + "ii", "sd", "si", "ss", "sk", "sl", "so", "es", "su", "sw", "sv", "tl", "tg", "ta", "tt", "te", "th", "bo", "ti", + "to", "ts", "tr", "tk", "tw", "ug", "uk", "ur", "uz", "vi", "vo", "wa", "cy", "wo", "xh", "yi", "ji", "yo", "zu", ]; /// Returns a list of valid ISO countries @@ -100,9 +96,9 @@ impl AriaValueType { Self::OptionalBoolean => matches!(value, "undefined" | "false" | "true"), Self::Token(tokens) => tokens.iter().any(|allowed_token| *allowed_token == value), Self::TokenList(tokens) => { - value.split_ascii_whitespace().all(|input_token| { - tokens.iter().any(|allowed_token| allowed_token.trim() == input_token) - }) + value + .split_ascii_whitespace() + .all(|input_token| tokens.iter().any(|allowed_token| allowed_token.trim() == input_token)) }, Self::Tristate => matches!(value, "false" | "true" | "mixed"), } @@ -117,9 +113,7 @@ impl AriaValueType { /// Whitespaces are usedd to separate two identifier in a list of identifiers. /// /// See https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id#syntax -fn is_valid_html_id(id:&str) -> bool { - !id.is_empty() && !id.bytes().any(|b| b.is_ascii_whitespace()) -} +fn is_valid_html_id(id:&str) -> bool { !id.is_empty() && !id.bytes().any(|b| b.is_ascii_whitespace()) } impl AriaRole { /// Returns the first valid role from `values`, a space-separated list of @@ -144,8 +138,7 @@ impl AriaRole { pub fn is_interactive(self) -> bool { // `progressbar` inherits of `widget`, but its value is always `readonly`. // So we treat it as a non-interactive role. - self != Self::Progressbar - && self.inherited_abstract_roles().contains(&AriaAbstractRole::Widget) + self != Self::Progressbar && self.inherited_abstract_roles().contains(&AriaAbstractRole::Widget) } /// Returns `true` if the given role is not interactive and is not @@ -168,15 +161,11 @@ impl AriaRole { /// /// This corresponds to a role that defines the page structure (section, /// navigation, ...). - pub fn is_presentational(self) -> bool { - self.inherited_abstract_roles().contains(&AriaAbstractRole::Structure) - } + pub fn is_presentational(self) -> bool { self.inherited_abstract_roles().contains(&AriaAbstractRole::Structure) } /// Returns `true` if the given role inherits of /// `AriaAbstractRole::Composite`. - pub fn is_composite(self) -> bool { - self.inherited_abstract_roles().contains(&AriaAbstractRole::Composite) - } + pub fn is_composite(self) -> bool { self.inherited_abstract_roles().contains(&AriaAbstractRole::Composite) } } #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] diff --git a/crates/biome_aria_metadata/build.rs b/crates/biome_aria_metadata/build.rs index bbb929229f36..d7d150ba04a8 100644 --- a/crates/biome_aria_metadata/build.rs +++ b/crates/biome_aria_metadata/build.rs @@ -18,34 +18,30 @@ const GRAPHICS_ARIA:&str = "../../packages/aria-data/graphics-aria-1-0.json"; const DPUB_ARIA:&str = "../../packages/aria-data/dpub-aria-1-1.json"; const ISO_COUNTRIES:&[&str] = &[ - "AF", "AL", "DZ", "AS", "AD", "AO", "AI", "AQ", "AG", "AR", "AM", "AW", "AU", "AT", "AZ", "BS", - "BH", "BD", "BB", "BY", "BE", "BZ", "BJ", "BM", "BT", "BO", "BA", "BW", "BR", "IO", "VG", "BN", - "BG", "BF", "MM", "BI", "KH", "CM", "CA", "CV", "KY", "CF", "TD", "CL", "CN", "CX", "CC", "CO", - "KM", "CK", "CR", "HR", "CU", "CY", "CZ", "CD", "DK", "DJ", "DM", "DO", "EC", "EG", "SV", "GQ", - "ER", "EE", "ET", "FK", "FO", "FJ", "FI", "FR", "PF", "GA", "GM", "GE", "DE", "GH", "GI", "GR", - "GL", "GD", "GU", "GT", "GN", "GW", "GY", "HT", "VA", "HN", "HK", "HU", "IS", "IN", "ID", "IR", - "IQ", "IE", "IM", "IL", "IT", "CI", "JM", "JP", "JE", "JO", "KZ", "KE", "KI", "KW", "KG", "LA", - "LV", "LB", "LS", "LR", "LY", "LI", "LT", "LU", "MO", "MK", "MG", "MW", "MY", "MV", "ML", "MT", - "MH", "MR", "MU", "YT", "MX", "FM", "MD", "MC", "MN", "ME", "MS", "MA", "MZ", "NA", "NR", "NP", - "NL", "AN", "NC", "NZ", "NI", "NE", "NG", "NU", "KP", "MP", "NO", "OM", "PK", "PW", "PA", "PG", - "PY", "PE", "PH", "PN", "PL", "PT", "PR", "QA", "CG", "RO", "RU", "RW", "BL", "SH", "KN", "LC", - "MF", "PM", "VC", "WS", "SM", "ST", "SA", "SN", "RS", "SC", "SL", "SG", "SK", "SI", "SB", "SO", - "ZA", "KR", "ES", "LK", "SD", "SR", "SJ", "SZ", "SE", "CH", "SY", "TW", "TJ", "TZ", "TH", "TL", - "TG", "TK", "TO", "TT", "TN", "TR", "TM", "TC", "TV", "UG", "UA", "AE", "GB", "US", "UY", "VI", - "UZ", "VU", "VE", "VN", "WF", "EH", "YE", "ZM", "ZW", + "AF", "AL", "DZ", "AS", "AD", "AO", "AI", "AQ", "AG", "AR", "AM", "AW", "AU", "AT", "AZ", "BS", "BH", "BD", "BB", + "BY", "BE", "BZ", "BJ", "BM", "BT", "BO", "BA", "BW", "BR", "IO", "VG", "BN", "BG", "BF", "MM", "BI", "KH", "CM", + "CA", "CV", "KY", "CF", "TD", "CL", "CN", "CX", "CC", "CO", "KM", "CK", "CR", "HR", "CU", "CY", "CZ", "CD", "DK", + "DJ", "DM", "DO", "EC", "EG", "SV", "GQ", "ER", "EE", "ET", "FK", "FO", "FJ", "FI", "FR", "PF", "GA", "GM", "GE", + "DE", "GH", "GI", "GR", "GL", "GD", "GU", "GT", "GN", "GW", "GY", "HT", "VA", "HN", "HK", "HU", "IS", "IN", "ID", + "IR", "IQ", "IE", "IM", "IL", "IT", "CI", "JM", "JP", "JE", "JO", "KZ", "KE", "KI", "KW", "KG", "LA", "LV", "LB", + "LS", "LR", "LY", "LI", "LT", "LU", "MO", "MK", "MG", "MW", "MY", "MV", "ML", "MT", "MH", "MR", "MU", "YT", "MX", + "FM", "MD", "MC", "MN", "ME", "MS", "MA", "MZ", "NA", "NR", "NP", "NL", "AN", "NC", "NZ", "NI", "NE", "NG", "NU", + "KP", "MP", "NO", "OM", "PK", "PW", "PA", "PG", "PY", "PE", "PH", "PN", "PL", "PT", "PR", "QA", "CG", "RO", "RU", + "RW", "BL", "SH", "KN", "LC", "MF", "PM", "VC", "WS", "SM", "ST", "SA", "SN", "RS", "SC", "SL", "SG", "SK", "SI", + "SB", "SO", "ZA", "KR", "ES", "LK", "SD", "SR", "SJ", "SZ", "SE", "CH", "SY", "TW", "TJ", "TZ", "TH", "TL", "TG", + "TK", "TO", "TT", "TN", "TR", "TM", "TC", "TV", "UG", "UA", "AE", "GB", "US", "UY", "VI", "UZ", "VU", "VE", "VN", + "WF", "EH", "YE", "ZM", "ZW", ]; const ISO_LANGUAGES:&[&str] = &[ - "ab", "aa", "af", "sq", "am", "ar", "an", "hy", "as", "ay", "az", "ba", "eu", "bn", "dz", "bh", - "bi", "br", "bg", "my", "be", "km", "ca", "zh", "zh-Hans", "zh-Hant", "co", "hr", "cs", "da", - "nl", "en", "eo", "et", "fo", "fa", "fj", "fi", "fr", "fy", "gl", "gd", "gv", "ka", "de", "el", - "kl", "gn", "gu", "ht", "ha", "he", "iw", "hi", "hu", "is", "io", "id", "in", "ia", "ie", "iu", - "ik", "ga", "it", "ja", "jv", "kn", "ks", "kk", "rw", "ky", "rn", "ko", "ku", "lo", "la", "lv", - "li", "ln", "lt", "mk", "mg", "ms", "ml", "mt", "mi", "mr", "mo", "mn", "na", "ne", "no", "oc", - "or", "om", "ps", "pl", "pt", "pa", "qu", "rm", "ro", "ru", "sm", "sg", "sa", "sr", "sh", "st", - "tn", "sn", "ii", "sd", "si", "ss", "sk", "sl", "so", "es", "su", "sw", "sv", "tl", "tg", "ta", - "tt", "te", "th", "bo", "ti", "to", "ts", "tr", "tk", "tw", "ug", "uk", "ur", "uz", "vi", "vo", - "wa", "cy", "wo", "xh", "yi", "ji", "yo", "zu", + "ab", "aa", "af", "sq", "am", "ar", "an", "hy", "as", "ay", "az", "ba", "eu", "bn", "dz", "bh", "bi", "br", "bg", + "my", "be", "km", "ca", "zh", "zh-Hans", "zh-Hant", "co", "hr", "cs", "da", "nl", "en", "eo", "et", "fo", "fa", + "fj", "fi", "fr", "fy", "gl", "gd", "gv", "ka", "de", "el", "kl", "gn", "gu", "ht", "ha", "he", "iw", "hi", "hu", + "is", "io", "id", "in", "ia", "ie", "iu", "ik", "ga", "it", "ja", "jv", "kn", "ks", "kk", "rw", "ky", "rn", "ko", + "ku", "lo", "la", "lv", "li", "ln", "lt", "mk", "mg", "ms", "ml", "mt", "mi", "mr", "mo", "mn", "na", "ne", "no", + "oc", "or", "om", "ps", "pl", "pt", "pa", "qu", "rm", "ro", "ru", "sm", "sg", "sa", "sr", "sh", "st", "tn", "sn", + "ii", "sd", "si", "ss", "sk", "sl", "so", "es", "su", "sw", "sv", "tl", "tg", "ta", "tt", "te", "th", "bo", "ti", + "to", "ts", "tr", "tk", "tw", "ug", "uk", "ur", "uz", "vi", "vo", "wa", "cy", "wo", "xh", "yi", "ji", "yo", "zu", ]; #[derive(Debug, Default, biome_deserialize_macros::Merge, serde::Deserialize)] @@ -169,9 +165,7 @@ struct AriaAttributeReference { impl From for AriaAttributeReference { fn from(value:AriaAttributeReferenceShortcut) -> Self { match value { - AriaAttributeReferenceShortcut::Active(name) => { - Self { name, deprecated_in_version:None } - }, + AriaAttributeReferenceShortcut::Active(name) => Self { name, deprecated_in_version:None }, AriaAttributeReferenceShortcut::Deprecated { name, deprecated_in_version } => { Self { name, deprecated_in_version } }, @@ -199,9 +193,7 @@ struct AriaAttribute { values:BTreeMap, } -#[derive( - Clone, Copy, Debug, Default, Eq, PartialEq, biome_deserialize_macros::Merge, serde::Deserialize, -)] +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, biome_deserialize_macros::Merge, serde::Deserialize)] enum AriaValueType { #[default] #[serde(rename = "true/false")] @@ -406,25 +398,22 @@ fn generate_aria_attributes(attributes:&BTreeMap) -> Toke AriaValueType::Tristate => quote! { Tristate }, }; - let params = if !data.values.is_empty() - && matches!(data.value_type, AriaValueType::Token | AriaValueType::TokenList) - { - let default_value = - data.values.iter().find(|(_, data)| data.is_default).map(|(name, _)| name); + let params = + if !data.values.is_empty() && matches!(data.value_type, AriaValueType::Token | AriaValueType::TokenList) { + let default_value = data.values.iter().find(|(_, data)| data.is_default).map(|(name, _)| name); - let other_values = - data.values.iter().filter(|(_, data)| !data.is_default).map(|(name, _)| name); + let other_values = data.values.iter().filter(|(_, data)| !data.is_default).map(|(name, _)| name); - let values = default_value.into_iter().chain(other_values); + let values = default_value.into_iter().chain(other_values); - quote! { - (&[ - #( #values ),* - ]) - } - } else { - Default::default() - }; + quote! { + (&[ + #( #values ),* + ]) + } + } else { + Default::default() + }; value_type_match_lines.push(quote! { Self::#name => AriaValueType::#value_type_variant_name #params @@ -457,13 +446,11 @@ fn generate_aria_attributes(attributes:&BTreeMap) -> Toke } fn generate_aria_roles(aria:&Aria) -> TokenStream { - let aria_abstract_role_names = - aria.roles.iter().filter(|(_, data)| data.is_abstract).map(|(name, _)| name); + let aria_abstract_role_names = aria.roles.iter().filter(|(_, data)| data.is_abstract).map(|(name, _)| name); let aria_abstarct_role_enum = generate_enums(aria_abstract_role_names, "AriaAbstractRole"); - let aria_concrete_role_names = - aria.roles.iter().filter(|(_, data)| !data.is_abstract).map(|(name, _)| name); + let aria_concrete_role_names = aria.roles.iter().filter(|(_, data)| !data.is_abstract).map(|(name, _)| name); let aria_concrete_role_enum = generate_enums(aria_concrete_role_names, "AriaRole"); @@ -499,10 +486,7 @@ fn generate_aria_roles(aria:&Aria) -> TokenStream { variants.clear(); for global_attribute in &data.supported_attributes { - let variant = Ident::new( - &Case::Pascal.convert(&global_attribute.name), - Span::call_site(), - ); + let variant = Ident::new(&Case::Pascal.convert(&global_attribute.name), Span::call_site()); global_attribute_variants.push(variant); } @@ -579,8 +563,7 @@ fn generate_aria_roles(aria:&Aria) -> TokenStream { for (attribute_name, value) in attributes { html_attributes_names.insert(attribute_name.as_str()); - let attribute_name = - format_ident!("{}", Case::Pascal.convert(attribute_name)); + let attribute_name = format_ident!("{}", Case::Pascal.convert(attribute_name)); attribute_instances.push(quote! { HtmlAttributeInstance { @@ -622,8 +605,7 @@ fn generate_aria_roles(aria:&Aria) -> TokenStream { for (attribute_name, value) in attributes { html_attributes_names.insert(attribute_name.as_str()); - let attribute_name = - format_ident!("{}", Case::Pascal.convert(attribute_name)); + let attribute_name = format_ident!("{}", Case::Pascal.convert(attribute_name)); attribute_instances.push(quote! { HtmlAttributeInstance { diff --git a/crates/biome_cli/Source/changed.rs b/crates/biome_cli/Source/changed.rs index 83f7b05571d5..8fe241764019 100644 --- a/crates/biome_cli/Source/changed.rs +++ b/crates/biome_cli/Source/changed.rs @@ -19,8 +19,8 @@ pub(crate) fn get_changed_files( (None, Some(branch)) => branch, (None, None) => { return Err(CliDiagnostic::incompatible_end_configuration( - "The `--changed` flag was set, but Biome couldn't determine the base to compare \ - against. Either set configuration.vcs.defaultBranch or use the --since argument.", + "The `--changed` flag was set, but Biome couldn't determine the base to compare against. Either set \ + configuration.vcs.defaultBranch or use the --since argument.", )); }, }; @@ -32,9 +32,7 @@ pub(crate) fn get_changed_files( Ok(filtered_changed_files) } -pub(crate) fn get_staged_files( - fs:&DynRef<'_, dyn FileSystem>, -) -> Result, CliDiagnostic> { +pub(crate) fn get_staged_files(fs:&DynRef<'_, dyn FileSystem>) -> Result, CliDiagnostic> { let staged_files = fs.get_staged_files()?; let filtered_staged_files = staged_files.iter().map(OsString::from).collect::>(); diff --git a/crates/biome_cli/Source/cli_options.rs b/crates/biome_cli/Source/cli_options.rs index d12357d669dc..789dcf363d7c 100644 --- a/crates/biome_cli/Source/cli_options.rs +++ b/crates/biome_cli/Source/cli_options.rs @@ -227,8 +227,7 @@ impl FromStr for MaxDiagnostics { Ok(MaxDiagnostics::Limit(value)) } else { Err(format!( - "Invalid value provided. Provide 'none' to lift the limit, or a number \ - between 0 and {}.", + "Invalid value provided. Provide 'none' to lift the limit, or a number between 0 and {}.", u32::MAX )) } diff --git a/crates/biome_cli/Source/commands/check.rs b/crates/biome_cli/Source/commands/check.rs index 9ce84944c5db..e79f7f9bfc93 100644 --- a/crates/biome_cli/Source/commands/check.rs +++ b/crates/biome_cli/Source/commands/check.rs @@ -1,162 +1,157 @@ -use super::{determine_fix_file_mode, FixFileModeOptions, LoadEditorConfig}; -use crate::cli_options::CliOptions; -use crate::commands::{get_files_to_process_with_cli_options, CommandRunner}; -use crate::{CliDiagnostic, Execution, TraversalMode}; -use biome_configuration::analyzer::assists::PartialAssistsConfiguration; +use std::ffi::OsString; + use biome_configuration::{ - organize_imports::PartialOrganizeImports, PartialConfiguration, PartialFormatterConfiguration, - PartialLinterConfiguration, + PartialConfiguration, + PartialFormatterConfiguration, + PartialLinterConfiguration, + analyzer::assists::PartialAssistsConfiguration, + organize_imports::PartialOrganizeImports, }; use biome_console::Console; use biome_deserialize::Merge; use biome_fs::FileSystem; -use biome_service::{configuration::LoadedConfiguration, DynRef, Workspace, WorkspaceError}; -use std::ffi::OsString; +use biome_service::{DynRef, Workspace, WorkspaceError, configuration::LoadedConfiguration}; + +use super::{FixFileModeOptions, LoadEditorConfig, determine_fix_file_mode}; +use crate::{ + CliDiagnostic, + Execution, + TraversalMode, + cli_options::CliOptions, + commands::{CommandRunner, get_files_to_process_with_cli_options}, +}; pub(crate) struct CheckCommandPayload { - pub(crate) apply: bool, - pub(crate) apply_unsafe: bool, - pub(crate) write: bool, - pub(crate) fix: bool, - pub(crate) unsafe_: bool, - pub(crate) configuration: Option, - pub(crate) paths: Vec, - pub(crate) stdin_file_path: Option, - pub(crate) formatter_enabled: Option, - pub(crate) linter_enabled: Option, - pub(crate) organize_imports_enabled: Option, - pub(crate) assists_enabled: Option, - pub(crate) staged: bool, - pub(crate) changed: bool, - pub(crate) since: Option, + pub(crate) apply:bool, + pub(crate) apply_unsafe:bool, + pub(crate) write:bool, + pub(crate) fix:bool, + pub(crate) unsafe_:bool, + pub(crate) configuration:Option, + pub(crate) paths:Vec, + pub(crate) stdin_file_path:Option, + pub(crate) formatter_enabled:Option, + pub(crate) linter_enabled:Option, + pub(crate) organize_imports_enabled:Option, + pub(crate) assists_enabled:Option, + pub(crate) staged:bool, + pub(crate) changed:bool, + pub(crate) since:Option, } impl LoadEditorConfig for CheckCommandPayload { - fn should_load_editor_config(&self, fs_configuration: &PartialConfiguration) -> bool { - self.configuration - .as_ref() - .and_then(|c| c.use_editorconfig()) - .unwrap_or(fs_configuration.use_editorconfig().unwrap_or_default()) - } + fn should_load_editor_config(&self, fs_configuration:&PartialConfiguration) -> bool { + self.configuration + .as_ref() + .and_then(|c| c.use_editorconfig()) + .unwrap_or(fs_configuration.use_editorconfig().unwrap_or_default()) + } } impl CommandRunner for CheckCommandPayload { - const COMMAND_NAME: &'static str = "check"; - - fn merge_configuration( - &mut self, - loaded_configuration: LoadedConfiguration, - fs: &DynRef<'_, dyn FileSystem>, - console: &mut dyn Console, - ) -> Result { - let editorconfig_search_path = loaded_configuration.directory_path.clone(); - - let LoadedConfiguration { - configuration: biome_configuration, - .. - } = loaded_configuration; - - let mut fs_configuration = - self.load_editor_config(editorconfig_search_path, &biome_configuration, fs, console)?; - // this makes biome configuration take precedence over editorconfig configuration - fs_configuration.merge_with(biome_configuration); - - let formatter = fs_configuration - .formatter - .get_or_insert_with(PartialFormatterConfiguration::default); - - if self.formatter_enabled.is_some() { - formatter.enabled = self.formatter_enabled; - } - - let linter = fs_configuration - .linter - .get_or_insert_with(PartialLinterConfiguration::default); - - if self.linter_enabled.is_some() { - linter.enabled = self.linter_enabled; - } - - let organize_imports = fs_configuration - .organize_imports - .get_or_insert_with(PartialOrganizeImports::default); - - if self.organize_imports_enabled.is_some() { - organize_imports.enabled = self.organize_imports_enabled; - } - - let assists = fs_configuration - .assists - .get_or_insert_with(PartialAssistsConfiguration::default); - - if self.assists_enabled.is_some() { - assists.enabled = self.assists_enabled; - } - - if let Some(mut configuration) = self.configuration.clone() { - if let Some(linter) = configuration.linter.as_mut() { - // Don't overwrite rules from the CLI configuration. - // Otherwise, rules that are disabled in the config file might - // become re-enabled due to the defaults included in the CLI - // configuration. - linter.rules = None; - } - - fs_configuration.merge_with(configuration); - } - - Ok(fs_configuration) - } - - fn get_files_to_process( - &self, - fs: &DynRef<'_, dyn FileSystem>, - configuration: &PartialConfiguration, - ) -> Result, CliDiagnostic> { - let paths = get_files_to_process_with_cli_options( - self.since.as_deref(), - self.changed, - self.staged, - fs, - configuration, - )? - .unwrap_or(self.paths.clone()); - - Ok(paths) - } - - fn get_stdin_file_path(&self) -> Option<&str> { - self.stdin_file_path.as_deref() - } - - fn should_write(&self) -> bool { - self.write || self.fix - } - - fn get_execution( - &self, - cli_options: &CliOptions, - console: &mut dyn Console, - _workspace: &dyn Workspace, - ) -> Result { - let fix_file_mode = determine_fix_file_mode( - FixFileModeOptions { - apply: self.apply, - apply_unsafe: self.apply_unsafe, - write: self.write, - suppress: false, - suppression_reason: None, - fix: self.fix, - unsafe_: self.unsafe_, - }, - console, - )?; - - Ok(Execution::new(TraversalMode::Check { - fix_file_mode, - stdin: self.get_stdin(console)?, - vcs_targeted: (self.staged, self.changed).into(), - }) - .set_report(cli_options)) - } + const COMMAND_NAME:&'static str = "check"; + + fn merge_configuration( + &mut self, + loaded_configuration:LoadedConfiguration, + fs:&DynRef<'_, dyn FileSystem>, + console:&mut dyn Console, + ) -> Result { + let editorconfig_search_path = loaded_configuration.directory_path.clone(); + + let LoadedConfiguration { configuration: biome_configuration, .. } = loaded_configuration; + + let mut fs_configuration = + self.load_editor_config(editorconfig_search_path, &biome_configuration, fs, console)?; + // this makes biome configuration take precedence over editorconfig + // configuration + fs_configuration.merge_with(biome_configuration); + + let formatter = fs_configuration + .formatter + .get_or_insert_with(PartialFormatterConfiguration::default); + + if self.formatter_enabled.is_some() { + formatter.enabled = self.formatter_enabled; + } + + let linter = fs_configuration.linter.get_or_insert_with(PartialLinterConfiguration::default); + + if self.linter_enabled.is_some() { + linter.enabled = self.linter_enabled; + } + + let organize_imports = fs_configuration + .organize_imports + .get_or_insert_with(PartialOrganizeImports::default); + + if self.organize_imports_enabled.is_some() { + organize_imports.enabled = self.organize_imports_enabled; + } + + let assists = fs_configuration + .assists + .get_or_insert_with(PartialAssistsConfiguration::default); + + if self.assists_enabled.is_some() { + assists.enabled = self.assists_enabled; + } + + if let Some(mut configuration) = self.configuration.clone() { + if let Some(linter) = configuration.linter.as_mut() { + // Don't overwrite rules from the CLI configuration. + // Otherwise, rules that are disabled in the config file might + // become re-enabled due to the defaults included in the CLI + // configuration. + linter.rules = None; + } + + fs_configuration.merge_with(configuration); + } + + Ok(fs_configuration) + } + + fn get_files_to_process( + &self, + fs:&DynRef<'_, dyn FileSystem>, + configuration:&PartialConfiguration, + ) -> Result, CliDiagnostic> { + let paths = + get_files_to_process_with_cli_options(self.since.as_deref(), self.changed, self.staged, fs, configuration)? + .unwrap_or(self.paths.clone()); + + Ok(paths) + } + + fn get_stdin_file_path(&self) -> Option<&str> { self.stdin_file_path.as_deref() } + + fn should_write(&self) -> bool { self.write || self.fix } + + fn get_execution( + &self, + cli_options:&CliOptions, + console:&mut dyn Console, + _workspace:&dyn Workspace, + ) -> Result { + let fix_file_mode = determine_fix_file_mode( + FixFileModeOptions { + apply:self.apply, + apply_unsafe:self.apply_unsafe, + write:self.write, + suppress:false, + suppression_reason:None, + fix:self.fix, + unsafe_:self.unsafe_, + }, + console, + )?; + + Ok(Execution::new(TraversalMode::Check { + fix_file_mode, + stdin:self.get_stdin(console)?, + vcs_targeted:(self.staged, self.changed).into(), + }) + .set_report(cli_options)) + } } diff --git a/crates/biome_cli/Source/commands/ci.rs b/crates/biome_cli/Source/commands/ci.rs index 0b7a6594d6fa..db018e2f3e9d 100644 --- a/crates/biome_cli/Source/commands/ci.rs +++ b/crates/biome_cli/Source/commands/ci.rs @@ -1,145 +1,147 @@ -use crate::changed::get_changed_files; -use crate::cli_options::CliOptions; -use crate::commands::{CommandRunner, LoadEditorConfig}; -use crate::{CliDiagnostic, Execution}; -use biome_configuration::analyzer::assists::PartialAssistsConfiguration; -use biome_configuration::{organize_imports::PartialOrganizeImports, PartialConfiguration}; -use biome_configuration::{PartialFormatterConfiguration, PartialLinterConfiguration}; +use std::ffi::OsString; + +use biome_configuration::{ + PartialConfiguration, + PartialFormatterConfiguration, + PartialLinterConfiguration, + analyzer::assists::PartialAssistsConfiguration, + organize_imports::PartialOrganizeImports, +}; use biome_console::Console; use biome_deserialize::Merge; use biome_fs::FileSystem; -use biome_service::configuration::LoadedConfiguration; -use biome_service::{DynRef, Workspace, WorkspaceError}; -use std::ffi::OsString; +use biome_service::{DynRef, Workspace, WorkspaceError, configuration::LoadedConfiguration}; + +use crate::{ + CliDiagnostic, + Execution, + changed::get_changed_files, + cli_options::CliOptions, + commands::{CommandRunner, LoadEditorConfig}, +}; pub(crate) struct CiCommandPayload { - pub(crate) formatter_enabled: Option, - pub(crate) linter_enabled: Option, - pub(crate) organize_imports_enabled: Option, - pub(crate) assists_enabled: Option, - pub(crate) paths: Vec, - pub(crate) configuration: Option, - pub(crate) changed: bool, - pub(crate) since: Option, + pub(crate) formatter_enabled:Option, + pub(crate) linter_enabled:Option, + pub(crate) organize_imports_enabled:Option, + pub(crate) assists_enabled:Option, + pub(crate) paths:Vec, + pub(crate) configuration:Option, + pub(crate) changed:bool, + pub(crate) since:Option, } impl LoadEditorConfig for CiCommandPayload { - fn should_load_editor_config(&self, fs_configuration: &PartialConfiguration) -> bool { - self.configuration - .as_ref() - .and_then(|c| c.use_editorconfig()) - .unwrap_or(fs_configuration.use_editorconfig().unwrap_or_default()) - } + fn should_load_editor_config(&self, fs_configuration:&PartialConfiguration) -> bool { + self.configuration + .as_ref() + .and_then(|c| c.use_editorconfig()) + .unwrap_or(fs_configuration.use_editorconfig().unwrap_or_default()) + } } impl CommandRunner for CiCommandPayload { - const COMMAND_NAME: &'static str = "ci"; - - fn merge_configuration( - &mut self, - loaded_configuration: LoadedConfiguration, - fs: &DynRef<'_, dyn FileSystem>, - console: &mut dyn Console, - ) -> Result { - let LoadedConfiguration { - configuration: biome_configuration, - directory_path: configuration_path, - .. - } = loaded_configuration; - - let mut fs_configuration = - self.load_editor_config(configuration_path, &biome_configuration, fs, console)?; - // this makes biome configuration take precedence over editorconfig configuration - fs_configuration.merge_with(biome_configuration); - - let formatter = fs_configuration - .formatter - .get_or_insert_with(PartialFormatterConfiguration::default); - - if self.formatter_enabled.is_some() { - formatter.enabled = self.formatter_enabled; - } - - let linter = fs_configuration - .linter - .get_or_insert_with(PartialLinterConfiguration::default); - - if self.linter_enabled.is_some() { - linter.enabled = self.linter_enabled; - } - - let organize_imports = fs_configuration - .organize_imports - .get_or_insert_with(PartialOrganizeImports::default); - - if self.organize_imports_enabled.is_some() { - organize_imports.enabled = self.organize_imports_enabled; - } - - let assists = fs_configuration - .assists - .get_or_insert_with(PartialAssistsConfiguration::default); - - if self.assists_enabled.is_some() { - assists.enabled = self.assists_enabled; - } - - if let Some(mut configuration) = self.configuration.clone() { - if let Some(linter) = configuration.linter.as_mut() { - // Don't overwrite rules from the CLI configuration. - // Otherwise, rules that are disabled in the config file might - // become re-enabled due to the defaults included in the CLI - // configuration. - linter.rules = None; - } - - fs_configuration.merge_with(configuration); - } - - Ok(fs_configuration) - } - - fn get_files_to_process( - &self, - fs: &DynRef<'_, dyn FileSystem>, - configuration: &PartialConfiguration, - ) -> Result, CliDiagnostic> { - if self.changed { - get_changed_files(fs, configuration, self.since.as_deref()) - } else { - Ok(self.paths.clone()) - } - } - - fn get_stdin_file_path(&self) -> Option<&str> { - None - } - - fn should_write(&self) -> bool { - false - } - - fn get_execution( - &self, - cli_options: &CliOptions, - _console: &mut dyn Console, - _workspace: &dyn Workspace, - ) -> Result { - Ok(Execution::new_ci((false, self.changed).into()).set_report(cli_options)) - } - - fn check_incompatible_arguments(&self) -> Result<(), CliDiagnostic> { - if matches!(self.formatter_enabled, Some(false)) - && matches!(self.linter_enabled, Some(false)) - && matches!(self.organize_imports_enabled, Some(false)) - { - return Err(CliDiagnostic::incompatible_end_configuration("Formatter, linter and organize imports are disabled, can't perform the command. At least one feature needs to be enabled. This is probably and error.")); - } - - if self.since.is_some() && !self.changed { - return Err(CliDiagnostic::incompatible_arguments("since", "changed")); - } - - Ok(()) - } + const COMMAND_NAME:&'static str = "ci"; + + fn merge_configuration( + &mut self, + loaded_configuration:LoadedConfiguration, + fs:&DynRef<'_, dyn FileSystem>, + console:&mut dyn Console, + ) -> Result { + let LoadedConfiguration { configuration: biome_configuration, directory_path: configuration_path, .. } = + loaded_configuration; + + let mut fs_configuration = self.load_editor_config(configuration_path, &biome_configuration, fs, console)?; + // this makes biome configuration take precedence over editorconfig + // configuration + fs_configuration.merge_with(biome_configuration); + + let formatter = fs_configuration + .formatter + .get_or_insert_with(PartialFormatterConfiguration::default); + + if self.formatter_enabled.is_some() { + formatter.enabled = self.formatter_enabled; + } + + let linter = fs_configuration.linter.get_or_insert_with(PartialLinterConfiguration::default); + + if self.linter_enabled.is_some() { + linter.enabled = self.linter_enabled; + } + + let organize_imports = fs_configuration + .organize_imports + .get_or_insert_with(PartialOrganizeImports::default); + + if self.organize_imports_enabled.is_some() { + organize_imports.enabled = self.organize_imports_enabled; + } + + let assists = fs_configuration + .assists + .get_or_insert_with(PartialAssistsConfiguration::default); + + if self.assists_enabled.is_some() { + assists.enabled = self.assists_enabled; + } + + if let Some(mut configuration) = self.configuration.clone() { + if let Some(linter) = configuration.linter.as_mut() { + // Don't overwrite rules from the CLI configuration. + // Otherwise, rules that are disabled in the config file might + // become re-enabled due to the defaults included in the CLI + // configuration. + linter.rules = None; + } + + fs_configuration.merge_with(configuration); + } + + Ok(fs_configuration) + } + + fn get_files_to_process( + &self, + fs:&DynRef<'_, dyn FileSystem>, + configuration:&PartialConfiguration, + ) -> Result, CliDiagnostic> { + if self.changed { + get_changed_files(fs, configuration, self.since.as_deref()) + } else { + Ok(self.paths.clone()) + } + } + + fn get_stdin_file_path(&self) -> Option<&str> { None } + + fn should_write(&self) -> bool { false } + + fn get_execution( + &self, + cli_options:&CliOptions, + _console:&mut dyn Console, + _workspace:&dyn Workspace, + ) -> Result { + Ok(Execution::new_ci((false, self.changed).into()).set_report(cli_options)) + } + + fn check_incompatible_arguments(&self) -> Result<(), CliDiagnostic> { + if matches!(self.formatter_enabled, Some(false)) + && matches!(self.linter_enabled, Some(false)) + && matches!(self.organize_imports_enabled, Some(false)) + { + return Err(CliDiagnostic::incompatible_end_configuration( + "Formatter, linter and organize imports are disabled, can't perform the command. At least one feature \ + needs to be enabled. This is probably and error.", + )); + } + + if self.since.is_some() && !self.changed { + return Err(CliDiagnostic::incompatible_arguments("since", "changed")); + } + + Ok(()) + } } diff --git a/crates/biome_cli/Source/commands/clean.rs b/crates/biome_cli/Source/commands/clean.rs index 2fed9ed23870..fa917d600a8c 100644 --- a/crates/biome_cli/Source/commands/clean.rs +++ b/crates/biome_cli/Source/commands/clean.rs @@ -1,17 +1,20 @@ -use crate::commands::daemon::default_biome_log_path; -use crate::{CliDiagnostic, CliSession}; +use std::{ + fs::{create_dir, remove_dir_all}, + path::PathBuf, +}; + use biome_flags::biome_env; -use std::fs::{create_dir, remove_dir_all}; -use std::path::PathBuf; + +use crate::{CliDiagnostic, CliSession, commands::daemon::default_biome_log_path}; /// Runs the clean command -pub fn clean(_cli_session: CliSession) -> Result<(), CliDiagnostic> { - let logs_path = biome_env() - .biome_log_path - .value() - .map_or(default_biome_log_path(), PathBuf::from); +pub fn clean(_cli_session:CliSession) -> Result<(), CliDiagnostic> { + let logs_path = biome_env() + .biome_log_path + .value() + .map_or(default_biome_log_path(), PathBuf::from); - remove_dir_all(logs_path.clone()).and_then(|_| create_dir(logs_path))?; + remove_dir_all(logs_path.clone()).and_then(|_| create_dir(logs_path))?; - Ok(()) + Ok(()) } diff --git a/crates/biome_cli/Source/commands/daemon.rs b/crates/biome_cli/Source/commands/daemon.rs index 4d2569f2b036..9a0b12c6613d 100644 --- a/crates/biome_cli/Source/commands/daemon.rs +++ b/crates/biome_cli/Source/commands/daemon.rs @@ -1,220 +1,208 @@ -use crate::{ - open_transport, - service::{self, ensure_daemon, open_socket, run_daemon}, - CliDiagnostic, CliSession, -}; -use biome_console::{markup, ConsoleExt}; -use biome_lsp::ServerFactory; -use biome_service::{workspace::WorkspaceClient, TransportError, WorkspaceError}; use std::{env, fs, path::PathBuf}; -use tokio::io; -use tokio::runtime::Runtime; -use tracing::subscriber::Interest; -use tracing::{debug_span, metadata::LevelFilter, Instrument, Metadata}; + +use biome_console::{ConsoleExt, markup}; +use biome_lsp::ServerFactory; +use biome_service::{TransportError, WorkspaceError, workspace::WorkspaceClient}; +use tokio::{io, runtime::Runtime}; +use tracing::{Instrument, Metadata, debug_span, metadata::LevelFilter, subscriber::Interest}; use tracing_appender::rolling::Rotation; use tracing_subscriber::{ - layer::{Context, Filter}, - prelude::*, - registry, Layer, + Layer, + layer::{Context, Filter}, + prelude::*, + registry, }; use tracing_tree::HierarchicalLayer; +use crate::{ + CliDiagnostic, + CliSession, + open_transport, + service::{self, ensure_daemon, open_socket, run_daemon}, +}; + pub(crate) fn start( - session: CliSession, - config_path: Option, - log_path: Option, - log_file_name_prefix: Option, + session:CliSession, + config_path:Option, + log_path:Option, + log_file_name_prefix:Option, ) -> Result<(), CliDiagnostic> { - let rt = Runtime::new()?; - - let did_spawn = rt.block_on(ensure_daemon( - false, - config_path, - log_path, - log_file_name_prefix, - ))?; - - if did_spawn { - session.app.console.log(markup! { - "The Biome server was successfully started" - }); - } else { - session.app.console.log(markup! { - "The Biome server was already running" - }); - } - - Ok(()) + let rt = Runtime::new()?; + + let did_spawn = rt.block_on(ensure_daemon(false, config_path, log_path, log_file_name_prefix))?; + + if did_spawn { + session.app.console.log(markup! { + "The Biome server was successfully started" + }); + } else { + session.app.console.log(markup! { + "The Biome server was already running" + }); + } + + Ok(()) } -pub(crate) fn stop(session: CliSession) -> Result<(), CliDiagnostic> { - let rt = Runtime::new()?; +pub(crate) fn stop(session:CliSession) -> Result<(), CliDiagnostic> { + let rt = Runtime::new()?; - if let Some(transport) = open_transport(rt)? { - let client = WorkspaceClient::new(transport)?; + if let Some(transport) = open_transport(rt)? { + let client = WorkspaceClient::new(transport)?; - match client.shutdown() { - // The `ChannelClosed` error is expected since the server can - // shutdown before sending a response - Ok(()) | Err(WorkspaceError::TransportError(TransportError::ChannelClosed)) => {} + match client.shutdown() { + // The `ChannelClosed` error is expected since the server can + // shutdown before sending a response + Ok(()) | Err(WorkspaceError::TransportError(TransportError::ChannelClosed)) => {}, - Err(err) => return Err(CliDiagnostic::from(err)), - }; + Err(err) => return Err(CliDiagnostic::from(err)), + }; - session.app.console.log(markup! { - "The Biome server was successfully stopped" - }); - } else { - session.app.console.log(markup! { - "The Biome server was not running" - }); - } + session.app.console.log(markup! { + "The Biome server was successfully stopped" + }); + } else { + session.app.console.log(markup! { + "The Biome server was not running" + }); + } - Ok(()) + Ok(()) } pub(crate) fn run_server( - stop_on_disconnect: bool, - config_path: Option, - log_path: Option, - log_file_name_prefix: Option, + stop_on_disconnect:bool, + config_path:Option, + log_path:Option, + log_file_name_prefix:Option, ) -> Result<(), CliDiagnostic> { - setup_tracing_subscriber(log_path, log_file_name_prefix); + setup_tracing_subscriber(log_path, log_file_name_prefix); - let rt = Runtime::new()?; + let rt = Runtime::new()?; - let factory = ServerFactory::new(stop_on_disconnect); + let factory = ServerFactory::new(stop_on_disconnect); - let cancellation = factory.cancellation(); + let cancellation = factory.cancellation(); - let span = debug_span!("Running Server", pid = std::process::id()); + let span = debug_span!("Running Server", pid = std::process::id()); - rt.block_on(async move { - tokio::select! { - res = run_daemon(factory, config_path).instrument(span) => { - match res { - Ok(never) => match never {}, - Err(err) => Err(err.into()), - } - } + rt.block_on(async move { + tokio::select! { + res = run_daemon(factory, config_path).instrument(span) => { + match res { + Ok(never) => match never {}, + Err(err) => Err(err.into()), + } + } - _ = cancellation.notified() => { - tracing::info!("Received shutdown signal"); + _ = cancellation.notified() => { + tracing::info!("Received shutdown signal"); - Ok(()) - } - } - }) + Ok(()) + } + } + }) } pub(crate) fn print_socket() -> Result<(), CliDiagnostic> { - let rt = Runtime::new()?; + let rt = Runtime::new()?; - rt.block_on(service::print_socket())?; + rt.block_on(service::print_socket())?; - Ok(()) + Ok(()) } pub(crate) fn lsp_proxy( - config_path: Option, - log_path: Option, - log_file_name_prefix: Option, + config_path:Option, + log_path:Option, + log_file_name_prefix:Option, ) -> Result<(), CliDiagnostic> { - let rt = Runtime::new()?; + let rt = Runtime::new()?; - rt.block_on(start_lsp_proxy( - &rt, - config_path, - log_path, - log_file_name_prefix, - ))?; + rt.block_on(start_lsp_proxy(&rt, config_path, log_path, log_file_name_prefix))?; - Ok(()) + Ok(()) } /// Start a proxy process. /// Receives a process via `stdin` and then copy the content to the LSP socket. /// Copy to the process on `stdout` when the LSP responds to a message async fn start_lsp_proxy( - rt: &Runtime, - config_path: Option, - log_path: Option, - log_file_name_prefix: Option, + rt:&Runtime, + config_path:Option, + log_path:Option, + log_file_name_prefix:Option, ) -> Result<(), CliDiagnostic> { - ensure_daemon(true, config_path, log_path, log_file_name_prefix).await?; - - match open_socket().await? { - Some((mut owned_read_half, mut owned_write_half)) => { - // forward stdin to socket - let mut stdin = io::stdin(); - - let input_handle = rt.spawn(async move { - loop { - match io::copy(&mut stdin, &mut owned_write_half).await { - Ok(b) => { - if b == 0 { - return Ok(()); - } - } - - Err(err) => return Err(err), - }; - } - }); - - // receive socket response to stdout - let mut stdout = io::stdout(); - - let out_put_handle = rt.spawn(async move { - loop { - match io::copy(&mut owned_read_half, &mut stdout).await { - Ok(b) => { - if b == 0 { - return Ok(()); - } - } - - Err(err) => return Err(err), - }; - } - }); - - let _ = input_handle.await; - - let _ = out_put_handle.await; - - Ok(()) - } - - None => Ok(()), - } + ensure_daemon(true, config_path, log_path, log_file_name_prefix).await?; + + match open_socket().await? { + Some((mut owned_read_half, mut owned_write_half)) => { + // forward stdin to socket + let mut stdin = io::stdin(); + + let input_handle = rt.spawn(async move { + loop { + match io::copy(&mut stdin, &mut owned_write_half).await { + Ok(b) => { + if b == 0 { + return Ok(()); + } + }, + + Err(err) => return Err(err), + }; + } + }); + + // receive socket response to stdout + let mut stdout = io::stdout(); + + let out_put_handle = rt.spawn(async move { + loop { + match io::copy(&mut owned_read_half, &mut stdout).await { + Ok(b) => { + if b == 0 { + return Ok(()); + } + }, + + Err(err) => return Err(err), + }; + } + }); + + let _ = input_handle.await; + + let _ = out_put_handle.await; + + Ok(()) + }, + + None => Ok(()), + } } pub(crate) fn read_most_recent_log_file( - log_path: Option, - log_file_name_prefix: String, + log_path:Option, + log_file_name_prefix:String, ) -> io::Result> { - let biome_log_path = log_path.unwrap_or(default_biome_log_path()); - - let most_recent = fs::read_dir(biome_log_path)? - .flatten() - .filter(|file| file.file_type().map_or(false, |ty| ty.is_file())) - .filter_map(|file| { - match file - .file_name() - .to_str()? - .split_once(log_file_name_prefix.as_str()) - { - Some((_, date_part)) if date_part.split('-').count() == 4 => Some(file.path()), - _ => None, - } - }) - .max(); - - match most_recent { - Some(file) => Ok(Some(fs::read_to_string(file)?)), - None => Ok(None), - } + let biome_log_path = log_path.unwrap_or(default_biome_log_path()); + + let most_recent = fs::read_dir(biome_log_path)? + .flatten() + .filter(|file| file.file_type().map_or(false, |ty| ty.is_file())) + .filter_map(|file| { + match file.file_name().to_str()?.split_once(log_file_name_prefix.as_str()) { + Some((_, date_part)) if date_part.split('-').count() == 4 => Some(file.path()), + _ => None, + } + }) + .max(); + + match most_recent { + Some(file) => Ok(Some(fs::read_to_string(file)?)), + None => Ok(None), + } } /// Set up the [tracing]-based logging system for the server @@ -223,81 +211,68 @@ pub(crate) fn read_most_recent_log_file( /// is written to log files rotated on a hourly basis (in /// `biome-logs/server.log.yyyy-MM-dd-HH` files inside the system temporary /// directory) -fn setup_tracing_subscriber(log_path: Option, log_file_name_prefix: Option) { - let biome_log_path = log_path.unwrap_or(biome_fs::ensure_cache_dir().join("biome-logs")); - - let appender_builder = tracing_appender::rolling::RollingFileAppender::builder(); - - let file_appender = appender_builder - .filename_prefix(log_file_name_prefix.unwrap_or(String::from("server.log"))) - .max_log_files(7) - .rotation(Rotation::HOURLY) - .build(biome_log_path) - .expect("Failed to start the logger for the daemon."); - - registry() - .with( - HierarchicalLayer::default() - .with_indent_lines(true) - .with_indent_amount(2) - .with_bracketed_fields(true) - .with_targets(true) - .with_ansi(false) - .with_writer(file_appender) - .with_filter(LoggingFilter), - ) - .init(); +fn setup_tracing_subscriber(log_path:Option, log_file_name_prefix:Option) { + let biome_log_path = log_path.unwrap_or(biome_fs::ensure_cache_dir().join("biome-logs")); + + let appender_builder = tracing_appender::rolling::RollingFileAppender::builder(); + + let file_appender = appender_builder + .filename_prefix(log_file_name_prefix.unwrap_or(String::from("server.log"))) + .max_log_files(7) + .rotation(Rotation::HOURLY) + .build(biome_log_path) + .expect("Failed to start the logger for the daemon."); + + registry() + .with( + HierarchicalLayer::default() + .with_indent_lines(true) + .with_indent_amount(2) + .with_bracketed_fields(true) + .with_targets(true) + .with_ansi(false) + .with_writer(file_appender) + .with_filter(LoggingFilter), + ) + .init(); } pub fn default_biome_log_path() -> PathBuf { - match env::var_os("BIOME_LOG_PATH") { - Some(directory) => PathBuf::from(directory), - // TODO: Remove in Biome v2, and use the None part as fallback. - None => match env::var_os("BIOME_LOG_DIR") { - Some(directory) => PathBuf::from(directory), - None => biome_fs::ensure_cache_dir().join("biome-logs"), - }, - } + match env::var_os("BIOME_LOG_PATH") { + Some(directory) => PathBuf::from(directory), + // TODO: Remove in Biome v2, and use the None part as fallback. + None => { + match env::var_os("BIOME_LOG_DIR") { + Some(directory) => PathBuf::from(directory), + None => biome_fs::ensure_cache_dir().join("biome-logs"), + } + }, + } } /// Tracing filter enabling: /// - All spans and events at level info or higher -/// - All spans and events at level debug in crates whose name starts with `biome` +/// - All spans and events at level debug in crates whose name starts with +/// `biome` struct LoggingFilter; /// Tracing filter used for spans emitted by `biome*` crates -const SELF_FILTER: LevelFilter = if cfg!(debug_assertions) { - LevelFilter::TRACE -} else { - LevelFilter::DEBUG -}; +const SELF_FILTER:LevelFilter = if cfg!(debug_assertions) { LevelFilter::TRACE } else { LevelFilter::DEBUG }; impl LoggingFilter { - fn is_enabled(&self, meta: &Metadata<'_>) -> bool { - let filter = if meta.target().starts_with("biome") { - SELF_FILTER - } else { - LevelFilter::INFO - }; - - meta.level() <= &filter - } + fn is_enabled(&self, meta:&Metadata<'_>) -> bool { + let filter = if meta.target().starts_with("biome") { SELF_FILTER } else { LevelFilter::INFO }; + + meta.level() <= &filter + } } impl Filter for LoggingFilter { - fn enabled(&self, meta: &Metadata<'_>, _cx: &Context<'_, S>) -> bool { - self.is_enabled(meta) - } - - fn callsite_enabled(&self, meta: &'static Metadata<'static>) -> Interest { - if self.is_enabled(meta) { - Interest::always() - } else { - Interest::never() - } - } - - fn max_level_hint(&self) -> Option { - Some(SELF_FILTER) - } + fn enabled(&self, meta:&Metadata<'_>, _cx:&Context<'_, S>) -> bool { self.is_enabled(meta) } + + fn callsite_enabled(&self, meta:&'static Metadata<'static>) -> Interest { + if self.is_enabled(meta) { Interest::always() } else { Interest::never() } + } + + fn max_level_hint(&self) -> Option { Some(SELF_FILTER) } } diff --git a/crates/biome_cli/Source/commands/explain.rs b/crates/biome_cli/Source/commands/explain.rs index e0d22646434c..71fc0f10cf49 100644 --- a/crates/biome_cli/Source/commands/explain.rs +++ b/crates/biome_cli/Source/commands/explain.rs @@ -1,68 +1,67 @@ use biome_analyze::{FixKind, RuleMetadata}; -use biome_console::{markup, ConsoleExt}; +use biome_console::{ConsoleExt, markup}; use biome_flags::biome_env; use biome_service::documentation::Doc; -use crate::commands::daemon::default_biome_log_path; -use crate::{CliDiagnostic, CliSession}; +use crate::{CliDiagnostic, CliSession, commands::daemon::default_biome_log_path}; -fn print_rule(session: CliSession, metadata: &RuleMetadata) { - session.app.console.log(markup! { - "# "{metadata.name}"\n" - }); +fn print_rule(session:CliSession, metadata:&RuleMetadata) { + session.app.console.log(markup! { + "# "{metadata.name}"\n" + }); - match metadata.fix_kind { - FixKind::None => { - session.app.console.log(markup! { - "No fix available.\n" - }); - } + match metadata.fix_kind { + FixKind::None => { + session.app.console.log(markup! { + "No fix available.\n" + }); + }, - kind => { - session.app.console.log(markup! { - "Fix is "{kind}".\n" - }); - } - } + kind => { + session.app.console.log(markup! { + "Fix is "{kind}".\n" + }); + }, + } - let docs = metadata - .docs - .lines() - .map(|line| line.trim_start()) - .collect::>() - .join("\n"); + let docs = metadata + .docs + .lines() + .map(|line| line.trim_start()) + .collect::>() + .join("\n"); - session.app.console.log(markup! { - "This rule is "{if metadata.recommended {"recommended."} else {"not recommended."}} - "\n\n" - "# Description\n" - {docs} - }); + session.app.console.log(markup! { + "This rule is "{if metadata.recommended {"recommended."} else {"not recommended."}} + "\n\n" + "# Description\n" + {docs} + }); } -pub(crate) fn explain(session: CliSession, doc: Doc) -> Result<(), CliDiagnostic> { - match doc { - Doc::Rule(metadata) => { - print_rule(session, &metadata); +pub(crate) fn explain(session:CliSession, doc:Doc) -> Result<(), CliDiagnostic> { + match doc { + Doc::Rule(metadata) => { + print_rule(session, &metadata); - Ok(()) - } + Ok(()) + }, - Doc::DaemonLogs => { - let cache_dir = biome_env() - .biome_log_path - .value() - .unwrap_or(default_biome_log_path().display().to_string()); + Doc::DaemonLogs => { + let cache_dir = biome_env() + .biome_log_path + .value() + .unwrap_or(default_biome_log_path().display().to_string()); - session.app.console.error(markup! { - "The daemon logs are available in the directory: \n" - }); + session.app.console.error(markup! { + "The daemon logs are available in the directory: \n" + }); - session.app.console.log(markup! {{cache_dir}}); + session.app.console.log(markup! {{cache_dir}}); - Ok(()) - } + Ok(()) + }, - Doc::Unknown(arg) => Err(CliDiagnostic::unexpected_argument(arg, "explain")), - } + Doc::Unknown(arg) => Err(CliDiagnostic::unexpected_argument(arg, "explain")), + } } diff --git a/crates/biome_cli/Source/commands/format.rs b/crates/biome_cli/Source/commands/format.rs index 815dbe5f91b3..df8201209140 100644 --- a/crates/biome_cli/Source/commands/format.rs +++ b/crates/biome_cli/Source/commands/format.rs @@ -1,223 +1,215 @@ -use crate::cli_options::CliOptions; -use crate::commands::{get_files_to_process_with_cli_options, CommandRunner, LoadEditorConfig}; -use crate::diagnostics::DeprecatedArgument; -use crate::{CliDiagnostic, Execution, TraversalMode}; -use biome_configuration::vcs::PartialVcsConfiguration; +use std::ffi::OsString; + use biome_configuration::{ - PartialConfiguration, PartialCssFormatter, PartialFilesConfiguration, - PartialFormatterConfiguration, PartialGraphqlFormatter, PartialJavascriptFormatter, - PartialJsonFormatter, + PartialConfiguration, + PartialCssFormatter, + PartialFilesConfiguration, + PartialFormatterConfiguration, + PartialGraphqlFormatter, + PartialJavascriptFormatter, + PartialJsonFormatter, + vcs::PartialVcsConfiguration, }; -use biome_console::{markup, Console, ConsoleExt}; +use biome_console::{Console, ConsoleExt, markup}; use biome_deserialize::Merge; use biome_diagnostics::PrintDiagnostic; use biome_fs::FileSystem; -use biome_service::configuration::LoadedConfiguration; -use biome_service::{DynRef, Workspace, WorkspaceError}; -use std::ffi::OsString; +use biome_service::{DynRef, Workspace, WorkspaceError, configuration::LoadedConfiguration}; + +use crate::{ + CliDiagnostic, + Execution, + TraversalMode, + cli_options::CliOptions, + commands::{CommandRunner, LoadEditorConfig, get_files_to_process_with_cli_options}, + diagnostics::DeprecatedArgument, +}; pub(crate) struct FormatCommandPayload { - pub(crate) javascript_formatter: Option, - pub(crate) json_formatter: Option, - pub(crate) css_formatter: Option, - pub(crate) graphql_formatter: Option, - pub(crate) formatter_configuration: Option, - pub(crate) vcs_configuration: Option, - pub(crate) files_configuration: Option, - pub(crate) stdin_file_path: Option, - pub(crate) write: bool, - pub(crate) fix: bool, - pub(crate) paths: Vec, - pub(crate) staged: bool, - pub(crate) changed: bool, - pub(crate) since: Option, + pub(crate) javascript_formatter:Option, + pub(crate) json_formatter:Option, + pub(crate) css_formatter:Option, + pub(crate) graphql_formatter:Option, + pub(crate) formatter_configuration:Option, + pub(crate) vcs_configuration:Option, + pub(crate) files_configuration:Option, + pub(crate) stdin_file_path:Option, + pub(crate) write:bool, + pub(crate) fix:bool, + pub(crate) paths:Vec, + pub(crate) staged:bool, + pub(crate) changed:bool, + pub(crate) since:Option, } impl LoadEditorConfig for FormatCommandPayload { - fn should_load_editor_config(&self, fs_configuration: &PartialConfiguration) -> bool { - self.formatter_configuration - .as_ref() - .and_then(|c| c.use_editorconfig) - .unwrap_or(fs_configuration.use_editorconfig().unwrap_or_default()) - } + fn should_load_editor_config(&self, fs_configuration:&PartialConfiguration) -> bool { + self.formatter_configuration + .as_ref() + .and_then(|c| c.use_editorconfig) + .unwrap_or(fs_configuration.use_editorconfig().unwrap_or_default()) + } } impl CommandRunner for FormatCommandPayload { - const COMMAND_NAME: &'static str = "format"; - - fn merge_configuration( - &mut self, - loaded_configuration: LoadedConfiguration, - fs: &DynRef<'_, dyn FileSystem>, - console: &mut dyn Console, - ) -> Result { - let LoadedConfiguration { - configuration: biome_configuration, - directory_path: configuration_path, - .. - } = loaded_configuration; - - let editorconfig_search_path = configuration_path.clone(); - - let mut fs_configuration = - self.load_editor_config(editorconfig_search_path, &biome_configuration, fs, console)?; - // this makes biome configuration take precedence over editorconfig configuration - fs_configuration.merge_with(biome_configuration); - - let mut configuration = fs_configuration; - - // TODO: remove in biome 2.0 - if let Some(config) = self.formatter_configuration.as_mut() { - if let Some(indent_size) = config.indent_size { - let diagnostic = DeprecatedArgument::new(markup! { - "The argument ""--indent-size"" is deprecated, it will be removed in the next major release. Use ""--indent-width"" instead." - }); - - console.error(markup! { - {PrintDiagnostic::simple(&diagnostic)} - }); - - if config.indent_width.is_none() { - config.indent_width = Some(indent_size); - } - } - } - // TODO: remove in biome 2.0 - if let Some(js_formatter) = self.javascript_formatter.as_mut() { - if let Some(indent_size) = js_formatter.indent_size { - let diagnostic = DeprecatedArgument::new(markup! { - "The argument ""--javascript-formatter-indent-size"" is deprecated, it will be removed in the next major release. Use ""--javascript-formatter-indent-width"" instead." - }); - - console.error(markup! { - {PrintDiagnostic::simple(&diagnostic)} - }); - - if js_formatter.indent_width.is_none() { - js_formatter.indent_width = Some(indent_size); - } - } - - if let Some(trailing_comma) = js_formatter.trailing_comma { - let diagnostic = DeprecatedArgument::new(markup! { - "The argument ""--trailing-comma"" is deprecated, it will be removed in the next major release. Use ""--trailing-commas"" instead." - }); - - console.error(markup! { - {PrintDiagnostic::simple(&diagnostic)} - }); - - if js_formatter.trailing_commas.is_none() { - js_formatter.trailing_commas = Some(trailing_comma); - } - } - } - // TODO: remove in biome 2.0 - if let Some(json_formatter) = self.json_formatter.as_mut() { - if let Some(indent_size) = json_formatter.indent_size { - let diagnostic = DeprecatedArgument::new(markup! { - "The argument ""--json-formatter-indent-size"" is deprecated, it will be removed in the next major release. Use ""--json-formatter-indent-width"" instead." - }); - - console.error(markup! { - {PrintDiagnostic::simple(&diagnostic)} - }); - - if json_formatter.indent_width.is_none() { - json_formatter.indent_width = Some(indent_size); - } - } - } - - // merge formatter options - if !configuration - .formatter - .as_ref() - .is_some_and(PartialFormatterConfiguration::is_disabled) - { - let formatter = configuration.formatter.get_or_insert_with(Default::default); - - if let Some(formatter_configuration) = self.formatter_configuration.clone() { - formatter.merge_with(formatter_configuration); - } - - formatter.enabled = Some(true); - } - - if self.css_formatter.is_some() { - let css = configuration.css.get_or_insert_with(Default::default); - - css.formatter.merge_with(self.css_formatter.clone()); - } - - if self.graphql_formatter.is_some() { - let graphql = configuration.graphql.get_or_insert_with(Default::default); - - graphql.formatter.merge_with(self.graphql_formatter.clone()); - } - - if self.javascript_formatter.is_some() { - let javascript = configuration - .javascript - .get_or_insert_with(Default::default); - - javascript - .formatter - .merge_with(self.javascript_formatter.clone()); - } - - if self.json_formatter.is_some() { - let json = configuration.json.get_or_insert_with(Default::default); - - json.formatter.merge_with(self.json_formatter.clone()); - } - - configuration - .files - .merge_with(self.files_configuration.clone()); - - configuration.vcs.merge_with(self.vcs_configuration.clone()); - - Ok(configuration) - } - - fn get_files_to_process( - &self, - fs: &DynRef<'_, dyn FileSystem>, - configuration: &PartialConfiguration, - ) -> Result, CliDiagnostic> { - let paths = get_files_to_process_with_cli_options( - self.since.as_deref(), - self.changed, - self.staged, - fs, - configuration, - )? - .unwrap_or(self.paths.clone()); - - Ok(paths) - } - - fn get_stdin_file_path(&self) -> Option<&str> { - self.stdin_file_path.as_deref() - } - - fn should_write(&self) -> bool { - self.write || self.fix - } - - fn get_execution( - &self, - cli_options: &CliOptions, - console: &mut dyn Console, - _workspace: &dyn Workspace, - ) -> Result { - Ok(Execution::new(TraversalMode::Format { - ignore_errors: cli_options.skip_errors, - write: self.should_write(), - stdin: self.get_stdin(console)?, - vcs_targeted: (self.staged, self.changed).into(), - }) - .set_report(cli_options)) - } + const COMMAND_NAME:&'static str = "format"; + + fn merge_configuration( + &mut self, + loaded_configuration:LoadedConfiguration, + fs:&DynRef<'_, dyn FileSystem>, + console:&mut dyn Console, + ) -> Result { + let LoadedConfiguration { configuration: biome_configuration, directory_path: configuration_path, .. } = + loaded_configuration; + + let editorconfig_search_path = configuration_path.clone(); + + let mut fs_configuration = + self.load_editor_config(editorconfig_search_path, &biome_configuration, fs, console)?; + // this makes biome configuration take precedence over editorconfig + // configuration + fs_configuration.merge_with(biome_configuration); + + let mut configuration = fs_configuration; + + // TODO: remove in biome 2.0 + if let Some(config) = self.formatter_configuration.as_mut() { + if let Some(indent_size) = config.indent_size { + let diagnostic = DeprecatedArgument::new(markup! { + "The argument ""--indent-size"" is deprecated, it will be removed in the next major release. Use ""--indent-width"" instead." + }); + + console.error(markup! { + {PrintDiagnostic::simple(&diagnostic)} + }); + + if config.indent_width.is_none() { + config.indent_width = Some(indent_size); + } + } + } + // TODO: remove in biome 2.0 + if let Some(js_formatter) = self.javascript_formatter.as_mut() { + if let Some(indent_size) = js_formatter.indent_size { + let diagnostic = DeprecatedArgument::new(markup! { + "The argument ""--javascript-formatter-indent-size"" is deprecated, it will be removed in the next major release. Use ""--javascript-formatter-indent-width"" instead." + }); + + console.error(markup! { + {PrintDiagnostic::simple(&diagnostic)} + }); + + if js_formatter.indent_width.is_none() { + js_formatter.indent_width = Some(indent_size); + } + } + + if let Some(trailing_comma) = js_formatter.trailing_comma { + let diagnostic = DeprecatedArgument::new(markup! { + "The argument ""--trailing-comma"" is deprecated, it will be removed in the next major release. Use ""--trailing-commas"" instead." + }); + + console.error(markup! { + {PrintDiagnostic::simple(&diagnostic)} + }); + + if js_formatter.trailing_commas.is_none() { + js_formatter.trailing_commas = Some(trailing_comma); + } + } + } + // TODO: remove in biome 2.0 + if let Some(json_formatter) = self.json_formatter.as_mut() { + if let Some(indent_size) = json_formatter.indent_size { + let diagnostic = DeprecatedArgument::new(markup! { + "The argument ""--json-formatter-indent-size"" is deprecated, it will be removed in the next major release. Use ""--json-formatter-indent-width"" instead." + }); + + console.error(markup! { + {PrintDiagnostic::simple(&diagnostic)} + }); + + if json_formatter.indent_width.is_none() { + json_formatter.indent_width = Some(indent_size); + } + } + } + + // merge formatter options + if !configuration + .formatter + .as_ref() + .is_some_and(PartialFormatterConfiguration::is_disabled) + { + let formatter = configuration.formatter.get_or_insert_with(Default::default); + + if let Some(formatter_configuration) = self.formatter_configuration.clone() { + formatter.merge_with(formatter_configuration); + } + + formatter.enabled = Some(true); + } + + if self.css_formatter.is_some() { + let css = configuration.css.get_or_insert_with(Default::default); + + css.formatter.merge_with(self.css_formatter.clone()); + } + + if self.graphql_formatter.is_some() { + let graphql = configuration.graphql.get_or_insert_with(Default::default); + + graphql.formatter.merge_with(self.graphql_formatter.clone()); + } + + if self.javascript_formatter.is_some() { + let javascript = configuration.javascript.get_or_insert_with(Default::default); + + javascript.formatter.merge_with(self.javascript_formatter.clone()); + } + + if self.json_formatter.is_some() { + let json = configuration.json.get_or_insert_with(Default::default); + + json.formatter.merge_with(self.json_formatter.clone()); + } + + configuration.files.merge_with(self.files_configuration.clone()); + + configuration.vcs.merge_with(self.vcs_configuration.clone()); + + Ok(configuration) + } + + fn get_files_to_process( + &self, + fs:&DynRef<'_, dyn FileSystem>, + configuration:&PartialConfiguration, + ) -> Result, CliDiagnostic> { + let paths = + get_files_to_process_with_cli_options(self.since.as_deref(), self.changed, self.staged, fs, configuration)? + .unwrap_or(self.paths.clone()); + + Ok(paths) + } + + fn get_stdin_file_path(&self) -> Option<&str> { self.stdin_file_path.as_deref() } + + fn should_write(&self) -> bool { self.write || self.fix } + + fn get_execution( + &self, + cli_options:&CliOptions, + console:&mut dyn Console, + _workspace:&dyn Workspace, + ) -> Result { + Ok(Execution::new(TraversalMode::Format { + ignore_errors:cli_options.skip_errors, + write:self.should_write(), + stdin:self.get_stdin(console)?, + vcs_targeted:(self.staged, self.changed).into(), + }) + .set_report(cli_options)) + } } diff --git a/crates/biome_cli/Source/commands/init.rs b/crates/biome_cli/Source/commands/init.rs index d9d3341e56e1..b9de0babd844 100644 --- a/crates/biome_cli/Source/commands/init.rs +++ b/crates/biome_cli/Source/commands/init.rs @@ -1,21 +1,18 @@ -use crate::{CliDiagnostic, CliSession}; use biome_configuration::PartialConfiguration; -use biome_console::{markup, ConsoleExt}; +use biome_console::{ConsoleExt, markup}; use biome_fs::ConfigName; use biome_service::configuration::create_config; -pub(crate) fn init(mut session: CliSession, emit_jsonc: bool) -> Result<(), CliDiagnostic> { - let fs = &mut session.app.fs; +use crate::{CliDiagnostic, CliSession}; + +pub(crate) fn init(mut session:CliSession, emit_jsonc:bool) -> Result<(), CliDiagnostic> { + let fs = &mut session.app.fs; - create_config(fs, PartialConfiguration::init(), emit_jsonc)?; + create_config(fs, PartialConfiguration::init(), emit_jsonc)?; - let file_created = if emit_jsonc { - ConfigName::biome_jsonc() - } else { - ConfigName::biome_json() - }; + let file_created = if emit_jsonc { ConfigName::biome_jsonc() } else { ConfigName::biome_json() }; - session.app.console.log(markup! { + session.app.console.log(markup! { " Welcome to Biome! Let's get you started... @@ -47,5 +44,5 @@ Welcome to Biome! Let's get you started... " }); - Ok(()) + Ok(()) } diff --git a/crates/biome_cli/Source/commands/lint.rs b/crates/biome_cli/Source/commands/lint.rs index 873d4a7efd39..7ae34bfa0f47 100644 --- a/crates/biome_cli/Source/commands/lint.rs +++ b/crates/biome_cli/Source/commands/lint.rs @@ -1,165 +1,156 @@ -use super::{determine_fix_file_mode, FixFileModeOptions}; -use crate::cli_options::CliOptions; -use crate::commands::{get_files_to_process_with_cli_options, CommandRunner}; -use crate::{CliDiagnostic, Execution, TraversalMode}; -use biome_configuration::analyzer::RuleSelector; -use biome_configuration::css::PartialCssLinter; -use biome_configuration::javascript::PartialJavascriptLinter; -use biome_configuration::json::PartialJsonLinter; -use biome_configuration::vcs::PartialVcsConfiguration; +use std::ffi::OsString; + use biome_configuration::{ - PartialConfiguration, PartialFilesConfiguration, PartialGraphqlLinter, - PartialLinterConfiguration, + PartialConfiguration, + PartialFilesConfiguration, + PartialGraphqlLinter, + PartialLinterConfiguration, + analyzer::RuleSelector, + css::PartialCssLinter, + javascript::PartialJavascriptLinter, + json::PartialJsonLinter, + vcs::PartialVcsConfiguration, }; use biome_console::Console; use biome_deserialize::Merge; use biome_fs::FileSystem; -use biome_service::configuration::LoadedConfiguration; -use biome_service::{DynRef, Workspace, WorkspaceError}; -use std::ffi::OsString; +use biome_service::{DynRef, Workspace, WorkspaceError, configuration::LoadedConfiguration}; + +use super::{FixFileModeOptions, determine_fix_file_mode}; +use crate::{ + CliDiagnostic, + Execution, + TraversalMode, + cli_options::CliOptions, + commands::{CommandRunner, get_files_to_process_with_cli_options}, +}; pub(crate) struct LintCommandPayload { - pub(crate) apply: bool, - pub(crate) apply_unsafe: bool, - pub(crate) write: bool, - pub(crate) fix: bool, - pub(crate) unsafe_: bool, - pub(crate) suppress: bool, - pub(crate) suppression_reason: Option, - pub(crate) linter_configuration: Option, - pub(crate) vcs_configuration: Option, - pub(crate) files_configuration: Option, - pub(crate) paths: Vec, - pub(crate) only: Vec, - pub(crate) skip: Vec, - pub(crate) stdin_file_path: Option, - pub(crate) staged: bool, - pub(crate) changed: bool, - pub(crate) since: Option, - pub(crate) javascript_linter: Option, - pub(crate) json_linter: Option, - pub(crate) css_linter: Option, - pub(crate) graphql_linter: Option, + pub(crate) apply:bool, + pub(crate) apply_unsafe:bool, + pub(crate) write:bool, + pub(crate) fix:bool, + pub(crate) unsafe_:bool, + pub(crate) suppress:bool, + pub(crate) suppression_reason:Option, + pub(crate) linter_configuration:Option, + pub(crate) vcs_configuration:Option, + pub(crate) files_configuration:Option, + pub(crate) paths:Vec, + pub(crate) only:Vec, + pub(crate) skip:Vec, + pub(crate) stdin_file_path:Option, + pub(crate) staged:bool, + pub(crate) changed:bool, + pub(crate) since:Option, + pub(crate) javascript_linter:Option, + pub(crate) json_linter:Option, + pub(crate) css_linter:Option, + pub(crate) graphql_linter:Option, } impl CommandRunner for LintCommandPayload { - const COMMAND_NAME: &'static str = "lint"; - - fn merge_configuration( - &mut self, - loaded_configuration: LoadedConfiguration, - _fs: &DynRef<'_, dyn FileSystem>, - _console: &mut dyn Console, - ) -> Result { - let LoadedConfiguration { - configuration: mut fs_configuration, - .. - } = loaded_configuration; - - fs_configuration.merge_with(PartialConfiguration { - linter: if fs_configuration - .linter - .as_ref() - .is_some_and(PartialLinterConfiguration::is_disabled) - { - None - } else { - if let Some(linter) = self.linter_configuration.as_mut() { - // Don't overwrite rules from the CLI configuration. - linter.rules = None; - } - - self.linter_configuration.clone() - }, - files: self.files_configuration.clone(), - vcs: self.vcs_configuration.clone(), - ..Default::default() - }); - - if self.css_linter.is_some() { - let css = fs_configuration.css.get_or_insert_with(Default::default); - - css.linter.merge_with(self.css_linter.clone()); - } - - if self.graphql_linter.is_some() { - let graphql = fs_configuration - .graphql - .get_or_insert_with(Default::default); - - graphql.linter.merge_with(self.graphql_linter.clone()); - } - - if self.javascript_linter.is_some() { - let javascript = fs_configuration - .javascript - .get_or_insert_with(Default::default); - - javascript.linter.merge_with(self.javascript_linter.clone()); - } - - if self.json_linter.is_some() { - let json = fs_configuration.json.get_or_insert_with(Default::default); - - json.linter.merge_with(self.json_linter.clone()); - } - - Ok(fs_configuration) - } - - fn get_files_to_process( - &self, - fs: &DynRef<'_, dyn FileSystem>, - configuration: &PartialConfiguration, - ) -> Result, CliDiagnostic> { - let paths = get_files_to_process_with_cli_options( - self.since.as_deref(), - self.changed, - self.staged, - fs, - configuration, - )? - .unwrap_or(self.paths.clone()); - - Ok(paths) - } - - fn get_stdin_file_path(&self) -> Option<&str> { - self.stdin_file_path.as_deref() - } - - fn should_write(&self) -> bool { - self.write || self.fix - } - - fn get_execution( - &self, - cli_options: &CliOptions, - console: &mut dyn Console, - _workspace: &dyn Workspace, - ) -> Result { - let fix_file_mode = determine_fix_file_mode( - FixFileModeOptions { - apply: self.apply, - apply_unsafe: self.apply_unsafe, - write: self.write, - fix: self.fix, - unsafe_: self.unsafe_, - suppress: self.suppress, - suppression_reason: self.suppression_reason.clone(), - }, - console, - )?; - - Ok(Execution::new(TraversalMode::Lint { - fix_file_mode, - stdin: self.get_stdin(console)?, - only: self.only.clone(), - skip: self.skip.clone(), - vcs_targeted: (self.staged, self.changed).into(), - suppress: self.suppress, - suppression_reason: self.suppression_reason.clone(), - }) - .set_report(cli_options)) - } + const COMMAND_NAME:&'static str = "lint"; + + fn merge_configuration( + &mut self, + loaded_configuration:LoadedConfiguration, + _fs:&DynRef<'_, dyn FileSystem>, + _console:&mut dyn Console, + ) -> Result { + let LoadedConfiguration { configuration: mut fs_configuration, .. } = loaded_configuration; + + fs_configuration.merge_with(PartialConfiguration { + linter:if fs_configuration + .linter + .as_ref() + .is_some_and(PartialLinterConfiguration::is_disabled) + { + None + } else { + if let Some(linter) = self.linter_configuration.as_mut() { + // Don't overwrite rules from the CLI configuration. + linter.rules = None; + } + + self.linter_configuration.clone() + }, + files:self.files_configuration.clone(), + vcs:self.vcs_configuration.clone(), + ..Default::default() + }); + + if self.css_linter.is_some() { + let css = fs_configuration.css.get_or_insert_with(Default::default); + + css.linter.merge_with(self.css_linter.clone()); + } + + if self.graphql_linter.is_some() { + let graphql = fs_configuration.graphql.get_or_insert_with(Default::default); + + graphql.linter.merge_with(self.graphql_linter.clone()); + } + + if self.javascript_linter.is_some() { + let javascript = fs_configuration.javascript.get_or_insert_with(Default::default); + + javascript.linter.merge_with(self.javascript_linter.clone()); + } + + if self.json_linter.is_some() { + let json = fs_configuration.json.get_or_insert_with(Default::default); + + json.linter.merge_with(self.json_linter.clone()); + } + + Ok(fs_configuration) + } + + fn get_files_to_process( + &self, + fs:&DynRef<'_, dyn FileSystem>, + configuration:&PartialConfiguration, + ) -> Result, CliDiagnostic> { + let paths = + get_files_to_process_with_cli_options(self.since.as_deref(), self.changed, self.staged, fs, configuration)? + .unwrap_or(self.paths.clone()); + + Ok(paths) + } + + fn get_stdin_file_path(&self) -> Option<&str> { self.stdin_file_path.as_deref() } + + fn should_write(&self) -> bool { self.write || self.fix } + + fn get_execution( + &self, + cli_options:&CliOptions, + console:&mut dyn Console, + _workspace:&dyn Workspace, + ) -> Result { + let fix_file_mode = determine_fix_file_mode( + FixFileModeOptions { + apply:self.apply, + apply_unsafe:self.apply_unsafe, + write:self.write, + fix:self.fix, + unsafe_:self.unsafe_, + suppress:self.suppress, + suppression_reason:self.suppression_reason.clone(), + }, + console, + )?; + + Ok(Execution::new(TraversalMode::Lint { + fix_file_mode, + stdin:self.get_stdin(console)?, + only:self.only.clone(), + skip:self.skip.clone(), + vcs_targeted:(self.staged, self.changed).into(), + suppress:self.suppress, + suppression_reason:self.suppression_reason.clone(), + }) + .set_report(cli_options)) + } } diff --git a/crates/biome_cli/Source/commands/migrate.rs b/crates/biome_cli/Source/commands/migrate.rs index 6057b8358304..e96cd6f036e7 100644 --- a/crates/biome_cli/Source/commands/migrate.rs +++ b/crates/biome_cli/Source/commands/migrate.rs @@ -1,98 +1,91 @@ -use super::{ - check_fix_incompatible_arguments, CommandRunner, FixFileModeOptions, MigrateSubCommand, -}; -use crate::cli_options::CliOptions; -use crate::diagnostics::MigrationDiagnostic; -use crate::execute::{Execution, TraversalMode}; -use crate::CliDiagnostic; +use std::{ffi::OsString, path::PathBuf}; + use biome_configuration::PartialConfiguration; -use biome_console::{markup, Console, ConsoleExt}; +use biome_console::{Console, ConsoleExt, markup}; use biome_fs::FileSystem; -use biome_service::configuration::LoadedConfiguration; -use biome_service::{DynRef, Workspace, WorkspaceError}; -use std::ffi::OsString; -use std::path::PathBuf; +use biome_service::{DynRef, Workspace, WorkspaceError, configuration::LoadedConfiguration}; + +use super::{CommandRunner, FixFileModeOptions, MigrateSubCommand, check_fix_incompatible_arguments}; +use crate::{ + CliDiagnostic, + cli_options::CliOptions, + diagnostics::MigrationDiagnostic, + execute::{Execution, TraversalMode}, +}; pub(crate) struct MigrateCommandPayload { - pub(crate) write: bool, - pub(crate) fix: bool, - pub(crate) sub_command: Option, - pub(crate) configuration_file_path: Option, - pub(crate) configuration_directory_path: Option, + pub(crate) write:bool, + pub(crate) fix:bool, + pub(crate) sub_command:Option, + pub(crate) configuration_file_path:Option, + pub(crate) configuration_directory_path:Option, } impl CommandRunner for MigrateCommandPayload { - const COMMAND_NAME: &'static str = "migrate"; + const COMMAND_NAME:&'static str = "migrate"; - fn merge_configuration( - &mut self, - loaded_configuration: LoadedConfiguration, - _fs: &DynRef<'_, dyn FileSystem>, - _console: &mut dyn Console, - ) -> Result { - self.configuration_file_path = loaded_configuration.file_path; + fn merge_configuration( + &mut self, + loaded_configuration:LoadedConfiguration, + _fs:&DynRef<'_, dyn FileSystem>, + _console:&mut dyn Console, + ) -> Result { + self.configuration_file_path = loaded_configuration.file_path; - self.configuration_directory_path = loaded_configuration.directory_path; + self.configuration_directory_path = loaded_configuration.directory_path; - Ok(loaded_configuration.configuration) - } + Ok(loaded_configuration.configuration) + } - fn get_files_to_process( - &self, - _fs: &DynRef<'_, dyn FileSystem>, - _configuration: &PartialConfiguration, - ) -> Result, CliDiagnostic> { - Ok(vec![]) - } + fn get_files_to_process( + &self, + _fs:&DynRef<'_, dyn FileSystem>, + _configuration:&PartialConfiguration, + ) -> Result, CliDiagnostic> { + Ok(vec![]) + } - fn get_stdin_file_path(&self) -> Option<&str> { - None - } + fn get_stdin_file_path(&self) -> Option<&str> { None } - fn should_write(&self) -> bool { - self.write || self.fix - } + fn should_write(&self) -> bool { self.write || self.fix } - fn get_execution( - &self, - _cli_options: &CliOptions, - console: &mut dyn Console, - _workspace: &dyn Workspace, - ) -> Result { - if let (Some(path), Some(directory_path)) = ( - self.configuration_file_path.clone(), - self.configuration_directory_path.clone(), - ) { - Ok(Execution::new(TraversalMode::Migrate { - write: self.should_write(), - configuration_file_path: path, - configuration_directory_path: directory_path, - sub_command: self.sub_command.clone(), - })) - } else { - console.log(markup! { + fn get_execution( + &self, + _cli_options:&CliOptions, + console:&mut dyn Console, + _workspace:&dyn Workspace, + ) -> Result { + if let (Some(path), Some(directory_path)) = + (self.configuration_file_path.clone(), self.configuration_directory_path.clone()) + { + Ok(Execution::new(TraversalMode::Migrate { + write:self.should_write(), + configuration_file_path:path, + configuration_directory_path:directory_path, + sub_command:self.sub_command.clone(), + })) + } else { + console.log(markup! { "If this project has not yet been set up with Biome yet, please follow the ""Getting Started guide"" first." }); - Err(CliDiagnostic::MigrateError(MigrationDiagnostic { - reason: "Biome couldn't find the Biome configuration file.".to_string(), - })) - } - } + Err(CliDiagnostic::MigrateError(MigrationDiagnostic { + reason:"Biome couldn't find the Biome configuration file.".to_string(), + })) + } + } - fn check_incompatible_arguments(&self) -> Result<(), CliDiagnostic> { - check_fix_incompatible_arguments(FixFileModeOptions { - apply: false, - apply_unsafe: false, - write: self.write, - fix: self.fix, - unsafe_: false, - suppress: false, - suppression_reason: None, - }) - } + fn check_incompatible_arguments(&self) -> Result<(), CliDiagnostic> { + check_fix_incompatible_arguments(FixFileModeOptions { + apply:false, + apply_unsafe:false, + write:self.write, + fix:self.fix, + unsafe_:false, + suppress:false, + suppression_reason:None, + }) + } - fn should_validate_configuration_diagnostics(&self) -> bool { - false - } + fn should_validate_configuration_diagnostics(&self) -> bool { false } } diff --git a/crates/biome_cli/Source/commands/mod.rs b/crates/biome_cli/Source/commands/mod.rs index 1da14b5d33a7..8fd8e9be6d63 100644 --- a/crates/biome_cli/Source/commands/mod.rs +++ b/crates/biome_cli/Source/commands/mod.rs @@ -1,38 +1,54 @@ -use crate::changed::{get_changed_files, get_staged_files}; -use crate::cli_options::{cli_options, CliOptions, CliReporter, ColorsArg}; -use crate::diagnostics::{DeprecatedArgument, DeprecatedConfigurationFile}; -use crate::execute::Stdin; -use crate::logging::LoggingKind; -use crate::{ - execute_mode, setup_cli_subscriber, CliDiagnostic, CliSession, Execution, LoggingLevel, VERSION, -}; -use biome_configuration::analyzer::RuleSelector; -use biome_configuration::css::PartialCssLinter; -use biome_configuration::javascript::PartialJavascriptLinter; -use biome_configuration::json::PartialJsonLinter; +use std::{ffi::OsString, path::PathBuf}; + use biome_configuration::{ - css::partial_css_formatter, css::partial_css_linter, graphql::partial_graphql_formatter, - graphql::partial_graphql_linter, javascript::partial_javascript_formatter, - javascript::partial_javascript_linter, json::partial_json_formatter, json::partial_json_linter, - partial_configuration, partial_files_configuration, partial_formatter_configuration, - partial_linter_configuration, vcs::partial_vcs_configuration, vcs::PartialVcsConfiguration, - PartialCssFormatter, PartialFilesConfiguration, PartialFormatterConfiguration, - PartialGraphqlFormatter, PartialGraphqlLinter, PartialJavascriptFormatter, - PartialJsonFormatter, PartialLinterConfiguration, + BiomeDiagnostic, + PartialConfiguration, + PartialCssFormatter, + PartialFilesConfiguration, + PartialFormatterConfiguration, + PartialGraphqlFormatter, + PartialGraphqlLinter, + PartialJavascriptFormatter, + PartialJsonFormatter, + PartialLinterConfiguration, + analyzer::RuleSelector, + css::{PartialCssLinter, partial_css_formatter, partial_css_linter}, + graphql::{partial_graphql_formatter, partial_graphql_linter}, + javascript::{PartialJavascriptLinter, partial_javascript_formatter, partial_javascript_linter}, + json::{PartialJsonLinter, partial_json_formatter, partial_json_linter}, + partial_configuration, + partial_files_configuration, + partial_formatter_configuration, + partial_linter_configuration, + vcs::{PartialVcsConfiguration, partial_vcs_configuration}, }; -use biome_configuration::{BiomeDiagnostic, PartialConfiguration}; -use biome_console::{markup, Console, ConsoleExt}; +use biome_console::{Console, ConsoleExt, markup}; use biome_diagnostics::{Diagnostic, PrintDiagnostic}; use biome_fs::{BiomePath, FileSystem}; -use biome_service::configuration::{ - load_configuration, load_editorconfig, LoadedConfiguration, PartialConfigurationExt, +use biome_service::{ + DynRef, + Workspace, + WorkspaceError, + configuration::{LoadedConfiguration, PartialConfigurationExt, load_configuration, load_editorconfig}, + documentation::Doc, + workspace::{FixFileMode, RegisterProjectFolderParams, UpdateSettingsParams}, }; -use biome_service::documentation::Doc; -use biome_service::workspace::{FixFileMode, RegisterProjectFolderParams, UpdateSettingsParams}; -use biome_service::{DynRef, Workspace, WorkspaceError}; use bpaf::Bpaf; -use std::ffi::OsString; -use std::path::PathBuf; + +use crate::{ + CliDiagnostic, + CliSession, + Execution, + LoggingLevel, + VERSION, + changed::{get_changed_files, get_staged_files}, + cli_options::{CliOptions, CliReporter, ColorsArg, cli_options}, + diagnostics::{DeprecatedArgument, DeprecatedConfigurationFile}, + execute::Stdin, + execute_mode, + logging::LoggingKind, + setup_cli_subscriber, +}; pub(crate) mod check; pub(crate) mod ci; @@ -49,777 +65,760 @@ pub(crate) mod version; #[derive(Debug, Clone, Bpaf)] #[bpaf(options, version(VERSION))] -/// Biome official CLI. Use it to check the health of your project or run it to check single files. +/// Biome official CLI. Use it to check the health of your project or run it to +/// check single files. pub enum BiomeCommand { - /// Shows the Biome version information and quit. - #[bpaf(command)] - Version(#[bpaf(external(cli_options), hide_usage)] CliOptions), - - #[bpaf(command)] - /// Prints information for debugging. - Rage( - #[bpaf(external(cli_options), hide_usage)] CliOptions, - /// Prints the Biome daemon server logs - #[bpaf(long("daemon-logs"), switch)] - bool, - /// Prints the formatter options applied - #[bpaf(long("formatter"), switch)] - bool, - /// Prints the linter options applied - #[bpaf(long("linter"), switch)] - bool, - ), - /// Starts the Biome daemon server process. - #[bpaf(command)] - Start { - /// Allows to change the prefix applied to the file name of the logs. - #[bpaf( - env("BIOME_LOG_PREFIX_NAME"), - long("log-prefix-name"), - argument("STRING"), - hide_usage, - fallback(String::from("server.log")), - display_fallback - )] - log_prefix_name: String, - - /// Allows to change the folder where logs are stored. - #[bpaf( + /// Shows the Biome version information and quit. + #[bpaf(command)] + Version(#[bpaf(external(cli_options), hide_usage)] CliOptions), + + #[bpaf(command)] + /// Prints information for debugging. + Rage( + #[bpaf(external(cli_options), hide_usage)] CliOptions, + /// Prints the Biome daemon server logs + #[bpaf(long("daemon-logs"), switch)] + bool, + /// Prints the formatter options applied + #[bpaf(long("formatter"), switch)] + bool, + /// Prints the linter options applied + #[bpaf(long("linter"), switch)] + bool, + ), + /// Starts the Biome daemon server process. + #[bpaf(command)] + Start { + /// Allows to change the prefix applied to the file name of the logs. + #[bpaf( + env("BIOME_LOG_PREFIX_NAME"), + long("log-prefix-name"), + argument("STRING"), + hide_usage, + fallback(String::from("server.log")), + display_fallback + )] + log_prefix_name:String, + + /// Allows to change the folder where logs are stored. + #[bpaf( env("BIOME_LOG_PATH"), long("log-path"), argument("PATH"), hide_usage, fallback(biome_fs::ensure_cache_dir().join("biome-logs")), )] - log_path: PathBuf, - /// Allows to set a custom file path to the configuration file, - /// or a custom directory path to find `biome.json` or `biome.jsonc` - #[bpaf(env("BIOME_CONFIG_PATH"), long("config-path"), argument("PATH"))] - config_path: Option, - }, - - /// Stops the Biome daemon server process. - #[bpaf(command)] - Stop, - - /// Runs formatter, linter and import sorting to the requested files. - #[bpaf(command)] - Check { - /// Writes safe fixes, formatting and import sorting - #[bpaf(long("write"), switch)] - write: bool, - - /// Allow to do unsafe fixes, should be used with `--write` or `--fix` - #[bpaf(long("unsafe"), switch)] - unsafe_: bool, - - /// Alias for `--write`, writes safe fixes, formatting and import sorting - #[bpaf(long("fix"), switch, hide_usage)] - fix: bool, - - /// Alias for `--write`, writes safe fixes, formatting and import sorting (deprecated, use `--write`) - #[bpaf(long("apply"), switch, hide_usage)] - apply: bool, - - /// Alias for `--write --unsafe`, writes safe and unsafe fixes, formatting and import sorting (deprecated, use `--write --unsafe`) - #[bpaf(long("apply-unsafe"), switch, hide_usage)] - apply_unsafe: bool, - - /// Allow to enable or disable the formatter check. - #[bpaf( - long("formatter-enabled"), - argument("true|false"), - optional, - hide_usage - )] - formatter_enabled: Option, - /// Allow to enable or disable the linter check. - #[bpaf(long("linter-enabled"), argument("true|false"), optional, hide_usage)] - linter_enabled: Option, - /// Allow to enable or disable the organize imports. - #[bpaf( - long("organize-imports-enabled"), - argument("true|false"), - optional, - hide_usage - )] - organize_imports_enabled: Option, - - /// Allow to enable or disable the assists. - #[bpaf(long("assists-enabled"), argument("true|false"), optional)] - assists_enabled: Option, - - #[bpaf(external(partial_configuration), hide_usage, optional)] - configuration: Option, - #[bpaf(external, hide_usage)] - cli_options: CliOptions, - /// Use this option when you want to format code piped from `stdin`, and print the output to `stdout`. - /// - /// The file doesn't need to exist on disk, what matters is the extension of the file. Based on the extension, Biome knows how to check the code. - /// - /// Example: `echo 'let a;' | biome check --stdin-file-path=file.js` - #[bpaf(long("stdin-file-path"), argument("PATH"), hide_usage)] - stdin_file_path: Option, - - /// When set to true, only the files that have been staged (the ones prepared to be committed) - /// will be linted. This option should be used when working locally. - #[bpaf(long("staged"), switch)] - staged: bool, - - /// When set to true, only the files that have been changed compared to your `defaultBranch` - /// configuration will be linted. This option should be used in CI environments. - #[bpaf(long("changed"), switch)] - changed: bool, - - /// Use this to specify the base branch to compare against when you're using the --changed - /// flag and the `defaultBranch` is not set in your `biome.json` - #[bpaf(long("since"), argument("REF"))] - since: Option, - - /// Single file, single path or list of paths - #[bpaf(positional("PATH"), many)] - paths: Vec, - }, - /// Run various checks on a set of files. - #[bpaf(command)] - Lint { - /// Writes safe fixes - #[bpaf(long("write"), switch)] - write: bool, - - /// Allow to do unsafe fixes, should be used with `--write` or `--fix` - #[bpaf(long("unsafe"), switch)] - unsafe_: bool, - - /// Alias for `--write`, writes safe fixes - #[bpaf(long("fix"), switch, hide_usage)] - fix: bool, - - /// Alias for `--write`, writes safe fixes (deprecated, use `--write`) - #[bpaf(long("apply"), switch, hide_usage)] - apply: bool, - - /// Alias for `--write --unsafe`, writes safe and unsafe fixes (deprecated, use `--write --unsafe`) - #[bpaf(long("apply-unsafe"), switch, hide_usage)] - apply_unsafe: bool, - - /// Fixes lint rule violations with a comment a suppression instead of using a rule code action (fix) - #[bpaf(long("suppress"))] - suppress: bool, - - /// Explanation for suppressing diagnostics with `--suppress` - #[bpaf(long("reason"), argument("STRING"))] - suppression_reason: Option, - - #[bpaf(external(partial_linter_configuration), hide_usage, optional)] - linter_configuration: Option, - - #[bpaf(external(partial_vcs_configuration), optional, hide_usage)] - vcs_configuration: Option, - - #[bpaf(external(partial_files_configuration), optional, hide_usage)] - files_configuration: Option, - - #[bpaf(external(partial_javascript_linter), optional, hide_usage)] - javascript_linter: Option, - - #[bpaf(external(partial_json_linter), optional, hide_usage)] - json_linter: Option, - - #[bpaf(external(partial_css_linter), optional, hide_usage, hide)] - css_linter: Option, - - #[bpaf(external(partial_graphql_linter), optional, hide_usage, hide)] - graphql_linter: Option, - - #[bpaf(external, hide_usage)] - cli_options: CliOptions, - - /// Run only the given rule or group of rules. - /// If the severity level of a rule is `off`, - /// then the severity level of the rule is set to `error` if it is a recommended rule or `warn` otherwise. - /// - /// Example: `biome lint --only=correctness/noUnusedVariables --only=suspicious` - #[bpaf(long("only"), argument("GROUP|RULE"))] - only: Vec, - - /// Skip the given rule or group of rules by setting the severity level of the rules to `off`. - /// This option takes precedence over `--only`. - /// - /// Example: `biome lint --skip=correctness/noUnusedVariables --skip=suspicious` - #[bpaf(long("skip"), argument("GROUP|RULE"))] - skip: Vec, - - /// Use this option when you want to format code piped from `stdin`, and print the output to `stdout`. - /// - /// The file doesn't need to exist on disk, what matters is the extension of the file. Based on the extension, Biome knows how to lint the code. - /// - /// Example: `echo 'let a;' | biome lint --stdin-file-path=file.js` - #[bpaf(long("stdin-file-path"), argument("PATH"), hide_usage)] - stdin_file_path: Option, - /// When set to true, only the files that have been staged (the ones prepared to be committed) - /// will be linted. - #[bpaf(long("staged"), switch)] - staged: bool, - /// When set to true, only the files that have been changed compared to your `defaultBranch` - /// configuration will be linted. - #[bpaf(long("changed"), switch)] - changed: bool, - /// Use this to specify the base branch to compare against when you're using the --changed - /// flag and the `defaultBranch` is not set in your biome.json - #[bpaf(long("since"), argument("REF"))] - since: Option, - /// Single file, single path or list of paths - #[bpaf(positional("PATH"), many)] - paths: Vec, - }, - /// Run the formatter on a set of files. - #[bpaf(command)] - Format { - #[bpaf(external(partial_formatter_configuration), optional, hide_usage)] - formatter_configuration: Option, - - #[bpaf(external(partial_javascript_formatter), optional, hide_usage)] - javascript_formatter: Option, - - #[bpaf(external(partial_json_formatter), optional, hide_usage)] - json_formatter: Option, - - #[bpaf(external(partial_css_formatter), optional, hide_usage, hide)] - css_formatter: Option, - - #[bpaf(external(partial_graphql_formatter), optional, hide_usage, hide)] - graphql_formatter: Option, - - #[bpaf(external(partial_vcs_configuration), optional, hide_usage)] - vcs_configuration: Option, - - #[bpaf(external(partial_files_configuration), optional, hide_usage)] - files_configuration: Option, - /// Use this option when you want to format code piped from `stdin`, and print the output to `stdout`. - /// - /// The file doesn't need to exist on disk, what matters is the extension of the file. Based on the extension, Biome knows how to format the code. - /// - /// Example: `echo 'let a;' | biome format --stdin-file-path=file.js` - #[bpaf(long("stdin-file-path"), argument("PATH"), hide_usage)] - stdin_file_path: Option, - - #[bpaf(external, hide_usage)] - cli_options: CliOptions, - - /// Writes formatted files to file system. - #[bpaf(long("write"), switch)] - write: bool, - - /// Alias of `--write`, writes formatted files to file system. - #[bpaf(long("fix"), switch, hide_usage)] - fix: bool, - - /// When set to true, only the files that have been staged (the ones prepared to be committed) - /// will be linted. - #[bpaf(long("staged"), switch)] - staged: bool, - - /// When set to true, only the files that have been changed compared to your `defaultBranch` - /// configuration will be linted. - #[bpaf(long("changed"), switch)] - changed: bool, - - /// Use this to specify the base branch to compare against when you're using the --changed - /// flag and the `defaultBranch` is not set in your biome.json - #[bpaf(long("since"), argument("REF"))] - since: Option, - - /// Single file, single path or list of paths. - #[bpaf(positional("PATH"), many)] - paths: Vec, - }, - /// Command to use in CI environments. Runs formatter, linter and import sorting to the requested files. - /// - /// Files won't be modified, the command is a read-only operation. - #[bpaf(command)] - Ci { - /// Allow to enable or disable the formatter check. - #[bpaf(long("formatter-enabled"), argument("true|false"), optional)] - formatter_enabled: Option, - /// Allow to enable or disable the linter check. - #[bpaf(long("linter-enabled"), argument("true|false"), optional)] - linter_enabled: Option, - /// Allow to enable or disable the organize imports. - #[bpaf(long("organize-imports-enabled"), argument("true|false"), optional)] - organize_imports_enabled: Option, - - /// Allow to enable or disable the assists. - #[bpaf(long("assists-enabled"), argument("true|false"), optional)] - assists_enabled: Option, - - #[bpaf(external(partial_configuration), hide_usage, optional)] - configuration: Option, - #[bpaf(external, hide_usage)] - cli_options: CliOptions, - - /// When set to true, only the files that have been changed compared to your `defaultBranch` - /// configuration will be linted. - #[bpaf(long("changed"), switch)] - changed: bool, - - /// Use this to specify the base branch to compare against when you're using the --changed - /// flag and the `defaultBranch` is not set in your biome.json - #[bpaf(long("since"), argument("REF"))] - since: Option, - - /// Single file, single path or list of paths - #[bpaf(positional("PATH"), many)] - paths: Vec, - }, - - /// Bootstraps a new biome project. Creates a configuration file with some defaults. - #[bpaf(command)] - Init( - /// Tells Biome to emit a `biome.jsonc` file. - #[bpaf(long("jsonc"), switch)] - bool, - ), - /// Acts as a server for the Language Server Protocol over stdin/stdout. - #[bpaf(command("lsp-proxy"))] - LspProxy { - /// Allows to change the prefix applied to the file name of the logs. - #[bpaf( - env("BIOME_LOG_PREFIX_NAME"), - long("log-prefix-name"), - argument("STRING"), - hide_usage, - fallback(String::from("server.log")), - display_fallback - )] - log_prefix_name: String, - /// Allows to change the folder where logs are stored. - #[bpaf( + log_path:PathBuf, + /// Allows to set a custom file path to the configuration file, + /// or a custom directory path to find `biome.json` or `biome.jsonc` + #[bpaf(env("BIOME_CONFIG_PATH"), long("config-path"), argument("PATH"))] + config_path:Option, + }, + + /// Stops the Biome daemon server process. + #[bpaf(command)] + Stop, + + /// Runs formatter, linter and import sorting to the requested files. + #[bpaf(command)] + Check { + /// Writes safe fixes, formatting and import sorting + #[bpaf(long("write"), switch)] + write:bool, + + /// Allow to do unsafe fixes, should be used with `--write` or `--fix` + #[bpaf(long("unsafe"), switch)] + unsafe_:bool, + + /// Alias for `--write`, writes safe fixes, formatting and import + /// sorting + #[bpaf(long("fix"), switch, hide_usage)] + fix:bool, + + /// Alias for `--write`, writes safe fixes, formatting and import + /// sorting (deprecated, use `--write`) + #[bpaf(long("apply"), switch, hide_usage)] + apply:bool, + + /// Alias for `--write --unsafe`, writes safe and unsafe fixes, + /// formatting and import sorting (deprecated, use `--write --unsafe`) + #[bpaf(long("apply-unsafe"), switch, hide_usage)] + apply_unsafe:bool, + + /// Allow to enable or disable the formatter check. + #[bpaf(long("formatter-enabled"), argument("true|false"), optional, hide_usage)] + formatter_enabled:Option, + /// Allow to enable or disable the linter check. + #[bpaf(long("linter-enabled"), argument("true|false"), optional, hide_usage)] + linter_enabled:Option, + /// Allow to enable or disable the organize imports. + #[bpaf(long("organize-imports-enabled"), argument("true|false"), optional, hide_usage)] + organize_imports_enabled:Option, + + /// Allow to enable or disable the assists. + #[bpaf(long("assists-enabled"), argument("true|false"), optional)] + assists_enabled:Option, + + #[bpaf(external(partial_configuration), hide_usage, optional)] + configuration:Option, + #[bpaf(external, hide_usage)] + cli_options:CliOptions, + /// Use this option when you want to format code piped from `stdin`, and + /// print the output to `stdout`. + /// + /// The file doesn't need to exist on disk, what matters is the + /// extension of the file. Based on the extension, Biome knows how to + /// check the code. + /// + /// Example: `echo 'let a;' | biome check --stdin-file-path=file.js` + #[bpaf(long("stdin-file-path"), argument("PATH"), hide_usage)] + stdin_file_path:Option, + + /// When set to true, only the files that have been staged (the ones + /// prepared to be committed) will be linted. This option should be + /// used when working locally. + #[bpaf(long("staged"), switch)] + staged:bool, + + /// When set to true, only the files that have been changed compared to + /// your `defaultBranch` configuration will be linted. This option + /// should be used in CI environments. + #[bpaf(long("changed"), switch)] + changed:bool, + + /// Use this to specify the base branch to compare against when you're + /// using the --changed flag and the `defaultBranch` is not set in + /// your `biome.json` + #[bpaf(long("since"), argument("REF"))] + since:Option, + + /// Single file, single path or list of paths + #[bpaf(positional("PATH"), many)] + paths:Vec, + }, + /// Run various checks on a set of files. + #[bpaf(command)] + Lint { + /// Writes safe fixes + #[bpaf(long("write"), switch)] + write:bool, + + /// Allow to do unsafe fixes, should be used with `--write` or `--fix` + #[bpaf(long("unsafe"), switch)] + unsafe_:bool, + + /// Alias for `--write`, writes safe fixes + #[bpaf(long("fix"), switch, hide_usage)] + fix:bool, + + /// Alias for `--write`, writes safe fixes (deprecated, use `--write`) + #[bpaf(long("apply"), switch, hide_usage)] + apply:bool, + + /// Alias for `--write --unsafe`, writes safe and unsafe fixes + /// (deprecated, use `--write --unsafe`) + #[bpaf(long("apply-unsafe"), switch, hide_usage)] + apply_unsafe:bool, + + /// Fixes lint rule violations with a comment a suppression instead of + /// using a rule code action (fix) + #[bpaf(long("suppress"))] + suppress:bool, + + /// Explanation for suppressing diagnostics with `--suppress` + #[bpaf(long("reason"), argument("STRING"))] + suppression_reason:Option, + + #[bpaf(external(partial_linter_configuration), hide_usage, optional)] + linter_configuration:Option, + + #[bpaf(external(partial_vcs_configuration), optional, hide_usage)] + vcs_configuration:Option, + + #[bpaf(external(partial_files_configuration), optional, hide_usage)] + files_configuration:Option, + + #[bpaf(external(partial_javascript_linter), optional, hide_usage)] + javascript_linter:Option, + + #[bpaf(external(partial_json_linter), optional, hide_usage)] + json_linter:Option, + + #[bpaf(external(partial_css_linter), optional, hide_usage, hide)] + css_linter:Option, + + #[bpaf(external(partial_graphql_linter), optional, hide_usage, hide)] + graphql_linter:Option, + + #[bpaf(external, hide_usage)] + cli_options:CliOptions, + + /// Run only the given rule or group of rules. + /// If the severity level of a rule is `off`, + /// then the severity level of the rule is set to `error` if it is a + /// recommended rule or `warn` otherwise. + /// + /// Example: `biome lint --only=correctness/noUnusedVariables + /// --only=suspicious` + #[bpaf(long("only"), argument("GROUP|RULE"))] + only:Vec, + + /// Skip the given rule or group of rules by setting the severity level + /// of the rules to `off`. This option takes precedence over `--only`. + /// + /// Example: `biome lint --skip=correctness/noUnusedVariables + /// --skip=suspicious` + #[bpaf(long("skip"), argument("GROUP|RULE"))] + skip:Vec, + + /// Use this option when you want to format code piped from `stdin`, and + /// print the output to `stdout`. + /// + /// The file doesn't need to exist on disk, what matters is the + /// extension of the file. Based on the extension, Biome knows how to + /// lint the code. + /// + /// Example: `echo 'let a;' | biome lint --stdin-file-path=file.js` + #[bpaf(long("stdin-file-path"), argument("PATH"), hide_usage)] + stdin_file_path:Option, + /// When set to true, only the files that have been staged (the ones + /// prepared to be committed) will be linted. + #[bpaf(long("staged"), switch)] + staged:bool, + /// When set to true, only the files that have been changed compared to + /// your `defaultBranch` configuration will be linted. + #[bpaf(long("changed"), switch)] + changed:bool, + /// Use this to specify the base branch to compare against when you're + /// using the --changed flag and the `defaultBranch` is not set in + /// your biome.json + #[bpaf(long("since"), argument("REF"))] + since:Option, + /// Single file, single path or list of paths + #[bpaf(positional("PATH"), many)] + paths:Vec, + }, + /// Run the formatter on a set of files. + #[bpaf(command)] + Format { + #[bpaf(external(partial_formatter_configuration), optional, hide_usage)] + formatter_configuration:Option, + + #[bpaf(external(partial_javascript_formatter), optional, hide_usage)] + javascript_formatter:Option, + + #[bpaf(external(partial_json_formatter), optional, hide_usage)] + json_formatter:Option, + + #[bpaf(external(partial_css_formatter), optional, hide_usage, hide)] + css_formatter:Option, + + #[bpaf(external(partial_graphql_formatter), optional, hide_usage, hide)] + graphql_formatter:Option, + + #[bpaf(external(partial_vcs_configuration), optional, hide_usage)] + vcs_configuration:Option, + + #[bpaf(external(partial_files_configuration), optional, hide_usage)] + files_configuration:Option, + /// Use this option when you want to format code piped from `stdin`, and + /// print the output to `stdout`. + /// + /// The file doesn't need to exist on disk, what matters is the + /// extension of the file. Based on the extension, Biome knows how to + /// format the code. + /// + /// Example: `echo 'let a;' | biome format --stdin-file-path=file.js` + #[bpaf(long("stdin-file-path"), argument("PATH"), hide_usage)] + stdin_file_path:Option, + + #[bpaf(external, hide_usage)] + cli_options:CliOptions, + + /// Writes formatted files to file system. + #[bpaf(long("write"), switch)] + write:bool, + + /// Alias of `--write`, writes formatted files to file system. + #[bpaf(long("fix"), switch, hide_usage)] + fix:bool, + + /// When set to true, only the files that have been staged (the ones + /// prepared to be committed) will be linted. + #[bpaf(long("staged"), switch)] + staged:bool, + + /// When set to true, only the files that have been changed compared to + /// your `defaultBranch` configuration will be linted. + #[bpaf(long("changed"), switch)] + changed:bool, + + /// Use this to specify the base branch to compare against when you're + /// using the --changed flag and the `defaultBranch` is not set in + /// your biome.json + #[bpaf(long("since"), argument("REF"))] + since:Option, + + /// Single file, single path or list of paths. + #[bpaf(positional("PATH"), many)] + paths:Vec, + }, + /// Command to use in CI environments. Runs formatter, linter and import + /// sorting to the requested files. + /// + /// Files won't be modified, the command is a read-only operation. + #[bpaf(command)] + Ci { + /// Allow to enable or disable the formatter check. + #[bpaf(long("formatter-enabled"), argument("true|false"), optional)] + formatter_enabled:Option, + /// Allow to enable or disable the linter check. + #[bpaf(long("linter-enabled"), argument("true|false"), optional)] + linter_enabled:Option, + /// Allow to enable or disable the organize imports. + #[bpaf(long("organize-imports-enabled"), argument("true|false"), optional)] + organize_imports_enabled:Option, + + /// Allow to enable or disable the assists. + #[bpaf(long("assists-enabled"), argument("true|false"), optional)] + assists_enabled:Option, + + #[bpaf(external(partial_configuration), hide_usage, optional)] + configuration:Option, + #[bpaf(external, hide_usage)] + cli_options:CliOptions, + + /// When set to true, only the files that have been changed compared to + /// your `defaultBranch` configuration will be linted. + #[bpaf(long("changed"), switch)] + changed:bool, + + /// Use this to specify the base branch to compare against when you're + /// using the --changed flag and the `defaultBranch` is not set in + /// your biome.json + #[bpaf(long("since"), argument("REF"))] + since:Option, + + /// Single file, single path or list of paths + #[bpaf(positional("PATH"), many)] + paths:Vec, + }, + + /// Bootstraps a new biome project. Creates a configuration file with some + /// defaults. + #[bpaf(command)] + Init( + /// Tells Biome to emit a `biome.jsonc` file. + #[bpaf(long("jsonc"), switch)] + bool, + ), + /// Acts as a server for the Language Server Protocol over stdin/stdout. + #[bpaf(command("lsp-proxy"))] + LspProxy { + /// Allows to change the prefix applied to the file name of the logs. + #[bpaf( + env("BIOME_LOG_PREFIX_NAME"), + long("log-prefix-name"), + argument("STRING"), + hide_usage, + fallback(String::from("server.log")), + display_fallback + )] + log_prefix_name:String, + /// Allows to change the folder where logs are stored. + #[bpaf( env("BIOME_LOG_PATH"), long("log-path"), argument("PATH"), hide_usage, fallback(biome_fs::ensure_cache_dir().join("biome-logs")), )] - log_path: PathBuf, - /// Allows to set a custom file path to the configuration file, - /// or a custom directory path to find `biome.json` or `biome.jsonc` - #[bpaf(env("BIOME_CONFIG_PATH"), long("config-path"), argument("PATH"))] - config_path: Option, - /// Bogus argument to make the command work with vscode-languageclient - #[bpaf(long("stdio"), hide, hide_usage, switch)] - stdio: bool, - }, - /// Updates the configuration when there are breaking changes. - #[bpaf(command)] - Migrate { - #[bpaf(external, hide_usage)] - cli_options: CliOptions, - - /// Writes the new configuration file to disk - #[bpaf(long("write"), switch)] - write: bool, - - /// Alias of `--write`, writes the new configuration file to disk - #[bpaf(long("fix"), switch, hide_usage)] - fix: bool, - - #[bpaf(external(migrate_sub_command), optional)] - sub_command: Option, - }, - - /// EXPERIMENTAL: Searches for Grit patterns across a project. - /// - /// Note: GritQL escapes code snippets using backticks, but most shells - /// interpret backticks as command invocations. To avoid this, it's best to - /// put single quotes around your Grit queries. - /// - /// ## Example - /// - /// ```shell - /// biome search '`console.log($message)`' # find all `console.log` invocations - /// ``` - #[bpaf(command)] - Search { - #[bpaf(external, hide_usage)] - cli_options: CliOptions, - - #[bpaf(external(partial_files_configuration), optional, hide_usage)] - files_configuration: Option, - - #[bpaf(external(partial_vcs_configuration), optional, hide_usage)] - vcs_configuration: Option, - - /// Use this option when you want to search through code piped from - /// `stdin`, and print the output to `stdout`. - /// - /// The file doesn't need to exist on disk, what matters is the - /// extension of the file. Based on the extension, Biome knows how to - /// parse the code. - /// - /// Example: `echo 'let a;' | biome search '`let $var`' --stdin-file-path=file.js` - #[bpaf(long("stdin-file-path"), argument("PATH"), hide_usage)] - stdin_file_path: Option, - - /// The GritQL pattern to search for. - /// - /// Note that the search command (currently) does not support rewrites. - #[bpaf(positional("PATTERN"))] - pattern: String, - - /// Single file, single path or list of paths. - #[bpaf(positional("PATH"), many)] - paths: Vec, - }, - - /// Shows documentation of various aspects of the CLI. - /// - /// ## Examples - /// - /// ```shell - /// biome explain noDebugger - /// ``` - /// - /// ```shell - /// biome explain daemon-logs - /// ``` - #[bpaf(command)] - Explain { - /// Single name to display documentation for. - #[bpaf(positional("NAME"))] - doc: Doc, - }, - - #[bpaf(command)] - /// Cleans the logs emitted by the daemon. - Clean, - - #[bpaf(command("__run_server"), hide)] - RunServer { - /// Allows to change the prefix applied to the file name of the logs. - #[bpaf( - env("BIOME_LOG_PREFIX_NAME"), - long("log-prefix-name"), - argument("STRING"), - hide_usage, - fallback(String::from("server.log")), - display_fallback - )] - log_prefix_name: String, - /// Allows to change the folder where logs are stored. - #[bpaf( + log_path:PathBuf, + /// Allows to set a custom file path to the configuration file, + /// or a custom directory path to find `biome.json` or `biome.jsonc` + #[bpaf(env("BIOME_CONFIG_PATH"), long("config-path"), argument("PATH"))] + config_path:Option, + /// Bogus argument to make the command work with vscode-languageclient + #[bpaf(long("stdio"), hide, hide_usage, switch)] + stdio:bool, + }, + /// Updates the configuration when there are breaking changes. + #[bpaf(command)] + Migrate { + #[bpaf(external, hide_usage)] + cli_options:CliOptions, + + /// Writes the new configuration file to disk + #[bpaf(long("write"), switch)] + write:bool, + + /// Alias of `--write`, writes the new configuration file to disk + #[bpaf(long("fix"), switch, hide_usage)] + fix:bool, + + #[bpaf(external(migrate_sub_command), optional)] + sub_command:Option, + }, + + /// EXPERIMENTAL: Searches for Grit patterns across a project. + /// + /// Note: GritQL escapes code snippets using backticks, but most shells + /// interpret backticks as command invocations. To avoid this, it's best to + /// put single quotes around your Grit queries. + /// + /// ## Example + /// + /// ```shell + /// biome search '`console.log($message)`' # find all `console.log` invocations + /// ``` + #[bpaf(command)] + Search { + #[bpaf(external, hide_usage)] + cli_options:CliOptions, + + #[bpaf(external(partial_files_configuration), optional, hide_usage)] + files_configuration:Option, + + #[bpaf(external(partial_vcs_configuration), optional, hide_usage)] + vcs_configuration:Option, + + /// Use this option when you want to search through code piped from + /// `stdin`, and print the output to `stdout`. + /// + /// The file doesn't need to exist on disk, what matters is the + /// extension of the file. Based on the extension, Biome knows how to + /// parse the code. + /// + /// Example: `echo 'let a;' | biome search '`let $var`' + /// --stdin-file-path=file.js` + #[bpaf(long("stdin-file-path"), argument("PATH"), hide_usage)] + stdin_file_path:Option, + + /// The GritQL pattern to search for. + /// + /// Note that the search command (currently) does not support rewrites. + #[bpaf(positional("PATTERN"))] + pattern:String, + + /// Single file, single path or list of paths. + #[bpaf(positional("PATH"), many)] + paths:Vec, + }, + + /// Shows documentation of various aspects of the CLI. + /// + /// ## Examples + /// + /// ```shell + /// biome explain noDebugger + /// ``` + /// + /// ```shell + /// biome explain daemon-logs + /// ``` + #[bpaf(command)] + Explain { + /// Single name to display documentation for. + #[bpaf(positional("NAME"))] + doc:Doc, + }, + + #[bpaf(command)] + /// Cleans the logs emitted by the daemon. + Clean, + + #[bpaf(command("__run_server"), hide)] + RunServer { + /// Allows to change the prefix applied to the file name of the logs. + #[bpaf( + env("BIOME_LOG_PREFIX_NAME"), + long("log-prefix-name"), + argument("STRING"), + hide_usage, + fallback(String::from("server.log")), + display_fallback + )] + log_prefix_name:String, + /// Allows to change the folder where logs are stored. + #[bpaf( env("BIOME_LOG_PATH"), long("log-path"), argument("PATH"), hide_usage, fallback(biome_fs::ensure_cache_dir().join("biome-logs")), )] - log_path: PathBuf, - - #[bpaf(long("stop-on-disconnect"), hide_usage)] - stop_on_disconnect: bool, - /// Allows to set a custom file path to the configuration file, - /// or a custom directory path to find `biome.json` or `biome.jsonc` - #[bpaf(env("BIOME_CONFIG_PATH"), long("config-path"), argument("PATH"))] - config_path: Option, - }, - #[bpaf(command("__print_socket"), hide)] - PrintSocket, + log_path:PathBuf, + + #[bpaf(long("stop-on-disconnect"), hide_usage)] + stop_on_disconnect:bool, + /// Allows to set a custom file path to the configuration file, + /// or a custom directory path to find `biome.json` or `biome.jsonc` + #[bpaf(env("BIOME_CONFIG_PATH"), long("config-path"), argument("PATH"))] + config_path:Option, + }, + #[bpaf(command("__print_socket"), hide)] + PrintSocket, } #[derive(Debug, Bpaf, Clone)] pub enum MigrateSubCommand { - /// It attempts to find the files `.prettierrc`/`prettier.json` and `.prettierignore`, and map the Prettier's configuration into Biome's configuration file. - #[bpaf(command)] - Prettier, - /// It attempts to find the ESLint configuration file in the working directory, and update the Biome's configuration file as a result. - #[bpaf(command)] - Eslint { - /// Includes rules inspired from an eslint rule in the migration - #[bpaf(long("include-inspired"))] - include_inspired: bool, - /// Includes nursery rules in the migration - #[bpaf(long("include-nursery"))] - include_nursery: bool, - }, + /// It attempts to find the files `.prettierrc`/`prettier.json` and + /// `.prettierignore`, and map the Prettier's configuration into Biome's + /// configuration file. + #[bpaf(command)] + Prettier, + /// It attempts to find the ESLint configuration file in the working + /// directory, and update the Biome's configuration file as a result. + #[bpaf(command)] + Eslint { + /// Includes rules inspired from an eslint rule in the migration + #[bpaf(long("include-inspired"))] + include_inspired:bool, + /// Includes nursery rules in the migration + #[bpaf(long("include-nursery"))] + include_nursery:bool, + }, } impl MigrateSubCommand { - pub const fn is_prettier(&self) -> bool { - matches!(self, MigrateSubCommand::Prettier) - } + pub const fn is_prettier(&self) -> bool { matches!(self, MigrateSubCommand::Prettier) } } impl BiomeCommand { - const fn cli_options(&self) -> Option<&CliOptions> { - match self { - BiomeCommand::Version(cli_options) - | BiomeCommand::Rage(cli_options, ..) - | BiomeCommand::Check { cli_options, .. } - | BiomeCommand::Lint { cli_options, .. } - | BiomeCommand::Ci { cli_options, .. } - | BiomeCommand::Format { cli_options, .. } - | BiomeCommand::Migrate { cli_options, .. } - | BiomeCommand::Search { cli_options, .. } => Some(cli_options), - BiomeCommand::LspProxy { .. } - | BiomeCommand::Start { .. } - | BiomeCommand::Stop - | BiomeCommand::Init(_) - | BiomeCommand::Explain { .. } - | BiomeCommand::RunServer { .. } - | BiomeCommand::Clean { .. } - | BiomeCommand::PrintSocket => None, - } - } - - pub const fn get_color(&self) -> Option<&ColorsArg> { - match self.cli_options() { - Some(cli_options) => { - // To properly display GitHub annotations we need to disable colors - if matches!(cli_options.reporter, CliReporter::GitHub) { - return Some(&ColorsArg::Off); - } - // We want force colors in CI, to give e better UX experience - // Unless users explicitly set the colors flag - if matches!(self, BiomeCommand::Ci { .. }) && cli_options.colors.is_none() { - return Some(&ColorsArg::Force); - } - // Normal behaviors - cli_options.colors.as_ref() - } - - None => None, - } - } - - pub const fn should_use_server(&self) -> bool { - match self.cli_options() { - Some(cli_options) => cli_options.use_server, - None => false, - } - } - - pub const fn has_metrics(&self) -> bool { - false - } - - pub fn is_verbose(&self) -> bool { - self.cli_options() - .map_or(false, |cli_options| cli_options.verbose) - } - - pub fn log_level(&self) -> LoggingLevel { - self.cli_options() - .map_or(LoggingLevel::default(), |cli_options| cli_options.log_level) - } - - pub fn log_kind(&self) -> LoggingKind { - self.cli_options() - .map_or(LoggingKind::default(), |cli_options| cli_options.log_kind) - } + const fn cli_options(&self) -> Option<&CliOptions> { + match self { + BiomeCommand::Version(cli_options) + | BiomeCommand::Rage(cli_options, ..) + | BiomeCommand::Check { cli_options, .. } + | BiomeCommand::Lint { cli_options, .. } + | BiomeCommand::Ci { cli_options, .. } + | BiomeCommand::Format { cli_options, .. } + | BiomeCommand::Migrate { cli_options, .. } + | BiomeCommand::Search { cli_options, .. } => Some(cli_options), + BiomeCommand::LspProxy { .. } + | BiomeCommand::Start { .. } + | BiomeCommand::Stop + | BiomeCommand::Init(_) + | BiomeCommand::Explain { .. } + | BiomeCommand::RunServer { .. } + | BiomeCommand::Clean { .. } + | BiomeCommand::PrintSocket => None, + } + } + + pub const fn get_color(&self) -> Option<&ColorsArg> { + match self.cli_options() { + Some(cli_options) => { + // To properly display GitHub annotations we need to disable colors + if matches!(cli_options.reporter, CliReporter::GitHub) { + return Some(&ColorsArg::Off); + } + // We want force colors in CI, to give e better UX experience + // Unless users explicitly set the colors flag + if matches!(self, BiomeCommand::Ci { .. }) && cli_options.colors.is_none() { + return Some(&ColorsArg::Force); + } + // Normal behaviors + cli_options.colors.as_ref() + }, + + None => None, + } + } + + pub const fn should_use_server(&self) -> bool { + match self.cli_options() { + Some(cli_options) => cli_options.use_server, + None => false, + } + } + + pub const fn has_metrics(&self) -> bool { false } + + pub fn is_verbose(&self) -> bool { self.cli_options().map_or(false, |cli_options| cli_options.verbose) } + + pub fn log_level(&self) -> LoggingLevel { + self.cli_options() + .map_or(LoggingLevel::default(), |cli_options| cli_options.log_level) + } + + pub fn log_kind(&self) -> LoggingKind { + self.cli_options() + .map_or(LoggingKind::default(), |cli_options| cli_options.log_kind) + } } -/// It accepts a [LoadedPartialConfiguration] and it prints the diagnostics emitted during parsing and deserialization. +/// It accepts a [LoadedPartialConfiguration] and it prints the diagnostics +/// emitted during parsing and deserialization. /// /// If it contains [errors](Severity::Error) or higher, it returns an error. pub(crate) fn validate_configuration_diagnostics( - loaded_configuration: &LoadedConfiguration, - console: &mut dyn Console, - verbose: bool, + loaded_configuration:&LoadedConfiguration, + console:&mut dyn Console, + verbose:bool, ) -> Result<(), CliDiagnostic> { - if let Some(file_path) = loaded_configuration - .file_path - .as_ref() - .and_then(|f| f.file_name()) - .and_then(|f| f.to_str()) - { - if file_path == "rome.json" { - let diagnostic = DeprecatedConfigurationFile::new(file_path); - - if diagnostic.tags().is_verbose() && verbose { - console.error(markup! {{PrintDiagnostic::verbose(&diagnostic)}}) - } else { - console.error(markup! {{PrintDiagnostic::simple(&diagnostic)}}) - } - } - } - - let diagnostics = loaded_configuration.as_diagnostics_iter(); - - for diagnostic in diagnostics { - if diagnostic.tags().is_verbose() && verbose { - console.error(markup! {{PrintDiagnostic::verbose(diagnostic)}}) - } else { - console.error(markup! {{PrintDiagnostic::simple(diagnostic)}}) - } - } - - if loaded_configuration.has_errors() { - return Err(CliDiagnostic::workspace_error( - BiomeDiagnostic::invalid_configuration( - "Biome exited because the configuration resulted in errors. Please fix them.", - ) - .into(), - )); - } - - Ok(()) + if let Some(file_path) = loaded_configuration + .file_path + .as_ref() + .and_then(|f| f.file_name()) + .and_then(|f| f.to_str()) + { + if file_path == "rome.json" { + let diagnostic = DeprecatedConfigurationFile::new(file_path); + + if diagnostic.tags().is_verbose() && verbose { + console.error(markup! {{PrintDiagnostic::verbose(&diagnostic)}}) + } else { + console.error(markup! {{PrintDiagnostic::simple(&diagnostic)}}) + } + } + } + + let diagnostics = loaded_configuration.as_diagnostics_iter(); + + for diagnostic in diagnostics { + if diagnostic.tags().is_verbose() && verbose { + console.error(markup! {{PrintDiagnostic::verbose(diagnostic)}}) + } else { + console.error(markup! {{PrintDiagnostic::simple(diagnostic)}}) + } + } + + if loaded_configuration.has_errors() { + return Err(CliDiagnostic::workspace_error( + BiomeDiagnostic::invalid_configuration( + "Biome exited because the configuration resulted in errors. Please fix them.", + ) + .into(), + )); + } + + Ok(()) } -fn resolve_manifest( - fs: &DynRef<'_, dyn FileSystem>, -) -> Result, WorkspaceError> { - let result = fs.auto_search( - &fs.working_directory().unwrap_or_default(), - &["package.json"], - false, - )?; +fn resolve_manifest(fs:&DynRef<'_, dyn FileSystem>) -> Result, WorkspaceError> { + let result = fs.auto_search(&fs.working_directory().unwrap_or_default(), &["package.json"], false)?; - if let Some(result) = result { - return Ok(Some((BiomePath::new(result.file_path), result.content))); - } + if let Some(result) = result { + return Ok(Some((BiomePath::new(result.file_path), result.content))); + } - Ok(None) + Ok(None) } fn get_files_to_process_with_cli_options( - since: Option<&str>, - changed: bool, - staged: bool, - fs: &DynRef<'_, dyn FileSystem>, - configuration: &PartialConfiguration, + since:Option<&str>, + changed:bool, + staged:bool, + fs:&DynRef<'_, dyn FileSystem>, + configuration:&PartialConfiguration, ) -> Result>, CliDiagnostic> { - if since.is_some() { - if !changed { - return Err(CliDiagnostic::incompatible_arguments("since", "changed")); - } - - if staged { - return Err(CliDiagnostic::incompatible_arguments("since", "staged")); - } - } - - if changed { - if staged { - return Err(CliDiagnostic::incompatible_arguments("changed", "staged")); - } - - Ok(Some(get_changed_files(fs, configuration, since)?)) - } else if staged { - Ok(Some(get_staged_files(fs)?)) - } else { - Ok(None) - } + if since.is_some() { + if !changed { + return Err(CliDiagnostic::incompatible_arguments("since", "changed")); + } + + if staged { + return Err(CliDiagnostic::incompatible_arguments("since", "staged")); + } + } + + if changed { + if staged { + return Err(CliDiagnostic::incompatible_arguments("changed", "staged")); + } + + Ok(Some(get_changed_files(fs, configuration, since)?)) + } else if staged { + Ok(Some(get_staged_files(fs)?)) + } else { + Ok(None) + } } /// Holds the options to determine the fix file mode. pub(crate) struct FixFileModeOptions { - apply: bool, - apply_unsafe: bool, - write: bool, - suppress: bool, - suppression_reason: Option, - fix: bool, - unsafe_: bool, + apply:bool, + apply_unsafe:bool, + write:bool, + suppress:bool, + suppression_reason:Option, + fix:bool, + unsafe_:bool, } /// - [Result]: if the given options are incompatible /// - [Option]: if no fixes are requested /// - [FixFileMode]: if safe or unsafe fixes are requested pub(crate) fn determine_fix_file_mode( - options: FixFileModeOptions, - console: &mut dyn Console, + options:FixFileModeOptions, + console:&mut dyn Console, ) -> Result, CliDiagnostic> { - let FixFileModeOptions { - apply, - apply_unsafe, - write, - fix, - suppress, - suppression_reason: _, - unsafe_, - } = options; - - if apply || apply_unsafe { - let (deprecated, alternative) = if apply { - ("--apply", "--write") - } else { - ("--apply-unsafe", "--write --unsafe") - }; - - let diagnostic = DeprecatedArgument::new(markup! { - "The argument "{deprecated}" is deprecated, it will be removed in the next major release. Use "{alternative}" instead." - }); - - console.error(markup! {{PrintDiagnostic::simple(&diagnostic)}}); - } - - check_fix_incompatible_arguments(options)?; - - let safe_fixes = apply || write || fix; - - let unsafe_fixes = apply_unsafe || ((write || safe_fixes) && unsafe_); - - if unsafe_fixes { - Ok(Some(FixFileMode::SafeAndUnsafeFixes)) - } else if safe_fixes { - Ok(Some(FixFileMode::SafeFixes)) - } else if suppress { - Ok(Some(FixFileMode::ApplySuppressions)) - } else { - Ok(None) - } + let FixFileModeOptions { apply, apply_unsafe, write, fix, suppress, suppression_reason: _, unsafe_ } = options; + + if apply || apply_unsafe { + let (deprecated, alternative) = if apply { + ("--apply", "--write") + } else { + ("--apply-unsafe", "--write --unsafe") + }; + + let diagnostic = DeprecatedArgument::new(markup! { + "The argument "{deprecated}" is deprecated, it will be removed in the next major release. Use "{alternative}" instead." + }); + + console.error(markup! {{PrintDiagnostic::simple(&diagnostic)}}); + } + + check_fix_incompatible_arguments(options)?; + + let safe_fixes = apply || write || fix; + + let unsafe_fixes = apply_unsafe || ((write || safe_fixes) && unsafe_); + + if unsafe_fixes { + Ok(Some(FixFileMode::SafeAndUnsafeFixes)) + } else if safe_fixes { + Ok(Some(FixFileMode::SafeFixes)) + } else if suppress { + Ok(Some(FixFileMode::ApplySuppressions)) + } else { + Ok(None) + } } /// Checks if the fix file options are incompatible. -fn check_fix_incompatible_arguments(options: FixFileModeOptions) -> Result<(), CliDiagnostic> { - let FixFileModeOptions { - apply, - apply_unsafe, - write, - suppress, - suppression_reason, - fix, - unsafe_, - } = options; - - if apply && apply_unsafe { - return Err(CliDiagnostic::incompatible_arguments( - "--apply", - "--apply-unsafe", - )); - } else if apply_unsafe && unsafe_ { - return Err(CliDiagnostic::incompatible_arguments( - "--apply-unsafe", - "--unsafe", - )); - } else if apply && (fix || write) { - return Err(CliDiagnostic::incompatible_arguments( - "--apply", - if fix { "--fix" } else { "--write" }, - )); - } else if apply_unsafe && (fix || write) { - return Err(CliDiagnostic::incompatible_arguments( - "--apply-unsafe", - if fix { "--fix" } else { "--write" }, - )); - } else if write && fix { - return Err(CliDiagnostic::incompatible_arguments("--write", "--fix")); - } else if suppress && write { - return Err(CliDiagnostic::incompatible_arguments( - "--suppress", - "--write", - )); - } else if suppress && fix { - return Err(CliDiagnostic::incompatible_arguments("--suppress", "--fix")); - } else if !suppress && suppression_reason.is_some() { - return Err(CliDiagnostic::unexpected_argument( - "--reason", - "`--reason` is only valid when `--suppress` is used.", - )); - }; - - Ok(()) +fn check_fix_incompatible_arguments(options:FixFileModeOptions) -> Result<(), CliDiagnostic> { + let FixFileModeOptions { apply, apply_unsafe, write, suppress, suppression_reason, fix, unsafe_ } = options; + + if apply && apply_unsafe { + return Err(CliDiagnostic::incompatible_arguments("--apply", "--apply-unsafe")); + } else if apply_unsafe && unsafe_ { + return Err(CliDiagnostic::incompatible_arguments("--apply-unsafe", "--unsafe")); + } else if apply && (fix || write) { + return Err(CliDiagnostic::incompatible_arguments( + "--apply", + if fix { "--fix" } else { "--write" }, + )); + } else if apply_unsafe && (fix || write) { + return Err(CliDiagnostic::incompatible_arguments( + "--apply-unsafe", + if fix { "--fix" } else { "--write" }, + )); + } else if write && fix { + return Err(CliDiagnostic::incompatible_arguments("--write", "--fix")); + } else if suppress && write { + return Err(CliDiagnostic::incompatible_arguments("--suppress", "--write")); + } else if suppress && fix { + return Err(CliDiagnostic::incompatible_arguments("--suppress", "--fix")); + } else if !suppress && suppression_reason.is_some() { + return Err(CliDiagnostic::unexpected_argument( + "--reason", + "`--reason` is only valid when `--suppress` is used.", + )); + }; + + Ok(()) } /// Generic interface for executing commands. @@ -835,303 +834,276 @@ fn check_fix_incompatible_arguments(options: FixFileModeOptions) -> Result<(), C /// Optional methods: /// - [CommandRunner::check_incompatible_arguments] pub(crate) trait CommandRunner: Sized { - const COMMAND_NAME: &'static str; + const COMMAND_NAME:&'static str; - /// The main command to use. - fn run(&mut self, session: CliSession, cli_options: &CliOptions) -> Result<(), CliDiagnostic> { - setup_cli_subscriber(cli_options.log_level, cli_options.log_kind); + /// The main command to use. + fn run(&mut self, session:CliSession, cli_options:&CliOptions) -> Result<(), CliDiagnostic> { + setup_cli_subscriber(cli_options.log_level, cli_options.log_kind); - let fs = &session.app.fs; - - let console = &mut *session.app.console; - - let workspace = &*session.app.workspace; - - self.check_incompatible_arguments()?; - - let (execution, paths) = self.configure_workspace(fs, console, workspace, cli_options)?; - - execute_mode(execution, session, cli_options, paths) - } - - /// This function prepares the workspace with the following: - /// - Loading the configuration file. - /// - Configure the VCS integration - /// - Computes the paths to traverse/handle. This changes based on the VCS arguments that were passed. - /// - Register a project folder using the working directory. - /// - Resolves the closets manifest AKA `package.json` and registers it. - /// - Updates the settings that belong to the project registered - fn configure_workspace( - &mut self, - fs: &DynRef<'_, dyn FileSystem>, - console: &mut dyn Console, - workspace: &dyn Workspace, - cli_options: &CliOptions, - ) -> Result<(Execution, Vec), CliDiagnostic> { - let loaded_configuration = - load_configuration(fs, cli_options.as_configuration_path_hint())?; - - if self.should_validate_configuration_diagnostics() { - validate_configuration_diagnostics( - &loaded_configuration, - console, - cli_options.verbose, - )?; - } - - let configuration_path = loaded_configuration.directory_path.clone(); - - let configuration = self.merge_configuration(loaded_configuration, fs, console)?; - - let vcs_base_path = configuration_path.or(fs.working_directory()); - - let (vcs_base_path, gitignore_matches) = - configuration.retrieve_gitignore_matches(fs, vcs_base_path.as_deref())?; - - let paths = self.get_files_to_process(fs, &configuration)?; - - workspace.register_project_folder(RegisterProjectFolderParams { - path: fs.working_directory(), - set_as_current_workspace: true, - })?; - - let manifest_data = resolve_manifest(fs)?; - - if let Some(manifest_data) = manifest_data { - workspace.set_manifest_for_project(manifest_data.into())?; - } - - workspace.update_settings(UpdateSettingsParams { - workspace_directory: fs.working_directory(), - configuration, - vcs_base_path, - gitignore_matches, - })?; - - let execution = self.get_execution(cli_options, console, workspace)?; - - Ok((execution, paths)) - } - - /// Computes [Stdin] if the CLI has the necessary information. - /// - /// ## Errors - /// - If the user didn't provide anything via `stdin` but the option `--stdin-file-path` is passed. - fn get_stdin(&self, console: &mut dyn Console) -> Result, CliDiagnostic> { - let stdin = if let Some(stdin_file_path) = self.get_stdin_file_path() { - let input_code = console.read(); - - if let Some(input_code) = input_code { - let path = PathBuf::from(stdin_file_path); - - Some((path, input_code).into()) - } else { - // we provided the argument without a piped stdin, we bail - return Err(CliDiagnostic::missing_argument("stdin", Self::COMMAND_NAME)); - } - } else { - None - }; - - Ok(stdin) - } - - // Below, the methods that consumers must implement. - - /// Implements this method if you need to merge CLI arguments to the loaded configuration. - /// - /// The CLI arguments take precedence over the option configured in the configuration file. - fn merge_configuration( - &mut self, - loaded_configuration: LoadedConfiguration, - fs: &DynRef<'_, dyn FileSystem>, - console: &mut dyn Console, - ) -> Result; - - /// It returns the paths that need to be handled/traversed. - fn get_files_to_process( - &self, - fs: &DynRef<'_, dyn FileSystem>, - configuration: &PartialConfiguration, - ) -> Result, CliDiagnostic>; - - /// It returns the file path to use in `stdin` mode. - fn get_stdin_file_path(&self) -> Option<&str>; - - /// Whether the command should write the files. - fn should_write(&self) -> bool; - - /// Returns the [Execution] mode. - fn get_execution( - &self, - cli_options: &CliOptions, - console: &mut dyn Console, - workspace: &dyn Workspace, - ) -> Result; - - // Below, methods that consumers can implement - - /// Optional method that can be implemented to check if some CLI arguments aren't compatible. - /// - /// The method is called before loading the configuration from disk. - fn check_incompatible_arguments(&self) -> Result<(), CliDiagnostic> { - Ok(()) - } - - /// Checks whether the configuration has errors. - fn should_validate_configuration_diagnostics(&self) -> bool { - true - } + let fs = &session.app.fs; + + let console = &mut *session.app.console; + + let workspace = &*session.app.workspace; + + self.check_incompatible_arguments()?; + + let (execution, paths) = self.configure_workspace(fs, console, workspace, cli_options)?; + + execute_mode(execution, session, cli_options, paths) + } + + /// This function prepares the workspace with the following: + /// - Loading the configuration file. + /// - Configure the VCS integration + /// - Computes the paths to traverse/handle. This changes based on the VCS + /// arguments that were passed. + /// - Register a project folder using the working directory. + /// - Resolves the closets manifest AKA `package.json` and registers it. + /// - Updates the settings that belong to the project registered + fn configure_workspace( + &mut self, + fs:&DynRef<'_, dyn FileSystem>, + console:&mut dyn Console, + workspace:&dyn Workspace, + cli_options:&CliOptions, + ) -> Result<(Execution, Vec), CliDiagnostic> { + let loaded_configuration = load_configuration(fs, cli_options.as_configuration_path_hint())?; + + if self.should_validate_configuration_diagnostics() { + validate_configuration_diagnostics(&loaded_configuration, console, cli_options.verbose)?; + } + + let configuration_path = loaded_configuration.directory_path.clone(); + + let configuration = self.merge_configuration(loaded_configuration, fs, console)?; + + let vcs_base_path = configuration_path.or(fs.working_directory()); + + let (vcs_base_path, gitignore_matches) = + configuration.retrieve_gitignore_matches(fs, vcs_base_path.as_deref())?; + + let paths = self.get_files_to_process(fs, &configuration)?; + + workspace.register_project_folder(RegisterProjectFolderParams { + path:fs.working_directory(), + set_as_current_workspace:true, + })?; + + let manifest_data = resolve_manifest(fs)?; + + if let Some(manifest_data) = manifest_data { + workspace.set_manifest_for_project(manifest_data.into())?; + } + + workspace.update_settings(UpdateSettingsParams { + workspace_directory:fs.working_directory(), + configuration, + vcs_base_path, + gitignore_matches, + })?; + + let execution = self.get_execution(cli_options, console, workspace)?; + + Ok((execution, paths)) + } + + /// Computes [Stdin] if the CLI has the necessary information. + /// + /// ## Errors + /// - If the user didn't provide anything via `stdin` but the option + /// `--stdin-file-path` is passed. + fn get_stdin(&self, console:&mut dyn Console) -> Result, CliDiagnostic> { + let stdin = if let Some(stdin_file_path) = self.get_stdin_file_path() { + let input_code = console.read(); + + if let Some(input_code) = input_code { + let path = PathBuf::from(stdin_file_path); + + Some((path, input_code).into()) + } else { + // we provided the argument without a piped stdin, we bail + return Err(CliDiagnostic::missing_argument("stdin", Self::COMMAND_NAME)); + } + } else { + None + }; + + Ok(stdin) + } + + // Below, the methods that consumers must implement. + + /// Implements this method if you need to merge CLI arguments to the loaded + /// configuration. + /// + /// The CLI arguments take precedence over the option configured in the + /// configuration file. + fn merge_configuration( + &mut self, + loaded_configuration:LoadedConfiguration, + fs:&DynRef<'_, dyn FileSystem>, + console:&mut dyn Console, + ) -> Result; + + /// It returns the paths that need to be handled/traversed. + fn get_files_to_process( + &self, + fs:&DynRef<'_, dyn FileSystem>, + configuration:&PartialConfiguration, + ) -> Result, CliDiagnostic>; + + /// It returns the file path to use in `stdin` mode. + fn get_stdin_file_path(&self) -> Option<&str>; + + /// Whether the command should write the files. + fn should_write(&self) -> bool; + + /// Returns the [Execution] mode. + fn get_execution( + &self, + cli_options:&CliOptions, + console:&mut dyn Console, + workspace:&dyn Workspace, + ) -> Result; + + // Below, methods that consumers can implement + + /// Optional method that can be implemented to check if some CLI arguments + /// aren't compatible. + /// + /// The method is called before loading the configuration from disk. + fn check_incompatible_arguments(&self) -> Result<(), CliDiagnostic> { Ok(()) } + + /// Checks whether the configuration has errors. + fn should_validate_configuration_diagnostics(&self) -> bool { true } } pub trait LoadEditorConfig: CommandRunner { - /// Whether this command should load the `.editorconfig` file. - fn should_load_editor_config(&self, fs_configuration: &PartialConfiguration) -> bool; - - /// It loads the `.editorconfig` from the file system, parses it and deserialize it into a [PartialConfiguration] - fn load_editor_config( - &self, - configuration_path: Option, - fs_configuration: &PartialConfiguration, - fs: &DynRef<'_, dyn FileSystem>, - console: &mut dyn Console, - ) -> Result { - Ok(if self.should_load_editor_config(fs_configuration) { - let (editorconfig, editorconfig_diagnostics) = { - let search_path = configuration_path - .clone() - .unwrap_or_else(|| fs.working_directory().unwrap_or_default()); - - load_editorconfig(fs, search_path)? - }; - - for diagnostic in editorconfig_diagnostics { - console.error(markup! { - {PrintDiagnostic::simple(&diagnostic)} - }) - } - - editorconfig.unwrap_or_default() - } else { - Default::default() - }) - } + /// Whether this command should load the `.editorconfig` file. + fn should_load_editor_config(&self, fs_configuration:&PartialConfiguration) -> bool; + + /// It loads the `.editorconfig` from the file system, parses it and + /// deserialize it into a [PartialConfiguration] + fn load_editor_config( + &self, + configuration_path:Option, + fs_configuration:&PartialConfiguration, + fs:&DynRef<'_, dyn FileSystem>, + console:&mut dyn Console, + ) -> Result { + Ok(if self.should_load_editor_config(fs_configuration) { + let (editorconfig, editorconfig_diagnostics) = { + let search_path = configuration_path + .clone() + .unwrap_or_else(|| fs.working_directory().unwrap_or_default()); + + load_editorconfig(fs, search_path)? + }; + + for diagnostic in editorconfig_diagnostics { + console.error(markup! { + {PrintDiagnostic::simple(&diagnostic)} + }) + } + + editorconfig.unwrap_or_default() + } else { + Default::default() + }) + } } #[cfg(test)] mod tests { - use biome_console::BufferConsole; - - use super::*; - - #[test] - fn incompatible_arguments() { - for (apply, apply_unsafe, write, suppress, suppression_reason, fix, unsafe_) in [ - (true, true, false, false, None, false, false), // --apply --apply-unsafe - (true, false, true, false, None, false, false), // --apply --write - (true, false, false, false, None, true, false), // --apply --fix - (false, true, false, false, None, false, true), // --apply-unsafe --unsafe - (false, true, true, false, None, false, false), // --apply-unsafe --write - (false, true, false, false, None, true, false), // --apply-unsafe --fix - (false, false, true, false, None, true, false), // --write --fix - ] { - assert!(check_fix_incompatible_arguments(FixFileModeOptions { - apply, - apply_unsafe, - write, - suppress, - suppression_reason, - fix, - unsafe_ - }) - .is_err()); - } - } - - #[test] - fn safe_fixes() { - let mut console = BufferConsole::default(); - - for (apply, apply_unsafe, write, suppress, suppression_reason, fix, unsafe_) in [ - (true, false, false, false, None, false, false), // --apply - (false, false, true, false, None, false, false), // --write - (false, false, false, false, None, true, false), // --fix - ] { - assert_eq!( - determine_fix_file_mode( - FixFileModeOptions { - apply, - apply_unsafe, - write, - suppress, - suppression_reason, - fix, - unsafe_ - }, - &mut console - ) - .unwrap(), - Some(FixFileMode::SafeFixes) - ); - } - } - - #[test] - fn safe_and_unsafe_fixes() { - let mut console = BufferConsole::default(); - - for (apply, apply_unsafe, write, suppress, suppression_reason, fix, unsafe_) in [ - (false, true, false, false, None, false, false), // --apply-unsafe - (false, false, true, false, None, false, true), // --write --unsafe - (false, false, false, false, None, true, true), // --fix --unsafe - ] { - assert_eq!( - determine_fix_file_mode( - FixFileModeOptions { - apply, - apply_unsafe, - write, - suppress, - suppression_reason, - fix, - unsafe_ - }, - &mut console - ) - .unwrap(), - Some(FixFileMode::SafeAndUnsafeFixes) - ); - } - } - - #[test] - fn no_fix() { - let mut console = BufferConsole::default(); - - let (apply, apply_unsafe, write, suppress, suppression_reason, fix, unsafe_) = - (false, false, false, false, None, false, false); - - assert_eq!( - determine_fix_file_mode( - FixFileModeOptions { - apply, - apply_unsafe, - write, - suppress, - suppression_reason, - fix, - unsafe_ - }, - &mut console - ) - .unwrap(), - None - ); - } - - /// Tests that all CLI options adhere to the invariants expected by `bpaf`. - #[test] - fn check_options() { - biome_command().check_invariants(false); - } + use biome_console::BufferConsole; + + use super::*; + + #[test] + fn incompatible_arguments() { + for (apply, apply_unsafe, write, suppress, suppression_reason, fix, unsafe_) in [ + (true, true, false, false, None, false, false), // --apply --apply-unsafe + (true, false, true, false, None, false, false), // --apply --write + (true, false, false, false, None, true, false), // --apply --fix + (false, true, false, false, None, false, true), // --apply-unsafe --unsafe + (false, true, true, false, None, false, false), // --apply-unsafe --write + (false, true, false, false, None, true, false), // --apply-unsafe --fix + (false, false, true, false, None, true, false), // --write --fix + ] { + assert!( + check_fix_incompatible_arguments(FixFileModeOptions { + apply, + apply_unsafe, + write, + suppress, + suppression_reason, + fix, + unsafe_ + }) + .is_err() + ); + } + } + + #[test] + fn safe_fixes() { + let mut console = BufferConsole::default(); + + for (apply, apply_unsafe, write, suppress, suppression_reason, fix, unsafe_) in [ + (true, false, false, false, None, false, false), // --apply + (false, false, true, false, None, false, false), // --write + (false, false, false, false, None, true, false), // --fix + ] { + assert_eq!( + determine_fix_file_mode( + FixFileModeOptions { apply, apply_unsafe, write, suppress, suppression_reason, fix, unsafe_ }, + &mut console + ) + .unwrap(), + Some(FixFileMode::SafeFixes) + ); + } + } + + #[test] + fn safe_and_unsafe_fixes() { + let mut console = BufferConsole::default(); + + for (apply, apply_unsafe, write, suppress, suppression_reason, fix, unsafe_) in [ + (false, true, false, false, None, false, false), // --apply-unsafe + (false, false, true, false, None, false, true), // --write --unsafe + (false, false, false, false, None, true, true), // --fix --unsafe + ] { + assert_eq!( + determine_fix_file_mode( + FixFileModeOptions { apply, apply_unsafe, write, suppress, suppression_reason, fix, unsafe_ }, + &mut console + ) + .unwrap(), + Some(FixFileMode::SafeAndUnsafeFixes) + ); + } + } + + #[test] + fn no_fix() { + let mut console = BufferConsole::default(); + + let (apply, apply_unsafe, write, suppress, suppression_reason, fix, unsafe_) = + (false, false, false, false, None, false, false); + + assert_eq!( + determine_fix_file_mode( + FixFileModeOptions { apply, apply_unsafe, write, suppress, suppression_reason, fix, unsafe_ }, + &mut console + ) + .unwrap(), + None + ); + } + + /// Tests that all CLI options adhere to the invariants expected by `bpaf`. + #[test] + fn check_options() { biome_command().check_invariants(false); } } diff --git a/crates/biome_cli/Source/commands/rage.rs b/crates/biome_cli/Source/commands/rage.rs index 905ed85df016..39208188a3fa 100644 --- a/crates/biome_cli/Source/commands/rage.rs +++ b/crates/biome_cli/Source/commands/rage.rs @@ -1,237 +1,243 @@ +use std::{env, io, ops::Deref, path::PathBuf}; + use biome_configuration::{ConfigurationPathHint, Rules}; -use biome_console::fmt::{Display, Formatter}; use biome_console::{ - fmt, markup, ConsoleExt, DebugDisplay, DebugDisplayOption, HorizontalLine, KeyValuePair, - Padding, SOFT_LINE, + ConsoleExt, + DebugDisplay, + DebugDisplayOption, + HorizontalLine, + KeyValuePair, + Padding, + SOFT_LINE, + fmt, + fmt::{Display, Formatter}, + markup, +}; +use biome_diagnostics::{ + PrintDescription, + termcolor, + termcolor::{ColorChoice, WriteColor}, }; -use biome_diagnostics::termcolor::{ColorChoice, WriteColor}; -use biome_diagnostics::{termcolor, PrintDescription}; use biome_flags::biome_env; use biome_fs::FileSystem; -use biome_service::configuration::{load_configuration, LoadedConfiguration}; -use biome_service::workspace::{client, RageEntry, RageParams}; -use biome_service::{DynRef, Workspace}; -use std::path::PathBuf; -use std::{env, io, ops::Deref}; +use biome_service::{ + DynRef, + Workspace, + configuration::{LoadedConfiguration, load_configuration}, + workspace::{RageEntry, RageParams, client}, +}; use tokio::runtime::Runtime; -use crate::commands::daemon::read_most_recent_log_file; -use crate::service::enumerate_pipes; -use crate::{service, CliDiagnostic, CliSession, VERSION}; +use crate::{ + CliDiagnostic, + CliSession, + VERSION, + commands::daemon::read_most_recent_log_file, + service, + service::enumerate_pipes, +}; /// Handler for the `rage` command -pub(crate) fn rage( - session: CliSession, - daemon_logs: bool, - formatter: bool, - linter: bool, -) -> Result<(), CliDiagnostic> { - let terminal_supports_colors = termcolor::BufferWriter::stdout(ColorChoice::Auto) - .buffer() - .supports_color(); - - let biome_env = biome_env(); - - session.app.console.log(markup!("CLI:\n" - {KeyValuePair("Version", markup!({VERSION}))} - {KeyValuePair("Color support", markup!({DebugDisplay(terminal_supports_colors)}))} - - {Section("Platform")} - {KeyValuePair("CPU Architecture", markup!({std::env::consts::ARCH}))} - {KeyValuePair("OS", markup!({std::env::consts::OS}))} - {Section("Environment")} - {biome_env} - {EnvVarOs("NO_COLOR")} - {EnvVarOs("TERM")} - {EnvVarOs("JS_RUNTIME_VERSION")} - {EnvVarOs("JS_RUNTIME_NAME")} - {EnvVarOs("NODE_PACKAGE_MANAGER")} - - {RageConfiguration { fs: &session.app.fs, formatter, linter }} - {WorkspaceRage(session.app.workspace.deref())} - )); - - if daemon_logs { - match session.app.workspace.server_info() { - Some(_) => { - session.app.console.log(markup!({ - ConnectedClientServerLog(session.app.workspace.deref()) - })); - } - - None => { - session - .app - .console - .log(markup!("Discovering running Biome servers...")); - - session.app.console.log(markup!({ RunningRomeServer })); - } - } - } - - Ok(()) +pub(crate) fn rage(session:CliSession, daemon_logs:bool, formatter:bool, linter:bool) -> Result<(), CliDiagnostic> { + let terminal_supports_colors = termcolor::BufferWriter::stdout(ColorChoice::Auto).buffer().supports_color(); + + let biome_env = biome_env(); + + session.app.console.log(markup!("CLI:\n" + {KeyValuePair("Version", markup!({VERSION}))} + {KeyValuePair("Color support", markup!({DebugDisplay(terminal_supports_colors)}))} + + {Section("Platform")} + {KeyValuePair("CPU Architecture", markup!({std::env::consts::ARCH}))} + {KeyValuePair("OS", markup!({std::env::consts::OS}))} + {Section("Environment")} + {biome_env} + {EnvVarOs("NO_COLOR")} + {EnvVarOs("TERM")} + {EnvVarOs("JS_RUNTIME_VERSION")} + {EnvVarOs("JS_RUNTIME_NAME")} + {EnvVarOs("NODE_PACKAGE_MANAGER")} + + {RageConfiguration { fs: &session.app.fs, formatter, linter }} + {WorkspaceRage(session.app.workspace.deref())} + )); + + if daemon_logs { + match session.app.workspace.server_info() { + Some(_) => { + session + .app + .console + .log(markup!({ ConnectedClientServerLog(session.app.workspace.deref()) })); + }, + + None => { + session.app.console.log(markup!("Discovering running Biome servers...")); + + session.app.console.log(markup!({ RunningRomeServer })); + }, + } + } + + Ok(()) } struct WorkspaceRage<'a>(&'a dyn Workspace); impl Display for WorkspaceRage<'_> { - fn fmt(&self, fmt: &mut Formatter) -> io::Result<()> { - let workspace = self.0; - - let rage_result = workspace.rage(RageParams {}); - - match rage_result { - Ok(result) => { - for entry in result.entries { - match entry { - RageEntry::Section(title) => { - Section(&title).fmt(fmt)?; - } - - RageEntry::Pair { name, value } => { - KeyValuePair(&name, markup!({ value })).fmt(fmt)?; - } - - RageEntry::Markup(markup) => markup.fmt(fmt)?, - } - } - - Ok(()) - } - - Err(err) => { - writeln!(fmt)?; - (markup! {"\u{2716} Workspace rage failed:"}).fmt(fmt)?; - - writeln!(fmt, " {err}") - } - } - } + fn fmt(&self, fmt:&mut Formatter) -> io::Result<()> { + let workspace = self.0; + + let rage_result = workspace.rage(RageParams {}); + + match rage_result { + Ok(result) => { + for entry in result.entries { + match entry { + RageEntry::Section(title) => { + Section(&title).fmt(fmt)?; + }, + + RageEntry::Pair { name, value } => { + KeyValuePair(&name, markup!({ value })).fmt(fmt)?; + }, + + RageEntry::Markup(markup) => markup.fmt(fmt)?, + } + } + + Ok(()) + }, + + Err(err) => { + writeln!(fmt)?; + (markup! {"\u{2716} Workspace rage failed:"}).fmt(fmt)?; + + writeln!(fmt, " {err}") + }, + } + } } /// Prints information about other running biome server instances. struct RunningRomeServer; impl Display for RunningRomeServer { - fn fmt(&self, f: &mut Formatter) -> io::Result<()> { - let versions = match enumerate_pipes() { - Ok(iter) => iter, - Err(err) => { - (markup! {"\u{2716} Enumerating Biome instances failed:"}).fmt(f)?; - - return writeln!(f, " {err}"); - } - }; - - for version in versions { - if version == biome_configuration::VERSION { - let runtime = Runtime::new()?; - - match service::open_transport(runtime) { - Ok(None) => { - markup!( - {Section("Server")} - {KeyValuePair("Status", markup!("stopped"))} - ) - .fmt(f)?; - - continue; - } - - Ok(Some(transport)) => { - markup!("\n""Running Biome Server:"" "{HorizontalLine::new(78)}" + fn fmt(&self, f:&mut Formatter) -> io::Result<()> { + let versions = match enumerate_pipes() { + Ok(iter) => iter, + Err(err) => { + (markup! {"\u{2716} Enumerating Biome instances failed:"}).fmt(f)?; + + return writeln!(f, " {err}"); + }, + }; + + for version in versions { + if version == biome_configuration::VERSION { + let runtime = Runtime::new()?; + + match service::open_transport(runtime) { + Ok(None) => { + markup!( + {Section("Server")} + {KeyValuePair("Status", markup!("stopped"))} + ) + .fmt(f)?; + + continue; + }, + + Ok(Some(transport)) => { + markup!("\n""Running Biome Server:"" "{HorizontalLine::new(78)}" ""\u{2139} The client isn't connected to any server but rage discovered this running Biome server."" ") - .fmt(f)?; + .fmt(f)?; - match client(transport) { - Ok(client) => WorkspaceRage(client.deref()).fmt(f)?, - Err(err) => { - markup!("\u{2716} Failed to connect: ").fmt(f)?; + match client(transport) { + Ok(client) => WorkspaceRage(client.deref()).fmt(f)?, + Err(err) => { + markup!("\u{2716} Failed to connect: ").fmt(f)?; - writeln!(f, "{err}")?; - } - } - } + writeln!(f, "{err}")?; + }, + } + }, - Err(err) => { - markup!("\n""\u{2716} Failed to connect: ").fmt(f)?; + Err(err) => { + markup!("\n""\u{2716} Failed to connect: ").fmt(f)?; - writeln!(f, "{err}")?; - } - } + writeln!(f, "{err}")?; + }, + } - BiomeServerLog.fmt(f)?; - } else { - markup!("\n""Incompatible Biome Server:"" "{HorizontalLine::new(78)}" + BiomeServerLog.fmt(f)?; + } else { + markup!("\n""Incompatible Biome Server:"" "{HorizontalLine::new(78)}" ""\u{2139} Rage discovered this running server using an incompatible version of Biome."" ") - .fmt(f)?; - - markup!( - {Section("Server")} - {KeyValuePair("Version", markup!({version.as_str()}))} - ) - .fmt(f)?; - } - } - - Ok(()) - } + .fmt(f)?; + + markup!( + {Section("Server")} + {KeyValuePair("Version", markup!({version.as_str()}))} + ) + .fmt(f)?; + } + } + + Ok(()) + } } struct RageConfiguration<'a, 'app> { - fs: &'a DynRef<'app, dyn FileSystem>, - formatter: bool, - linter: bool, + fs:&'a DynRef<'app, dyn FileSystem>, + formatter:bool, + linter:bool, } impl Display for RageConfiguration<'_, '_> { - fn fmt(&self, fmt: &mut Formatter) -> io::Result<()> { - Section("Biome Configuration").fmt(fmt)?; - - match load_configuration(self.fs, ConfigurationPathHint::default()) { - Ok(loaded_configuration) => { - if loaded_configuration.directory_path.is_none() { - KeyValuePair("Status", markup!("unset")).fmt(fmt)?; - } else { - let LoadedConfiguration { - configuration, - diagnostics, - .. - } = loaded_configuration; - - let status = if !diagnostics.is_empty() { - for diagnostic in diagnostics { - (markup! { - {KeyValuePair("Error", markup!{ - {format!{"{}", PrintDescription(&diagnostic)}} - })} - }) - .fmt(fmt)?; - } - - markup!("Loaded with errors") - } else { - markup!("Loaded successfully") - }; - - markup! ( - {KeyValuePair("Status", status)} - {KeyValuePair("Formatter disabled", markup!({DebugDisplay(configuration.is_formatter_disabled())}))} - {KeyValuePair("Linter disabled", markup!({DebugDisplay(configuration.is_linter_disabled())}))} - {KeyValuePair("Organize imports disabled", markup!({DebugDisplay(configuration.is_organize_imports_disabled())}))} - {KeyValuePair("VCS disabled", markup!({DebugDisplay(configuration.is_vcs_disabled())}))} - ).fmt(fmt)?; - - // Print formatter configuration if --formatter option is true - if self.formatter { - let formatter_configuration = configuration.get_formatter_configuration(); - - markup! ( + fn fmt(&self, fmt:&mut Formatter) -> io::Result<()> { + Section("Biome Configuration").fmt(fmt)?; + + match load_configuration(self.fs, ConfigurationPathHint::default()) { + Ok(loaded_configuration) => { + if loaded_configuration.directory_path.is_none() { + KeyValuePair("Status", markup!("unset")).fmt(fmt)?; + } else { + let LoadedConfiguration { configuration, diagnostics, .. } = loaded_configuration; + + let status = if !diagnostics.is_empty() { + for diagnostic in diagnostics { + (markup! { + {KeyValuePair("Error", markup!{ + {format!{"{}", PrintDescription(&diagnostic)}} + })} + }) + .fmt(fmt)?; + } + + markup!("Loaded with errors") + } else { + markup!("Loaded successfully") + }; + + markup! ( + {KeyValuePair("Status", status)} + {KeyValuePair("Formatter disabled", markup!({DebugDisplay(configuration.is_formatter_disabled())}))} + {KeyValuePair("Linter disabled", markup!({DebugDisplay(configuration.is_linter_disabled())}))} + {KeyValuePair("Organize imports disabled", markup!({DebugDisplay(configuration.is_organize_imports_disabled())}))} + {KeyValuePair("VCS disabled", markup!({DebugDisplay(configuration.is_vcs_disabled())}))} + ) + .fmt(fmt)?; + + // Print formatter configuration if --formatter option is true + if self.formatter { + let formatter_configuration = configuration.get_formatter_configuration(); + + markup! ( {Section("Formatter")} {KeyValuePair("Format with errors", markup!({DebugDisplay(configuration.get_formatter_configuration().format_with_errors)}))} {KeyValuePair("Indent style", markup!({DebugDisplay(formatter_configuration.indent_style)}))} @@ -244,10 +250,9 @@ impl Display for RageConfiguration<'_, '_> { {KeyValuePair("Include", markup!({DebugDisplay(formatter_configuration.include.iter().collect::>())}))} ).fmt(fmt)?; - let javascript_formatter_configuration = - configuration.get_javascript_formatter_configuration(); + let javascript_formatter_configuration = configuration.get_javascript_formatter_configuration(); - markup! ( + markup! ( {Section("JavaScript Formatter")} {KeyValuePair("Enabled", markup!({DebugDisplay(javascript_formatter_configuration.enabled)}))} {KeyValuePair("JSX quote style", markup!({DebugDisplay(javascript_formatter_configuration.jsx_quote_style)}))} @@ -266,10 +271,9 @@ impl Display for RageConfiguration<'_, '_> { ) .fmt(fmt)?; - let json_formatter_configuration = - configuration.get_json_formatter_configuration(); + let json_formatter_configuration = configuration.get_json_formatter_configuration(); - markup! ( + markup! ( {Section("JSON Formatter")} {KeyValuePair("Enabled", markup!({DebugDisplay(json_formatter_configuration.enabled)}))} {KeyValuePair("Indent style", markup!({DebugDisplayOption(json_formatter_configuration.indent_style)}))} @@ -279,130 +283,128 @@ impl Display for RageConfiguration<'_, '_> { {KeyValuePair("Trailing Commas", markup!({DebugDisplayOption(json_formatter_configuration.trailing_commas)}))} ).fmt(fmt)?; - let css_formatter_configuration = - configuration.get_css_formatter_configuration(); - - markup! ( - {Section("CSS Formatter")} - {KeyValuePair("Enabled", markup!({DebugDisplay(css_formatter_configuration.enabled)}))} - {KeyValuePair("Indent style", markup!({DebugDisplayOption(css_formatter_configuration.indent_style)}))} - {KeyValuePair("Indent width", markup!({DebugDisplayOption(css_formatter_configuration.indent_width)}))} - {KeyValuePair("Line ending", markup!({DebugDisplayOption(css_formatter_configuration.line_ending)}))} - {KeyValuePair("Line width", markup!({DebugDisplayOption(css_formatter_configuration.line_width)}))} - {KeyValuePair("Quote style", markup!({DebugDisplay(css_formatter_configuration.quote_style)}))} - ).fmt(fmt)?; - - let graphql_formatter_configuration = - configuration.get_graphql_formatter_configuration(); - - markup! ( - {Section("GraphQL Formatter")} - {KeyValuePair("Enabled", markup!({DebugDisplayOption(graphql_formatter_configuration.enabled)}))} - {KeyValuePair("Indent style", markup!({DebugDisplayOption(graphql_formatter_configuration.indent_style)}))} - {KeyValuePair("Indent width", markup!({DebugDisplayOption(graphql_formatter_configuration.indent_width)}))} - {KeyValuePair("Line ending", markup!({DebugDisplayOption(graphql_formatter_configuration.line_ending)}))} - {KeyValuePair("Line width", markup!({DebugDisplayOption(graphql_formatter_configuration.line_width)}))} - {KeyValuePair("Bracket spacing", markup!({DebugDisplayOption(graphql_formatter_configuration.bracket_spacing)}))} - {KeyValuePair("Quote style", markup!({DebugDisplayOption(graphql_formatter_configuration.quote_style)}))} - ).fmt(fmt)?; - } - - // Print linter configuration if --linter option is true - if self.linter { - let linter_configuration = configuration.get_linter_rules(); - - let javascript_linter = configuration.get_javascript_linter_configuration(); - - let json_linter = configuration.get_json_linter_configuration(); - - let css_linter = configuration.get_css_linter_configuration(); - - let graphq_linter = configuration.get_graphql_linter_configuration(); - - markup! ( - {Section("Linter")} - {KeyValuePair("JavaScript enabled", markup!({DebugDisplay(javascript_linter.enabled)}))} - {KeyValuePair("JSON enabled", markup!({DebugDisplay(json_linter.enabled)}))} - {KeyValuePair("CSS enabled", markup!({DebugDisplay(css_linter.enabled)}))} - {KeyValuePair("GraphQL enabled", markup!({DebugDisplay(graphq_linter.enabled)}))} - {KeyValuePair("Recommended", markup!({DebugDisplay(linter_configuration.recommended.unwrap_or_default())}))} - {KeyValuePair("All", markup!({DebugDisplay(linter_configuration.all.unwrap_or_default())}))} - {RageConfigurationLintRules("Enabled rules", linter_configuration)} - ).fmt(fmt)?; - } - } - } - - Err(err) => markup! ( - {KeyValuePair("Status", markup!("Failed to load"))} - {KeyValuePair("Error", markup!({format!("{err}")}))} - ) - .fmt(fmt)?, - } - - Ok(()) - } + let css_formatter_configuration = configuration.get_css_formatter_configuration(); + + markup! ( + {Section("CSS Formatter")} + {KeyValuePair("Enabled", markup!({DebugDisplay(css_formatter_configuration.enabled)}))} + {KeyValuePair("Indent style", markup!({DebugDisplayOption(css_formatter_configuration.indent_style)}))} + {KeyValuePair("Indent width", markup!({DebugDisplayOption(css_formatter_configuration.indent_width)}))} + {KeyValuePair("Line ending", markup!({DebugDisplayOption(css_formatter_configuration.line_ending)}))} + {KeyValuePair("Line width", markup!({DebugDisplayOption(css_formatter_configuration.line_width)}))} + {KeyValuePair("Quote style", markup!({DebugDisplay(css_formatter_configuration.quote_style)}))} + ) + .fmt(fmt)?; + + let graphql_formatter_configuration = configuration.get_graphql_formatter_configuration(); + + markup! ( + {Section("GraphQL Formatter")} + {KeyValuePair("Enabled", markup!({DebugDisplayOption(graphql_formatter_configuration.enabled)}))} + {KeyValuePair("Indent style", markup!({DebugDisplayOption(graphql_formatter_configuration.indent_style)}))} + {KeyValuePair("Indent width", markup!({DebugDisplayOption(graphql_formatter_configuration.indent_width)}))} + {KeyValuePair("Line ending", markup!({DebugDisplayOption(graphql_formatter_configuration.line_ending)}))} + {KeyValuePair("Line width", markup!({DebugDisplayOption(graphql_formatter_configuration.line_width)}))} + {KeyValuePair("Bracket spacing", markup!({DebugDisplayOption(graphql_formatter_configuration.bracket_spacing)}))} + {KeyValuePair("Quote style", markup!({DebugDisplayOption(graphql_formatter_configuration.quote_style)}))} + ) + .fmt(fmt)?; + } + + // Print linter configuration if --linter option is true + if self.linter { + let linter_configuration = configuration.get_linter_rules(); + + let javascript_linter = configuration.get_javascript_linter_configuration(); + + let json_linter = configuration.get_json_linter_configuration(); + + let css_linter = configuration.get_css_linter_configuration(); + + let graphq_linter = configuration.get_graphql_linter_configuration(); + + markup! ( + {Section("Linter")} + {KeyValuePair("JavaScript enabled", markup!({DebugDisplay(javascript_linter.enabled)}))} + {KeyValuePair("JSON enabled", markup!({DebugDisplay(json_linter.enabled)}))} + {KeyValuePair("CSS enabled", markup!({DebugDisplay(css_linter.enabled)}))} + {KeyValuePair("GraphQL enabled", markup!({DebugDisplay(graphq_linter.enabled)}))} + {KeyValuePair("Recommended", markup!({DebugDisplay(linter_configuration.recommended.unwrap_or_default())}))} + {KeyValuePair("All", markup!({DebugDisplay(linter_configuration.all.unwrap_or_default())}))} + {RageConfigurationLintRules("Enabled rules", linter_configuration)} + ) + .fmt(fmt)?; + } + } + }, + + Err(err) => { + markup! ( + {KeyValuePair("Status", markup!("Failed to load"))} + {KeyValuePair("Error", markup!({format!("{err}")}))} + ) + .fmt(fmt)? + }, + } + + Ok(()) + } } struct RageConfigurationLintRules<'a>(&'a str, Rules); impl Display for RageConfigurationLintRules<'_> { - fn fmt(&self, fmt: &mut Formatter<'_>) -> io::Result<()> { - let rules_str = self.0; + fn fmt(&self, fmt:&mut Formatter<'_>) -> io::Result<()> { + let rules_str = self.0; - let padding = Padding::new(2); + let padding = Padding::new(2); - fmt.write_markup(markup! {{padding}{rules_str}":"})?; + fmt.write_markup(markup! {{padding}{rules_str}":"})?; - fmt.write_markup(markup! {{SOFT_LINE}})?; + fmt.write_markup(markup! {{SOFT_LINE}})?; - let rules = self.1.as_enabled_rules(); + let rules = self.1.as_enabled_rules(); - let rules = rules.iter().collect::>(); + let rules = rules.iter().collect::>(); - for rule in rules { - fmt.write_markup(markup! {{padding}{rule}})?; + for rule in rules { + fmt.write_markup(markup! {{padding}{rule}})?; - fmt.write_markup(markup! {{SOFT_LINE}})?; - } + fmt.write_markup(markup! {{SOFT_LINE}})?; + } - Ok(()) - } + Ok(()) + } } struct EnvVarOs(&'static str); impl fmt::Display for EnvVarOs { - fn fmt(&self, fmt: &mut Formatter) -> io::Result<()> { - let name = self.0; - - match env::var_os(name) { - None => KeyValuePair(name, markup! { "unset" }).fmt(fmt), - Some(value) => KeyValuePair(name, markup! {{DebugDisplay(value)}}).fmt(fmt), - } - } + fn fmt(&self, fmt:&mut Formatter) -> io::Result<()> { + let name = self.0; + + match env::var_os(name) { + None => KeyValuePair(name, markup! { "unset" }).fmt(fmt), + Some(value) => KeyValuePair(name, markup! {{DebugDisplay(value)}}).fmt(fmt), + } + } } struct Section<'a>(&'a str); impl Display for Section<'_> { - fn fmt(&self, fmt: &mut Formatter) -> io::Result<()> { - writeln!(fmt, "\n{}:", self.0) - } + fn fmt(&self, fmt:&mut Formatter) -> io::Result<()> { writeln!(fmt, "\n{}:", self.0) } } struct BiomeServerLog; impl Display for BiomeServerLog { - fn fmt(&self, fmt: &mut Formatter) -> io::Result<()> { - if let Ok(Some(log)) = read_most_recent_log_file( - biome_env().biome_log_path.value().map(PathBuf::from), - biome_env() - .biome_log_prefix - .value() - .unwrap_or("server.log".to_string()), - ) { - markup!("\n""Biome Server Log:"" + fn fmt(&self, fmt:&mut Formatter) -> io::Result<()> { + if let Ok(Some(log)) = read_most_recent_log_file( + biome_env().biome_log_path.value().map(PathBuf::from), + biome_env().biome_log_prefix.value().unwrap_or("server.log".to_string()), + ) { + markup!("\n""Biome Server Log:"" ""\u{26a0} Please review the content of the log file before sharing it publicly as it may contain sensitive information: * Path names that may reveal your name, a project name, or the name of your employer. @@ -410,22 +412,19 @@ impl Display for BiomeServerLog { ") .fmt(fmt)?; - write!(fmt, "\n{log}")?; - } + write!(fmt, "\n{log}")?; + } - Ok(()) - } + Ok(()) + } } -/// Prints the server logs but only if the client is connected to a biome server. +/// Prints the server logs but only if the client is connected to a biome +/// server. struct ConnectedClientServerLog<'a>(&'a dyn Workspace); impl Display for ConnectedClientServerLog<'_> { - fn fmt(&self, fmt: &mut Formatter) -> io::Result<()> { - if self.0.server_info().is_some() { - BiomeServerLog.fmt(fmt) - } else { - Ok(()) - } - } + fn fmt(&self, fmt:&mut Formatter) -> io::Result<()> { + if self.0.server_info().is_some() { BiomeServerLog.fmt(fmt) } else { Ok(()) } + } } diff --git a/crates/biome_cli/Source/commands/search.rs b/crates/biome_cli/Source/commands/search.rs index 1a4c5e9e4813..1e334023dcb0 100644 --- a/crates/biome_cli/Source/commands/search.rs +++ b/crates/biome_cli/Source/commands/search.rs @@ -1,79 +1,67 @@ -use crate::cli_options::CliOptions; -use crate::commands::CommandRunner; -use crate::{CliDiagnostic, Execution, TraversalMode}; -use biome_configuration::{ - vcs::PartialVcsConfiguration, PartialConfiguration, PartialFilesConfiguration, -}; +use std::ffi::OsString; + +use biome_configuration::{PartialConfiguration, PartialFilesConfiguration, vcs::PartialVcsConfiguration}; use biome_console::Console; use biome_deserialize::Merge; use biome_fs::FileSystem; -use biome_service::configuration::LoadedConfiguration; -use biome_service::workspace::ParsePatternParams; -use biome_service::{DynRef, Workspace, WorkspaceError}; -use std::ffi::OsString; +use biome_service::{ + DynRef, + Workspace, + WorkspaceError, + configuration::LoadedConfiguration, + workspace::ParsePatternParams, +}; + +use crate::{CliDiagnostic, Execution, TraversalMode, cli_options::CliOptions, commands::CommandRunner}; pub(crate) struct SearchCommandPayload { - pub(crate) files_configuration: Option, - pub(crate) paths: Vec, - pub(crate) pattern: String, - pub(crate) stdin_file_path: Option, - pub(crate) vcs_configuration: Option, + pub(crate) files_configuration:Option, + pub(crate) paths:Vec, + pub(crate) pattern:String, + pub(crate) stdin_file_path:Option, + pub(crate) vcs_configuration:Option, } impl CommandRunner for SearchCommandPayload { - const COMMAND_NAME: &'static str = "search"; + const COMMAND_NAME:&'static str = "search"; - fn merge_configuration( - &mut self, - loaded_configuration: LoadedConfiguration, - _fs: &DynRef<'_, dyn FileSystem>, - _console: &mut dyn Console, - ) -> Result { - let LoadedConfiguration { - mut configuration, .. - } = loaded_configuration; + fn merge_configuration( + &mut self, + loaded_configuration:LoadedConfiguration, + _fs:&DynRef<'_, dyn FileSystem>, + _console:&mut dyn Console, + ) -> Result { + let LoadedConfiguration { mut configuration, .. } = loaded_configuration; - configuration - .files - .merge_with(self.files_configuration.clone()); + configuration.files.merge_with(self.files_configuration.clone()); - configuration.vcs.merge_with(self.vcs_configuration.clone()); + configuration.vcs.merge_with(self.vcs_configuration.clone()); - Ok(configuration) - } + Ok(configuration) + } - fn get_files_to_process( - &self, - _fs: &DynRef<'_, dyn FileSystem>, - _configuration: &PartialConfiguration, - ) -> Result, CliDiagnostic> { - Ok(self.paths.clone()) - } + fn get_files_to_process( + &self, + _fs:&DynRef<'_, dyn FileSystem>, + _configuration:&PartialConfiguration, + ) -> Result, CliDiagnostic> { + Ok(self.paths.clone()) + } - fn get_stdin_file_path(&self) -> Option<&str> { - self.stdin_file_path.as_deref() - } + fn get_stdin_file_path(&self) -> Option<&str> { self.stdin_file_path.as_deref() } - fn should_write(&self) -> bool { - false - } + fn should_write(&self) -> bool { false } - fn get_execution( - &self, - cli_options: &CliOptions, - _console: &mut dyn Console, - workspace: &dyn Workspace, - ) -> Result { - let pattern = workspace - .parse_pattern(ParsePatternParams { - pattern: self.pattern.clone(), - })? - .pattern_id; + fn get_execution( + &self, + cli_options:&CliOptions, + _console:&mut dyn Console, + workspace:&dyn Workspace, + ) -> Result { + let pattern = workspace + .parse_pattern(ParsePatternParams { pattern:self.pattern.clone() })? + .pattern_id; - Ok(Execution::new(TraversalMode::Search { - pattern, - stdin: self.get_stdin(_console)?, - }) - .set_report(cli_options)) - } + Ok(Execution::new(TraversalMode::Search { pattern, stdin:self.get_stdin(_console)? }).set_report(cli_options)) + } } diff --git a/crates/biome_cli/Source/commands/version.rs b/crates/biome_cli/Source/commands/version.rs index 99c80050e384..3b6aaa397693 100644 --- a/crates/biome_cli/Source/commands/version.rs +++ b/crates/biome_cli/Source/commands/version.rs @@ -1,43 +1,42 @@ -use biome_console::fmt::Formatter; -use biome_console::{fmt, markup, ConsoleExt}; +use biome_console::{ConsoleExt, fmt, fmt::Formatter, markup}; use biome_service::workspace::ServerInfo; use crate::{CliDiagnostic, CliSession, VERSION}; /// Handle of the `version` command. Prints a more in detail version of biome. -pub(crate) fn full_version(session: CliSession) -> Result<(), CliDiagnostic> { - session.app.console.log(markup! { - "CLI: "{VERSION} - }); +pub(crate) fn full_version(session:CliSession) -> Result<(), CliDiagnostic> { + session.app.console.log(markup! { + "CLI: "{VERSION} + }); - match session.app.workspace.server_info() { - None => { - session.app.console.log(markup! { - "Server: ""not connected" - }); - } + match session.app.workspace.server_info() { + None => { + session.app.console.log(markup! { + "Server: ""not connected" + }); + }, - Some(info) => { - session.app.console.log(markup! { + Some(info) => { + session.app.console.log(markup! { "Server: Name: "{info.name}" Version: "{DisplayServerVersion(info)} - }); - } - }; + }); + }, + }; - Ok(()) + Ok(()) } pub(super) struct DisplayServerVersion<'a>(pub &'a ServerInfo); impl fmt::Display for DisplayServerVersion<'_> { - fn fmt(&self, fmt: &mut Formatter) -> std::io::Result<()> { - match &self.0.version { - None => markup!("-").fmt(fmt), - Some(version) => { - write!(fmt, "{version}") - } - } - } + fn fmt(&self, fmt:&mut Formatter) -> std::io::Result<()> { + match &self.0.version { + None => markup!("-").fmt(fmt), + Some(version) => { + write!(fmt, "{version}") + }, + } + } } diff --git a/crates/biome_cli/Source/diagnostics.rs b/crates/biome_cli/Source/diagnostics.rs index 6ce6973721c2..34fe0a966280 100644 --- a/crates/biome_cli/Source/diagnostics.rs +++ b/crates/biome_cli/Source/diagnostics.rs @@ -292,9 +292,7 @@ struct CliAdvice { } impl CliAdvice { - fn new_with_help(sub_command:impl Into) -> Self { - Self { sub_command:sub_command.into() } - } + fn new_with_help(sub_command:impl Into) -> Self { Self { sub_command:sub_command.into() } } } impl Advices for CliAdvice { @@ -317,10 +315,7 @@ impl Advices for CliAdvice { impl CliDiagnostic { /// Returned when a subcommand is called with an unsupported combination of /// arguments - pub fn incompatible_arguments( - first_argument:impl Into, - second_argument:impl Into, - ) -> Self { + pub fn incompatible_arguments(first_argument:impl Into, second_argument:impl Into) -> Self { Self::IncompatibleArguments(IncompatibleArguments { first_argument:first_argument.into(), second_argument:second_argument.into(), @@ -345,10 +340,7 @@ impl CliDiagnostic { /// Returned when a required argument is not present in the command line pub fn missing_argument(argument:impl Into, subcommand:impl Into) -> Self { - Self::MissingArgument(MissingArgument { - argument:argument.into(), - advice:CliAdvice::new_with_help(subcommand), - }) + Self::MissingArgument(MissingArgument { argument:argument.into(), advice:CliAdvice::new_with_help(subcommand) }) } /// When no files were processed while traversing the file system @@ -373,53 +365,53 @@ impl CliDiagnostic { /// Emitted when errors were emitted while running `check` command pub fn check_error(category:&'static Category) -> Self { Self::CheckError(CheckError { - category, - message: MessageAndDescription::from( - markup! { - "Some ""errors"" were emitted while ""running checks""." - } - .to_owned(), - ), - }) + category, + message:MessageAndDescription::from( + markup! { + "Some ""errors"" were emitted while ""running checks""." + } + .to_owned(), + ), + }) } /// Emitted when warnings were emitted while running `check` command pub fn check_warnings(category:&'static Category) -> Self { Self::CheckError(CheckError { - category, - message: MessageAndDescription::from( - markup! { - "Some ""warnings"" were emitted while ""running checks""." - } - .to_owned(), - ), - }) + category, + message:MessageAndDescription::from( + markup! { + "Some ""warnings"" were emitted while ""running checks""." + } + .to_owned(), + ), + }) } /// Emitted when errors were emitted while apply code fixes pub fn apply_error(category:&'static Category) -> Self { Self::CheckError(CheckError { - category, - message: MessageAndDescription::from( - markup! { - "Some ""errors"" were emitted while ""applying fixes""." - } - .to_owned(), - ), - }) + category, + message:MessageAndDescription::from( + markup! { + "Some ""errors"" were emitted while ""applying fixes""." + } + .to_owned(), + ), + }) } /// Emitted when warnings were emitted while apply code fixes pub fn apply_warnings(category:&'static Category) -> Self { Self::CheckError(CheckError { - category, - message: MessageAndDescription::from( - markup! { - "Some ""warnings"" were emitted while ""running checks""." - } - .to_owned(), - ), - }) + category, + message:MessageAndDescription::from( + markup! { + "Some ""warnings"" were emitted while ""running checks""." + } + .to_owned(), + ), + }) } pub fn stdin() -> Self { Self::Stdin(StdinDiagnostic::default()) } diff --git a/crates/biome_cli/Source/execute/diagnostics.rs b/crates/biome_cli/Source/execute/diagnostics.rs index 68b66ccb50a6..31bcde4599d6 100644 --- a/crates/biome_cli/Source/execute/diagnostics.rs +++ b/crates/biome_cli/Source/execute/diagnostics.rs @@ -1,9 +1,16 @@ -use biome_diagnostics::adapters::{IoError, StdError}; +use std::io; + use biome_diagnostics::{ - Advices, Category, Diagnostic, DiagnosticExt, DiagnosticTags, Error, Visit, + Advices, + Category, + Diagnostic, + DiagnosticExt, + DiagnosticTags, + Error, + Visit, + adapters::{IoError, StdError}, }; use biome_text_edit::TextEdit; -use std::io; #[derive(Debug, Diagnostic)] #[diagnostic( @@ -12,33 +19,30 @@ use std::io; severity = Error )] pub(crate) struct CIFormatDiffDiagnostic { - #[location(resource)] - pub(crate) file_name: String, - #[advice] - pub(crate) diff: ContentDiffAdvice, + #[location(resource)] + pub(crate) file_name:String, + #[advice] + pub(crate) diff:ContentDiffAdvice, } #[derive(Debug, Diagnostic)] #[diagnostic( - category = "organizeImports", - message = "Import statements differs from the output" + category = "organizeImports", + message = "Import statements differs from the output" )] pub(crate) struct CIOrganizeImportsDiffDiagnostic { - #[location(resource)] - pub(crate) file_name: String, - #[advice] - pub(crate) diff: ContentDiffAdvice, + #[location(resource)] + pub(crate) file_name:String, + #[advice] + pub(crate) diff:ContentDiffAdvice, } #[derive(Debug, Diagnostic)] -#[diagnostic( - category = "assists", - message = "Applied assists differs from the output" -)] +#[diagnostic(category = "assists", message = "Applied assists differs from the output")] pub(crate) struct CIAssistsDiffDiagnostic { - #[location(resource)] - pub(crate) file_name: String, - #[advice] - pub(crate) diff: ContentDiffAdvice, + #[location(resource)] + pub(crate) file_name:String, + #[advice] + pub(crate) diff:ContentDiffAdvice, } #[derive(Debug, Diagnostic)] @@ -48,10 +52,10 @@ pub(crate) struct CIAssistsDiffDiagnostic { message = "Formatter would have printed the following content:" )] pub(crate) struct FormatDiffDiagnostic { - #[location(resource)] - pub(crate) file_name: String, - #[advice] - pub(crate) diff: ContentDiffAdvice, + #[location(resource)] + pub(crate) file_name:String, + #[advice] + pub(crate) diff:ContentDiffAdvice, } #[derive(Debug, Diagnostic)] @@ -61,10 +65,10 @@ pub(crate) struct FormatDiffDiagnostic { message = "Import statements could be sorted:" )] pub(crate) struct OrganizeImportsDiffDiagnostic { - #[location(resource)] - pub(crate) file_name: String, - #[advice] - pub(crate) diff: ContentDiffAdvice, + #[location(resource)] + pub(crate) file_name:String, + #[advice] + pub(crate) diff:ContentDiffAdvice, } #[derive(Debug, Diagnostic)] @@ -74,10 +78,10 @@ pub(crate) struct OrganizeImportsDiffDiagnostic { message = "Not all assists were applied:" )] pub(crate) struct AssistsDiffDiagnostic { - #[location(resource)] - pub(crate) file_name: String, - #[advice] - pub(crate) diff: ContentDiffAdvice, + #[location(resource)] + pub(crate) file_name:String, + #[advice] + pub(crate) diff:ContentDiffAdvice, } #[derive(Debug, Diagnostic)] @@ -87,32 +91,32 @@ pub(crate) struct AssistsDiffDiagnostic { message = "Configuration file can be updated." )] pub(crate) struct MigrateDiffDiagnostic { - #[location(resource)] - pub(crate) file_name: String, - #[advice] - pub(crate) diff: ContentDiffAdvice, + #[location(resource)] + pub(crate) file_name:String, + #[advice] + pub(crate) diff:ContentDiffAdvice, } #[derive(Debug)] pub(crate) struct ContentDiffAdvice { - pub(crate) old: String, - pub(crate) new: String, + pub(crate) old:String, + pub(crate) new:String, } impl Advices for ContentDiffAdvice { - fn record(&self, visitor: &mut dyn Visit) -> io::Result<()> { - let diff = TextEdit::from_unicode_words(&self.old, &self.new); + fn record(&self, visitor:&mut dyn Visit) -> io::Result<()> { + let diff = TextEdit::from_unicode_words(&self.old, &self.new); - visitor.record_diff(&diff) - } + visitor.record_diff(&diff) + } } #[derive(Debug, Diagnostic)] #[diagnostic(category = "internalError/panic", tags(INTERNAL))] pub(crate) struct PanicDiagnostic { - #[description] - #[message] - pub(crate) message: String, + #[description] + #[message] + pub(crate) message:String, } #[derive(Debug, Diagnostic)] @@ -134,62 +138,50 @@ pub(crate) struct SearchDiagnostic; /// Extension trait for turning [Display]-able error types into [TraversalError] pub(crate) trait ResultExt { - type Result; - - fn with_file_path_and_code( - self, - file_path: String, - code: &'static Category, - ) -> Result; - - fn with_file_path_and_code_and_tags( - self, - file_path: String, - code: &'static Category, - tags: DiagnosticTags, - ) -> Result; + type Result; + + fn with_file_path_and_code(self, file_path:String, code:&'static Category) -> Result; + + fn with_file_path_and_code_and_tags( + self, + file_path:String, + code:&'static Category, + tags:DiagnosticTags, + ) -> Result; } impl ResultExt for Result where - E: std::error::Error + Send + Sync + 'static, + E: std::error::Error + Send + Sync + 'static, { - type Result = T; - - fn with_file_path_and_code_and_tags( - self, - file_path: String, - code: &'static Category, - diagnostic_tags: DiagnosticTags, - ) -> Result { - self.map_err(move |err| { - StdError::from(err) - .with_category(code) - .with_file_path(file_path) - .with_tags(diagnostic_tags) - }) - } - - fn with_file_path_and_code( - self, - file_path: String, - code: &'static Category, - ) -> Result { - self.map_err(move |err| { - StdError::from(err) - .with_category(code) - .with_file_path(file_path) - }) - } + type Result = T; + + fn with_file_path_and_code_and_tags( + self, + file_path:String, + code:&'static Category, + diagnostic_tags:DiagnosticTags, + ) -> Result { + self.map_err(move |err| { + StdError::from(err) + .with_category(code) + .with_file_path(file_path) + .with_tags(diagnostic_tags) + }) + } + + fn with_file_path_and_code(self, file_path:String, code:&'static Category) -> Result { + self.map_err(move |err| StdError::from(err).with_category(code).with_file_path(file_path)) + } } /// Extension trait for turning [io::Error] into [Error] pub(crate) trait ResultIoExt: ResultExt { - fn with_file_path(self, file_path: String) -> Result; + fn with_file_path(self, file_path:String) -> Result; } impl ResultIoExt for io::Result { - fn with_file_path(self, file_path: String) -> Result { - self.map_err(|error| IoError::from(error).with_file_path(file_path)) - } + fn with_file_path(self, file_path:String) -> Result { + self.map_err(|error| IoError::from(error).with_file_path(file_path)) + } } diff --git a/crates/biome_cli/Source/execute/migrate.rs b/crates/biome_cli/Source/execute/migrate.rs index f731dcf64018..a3ed26874217 100644 --- a/crates/biome_cli/Source/execute/migrate.rs +++ b/crates/biome_cli/Source/execute/migrate.rs @@ -1,23 +1,24 @@ -use crate::commands::MigrateSubCommand; -use crate::diagnostics::MigrationDiagnostic; -use crate::execute::diagnostics::{ContentDiffAdvice, MigrateDiffDiagnostic}; -use crate::{CliDiagnostic, CliSession}; +use std::{borrow::Cow, ffi::OsStr, path::PathBuf}; + use biome_configuration::PartialConfiguration; -use biome_console::{markup, ConsoleExt}; -use biome_deserialize::json::deserialize_from_json_ast; -use biome_deserialize::Merge; -use biome_diagnostics::Diagnostic; -use biome_diagnostics::{category, PrintDiagnostic}; +use biome_console::{ConsoleExt, markup}; +use biome_deserialize::{Merge, json::deserialize_from_json_ast}; +use biome_diagnostics::{Diagnostic, PrintDiagnostic, category}; use biome_formatter::ParseFormatNumberError; use biome_fs::{BiomePath, ConfigName, FileSystemExt, OpenOptions}; -use biome_json_parser::{parse_json_with_cache, JsonParserOptions}; +use biome_json_parser::{JsonParserOptions, parse_json_with_cache}; use biome_json_syntax::{JsonFileSource, JsonRoot}; -use biome_migrate::{migrate_configuration, ControlFlow}; +use biome_migrate::{ControlFlow, migrate_configuration}; use biome_rowan::{AstNode, NodeCache}; use biome_service::workspace::{ChangeFileParams, FixAction, FormatFileParams, OpenFileParams}; -use std::borrow::Cow; -use std::ffi::OsStr; -use std::path::PathBuf; + +use crate::{ + CliDiagnostic, + CliSession, + commands::MigrateSubCommand, + diagnostics::MigrationDiagnostic, + execute::diagnostics::{ContentDiffAdvice, MigrateDiffDiagnostic}, +}; mod eslint; mod eslint_any_rule_to_biome; @@ -31,370 +32,317 @@ mod node; mod prettier; pub(crate) struct MigratePayload<'a> { - pub(crate) session: CliSession<'a>, - pub(crate) write: bool, - pub(crate) configuration_file_path: PathBuf, - pub(crate) configuration_directory_path: PathBuf, - pub(crate) verbose: bool, - pub(crate) sub_command: Option, + pub(crate) session:CliSession<'a>, + pub(crate) write:bool, + pub(crate) configuration_file_path:PathBuf, + pub(crate) configuration_directory_path:PathBuf, + pub(crate) verbose:bool, + pub(crate) sub_command:Option, } -pub(crate) fn run(migrate_payload: MigratePayload) -> Result<(), CliDiagnostic> { - let MigratePayload { - session, - write, - configuration_file_path, - configuration_directory_path, - verbose, - sub_command, - } = migrate_payload; - - let mut cache = NodeCache::default(); - - let fs = &session.app.fs; - - let console = session.app.console; - - let workspace = session.app.workspace; +pub(crate) fn run(migrate_payload:MigratePayload) -> Result<(), CliDiagnostic> { + let MigratePayload { + session, + write, + configuration_file_path, + configuration_directory_path, + verbose, + sub_command, + } = migrate_payload; - let open_options = if write { - OpenOptions::default().read(true).write(true) - } else { - OpenOptions::default().read(true) - }; + let mut cache = NodeCache::default(); - let mut biome_config_file = - fs.open_with_options(configuration_file_path.as_path(), open_options)?; + let fs = &session.app.fs; - let mut biome_config_content = String::new(); + let console = session.app.console; - biome_config_file.read_to_string(&mut biome_config_content)?; + let workspace = session.app.workspace; - let biome_path = BiomePath::new(configuration_file_path.as_path()); + let open_options = if write { + OpenOptions::default().read(true).write(true) + } else { + OpenOptions::default().read(true) + }; - workspace.open_file(OpenFileParams { - path: biome_path.clone(), - content: biome_config_content.to_string(), - version: 0, - document_file_source: Some(JsonFileSource::json().into()), - })?; + let mut biome_config_file = fs.open_with_options(configuration_file_path.as_path(), open_options)?; - let parsed = parse_json_with_cache( - &biome_config_content, - &mut cache, - JsonParserOptions::default(), - ); + let mut biome_config_content = String::new(); - match sub_command { - Some(MigrateSubCommand::Prettier) => { - let prettier::Config { - path: prettier_path, - data: prettier_config, - } = prettier::read_config_file(fs, console)?; + biome_config_file.read_to_string(&mut biome_config_content)?; - let biome_config = - deserialize_from_json_ast::(&parsed.tree(), "") - .into_deserialized(); + let biome_path = BiomePath::new(configuration_file_path.as_path()); - let Some(mut biome_config) = biome_config else { - return Ok(()); - }; + workspace.open_file(OpenFileParams { + path:biome_path.clone(), + content:biome_config_content.to_string(), + version:0, + document_file_source:Some(JsonFileSource::json().into()), + })?; - let old_biome_config = biome_config.clone(); + let parsed = parse_json_with_cache(&biome_config_content, &mut cache, JsonParserOptions::default()); - let prettier_biome_config = - prettier_config - .try_into() - .map_err(|err: ParseFormatNumberError| { - CliDiagnostic::MigrateError(MigrationDiagnostic { - reason: err.to_string(), - }) - })?; - - biome_config.merge_with(prettier_biome_config); - - if let Ok(ignore_patterns) = ignorefile::read_ignore_file(fs, prettier::IGNORE_FILE) { - if !ignore_patterns.patterns.is_empty() { - biome_config - .formatter - .get_or_insert(Default::default()) - .ignore - .get_or_insert(Default::default()) - .extend(ignore_patterns.patterns); - } - - if ignore_patterns.has_negated_patterns { - console.log(markup! { - {prettier::IGNORE_FILE}" contains negated glob patterns that start with ""!"".\nThese patterns cannot be migrated because Biome doesn't support them." - }) - } else if write && biome_config != old_biome_config { - console.log(markup!{ - {prettier::IGNORE_FILE}" has been successfully migrated." - }); - } - } - - if biome_config == old_biome_config { - console.log(markup! { - "No changes to apply to the Biome configuration file." - }); - } else { - let new_content = serde_json::to_string(&biome_config).map_err(|err| { - CliDiagnostic::MigrateError(MigrationDiagnostic { - reason: err.to_string(), - }) - })?; + match sub_command { + Some(MigrateSubCommand::Prettier) => { + let prettier::Config { path: prettier_path, data: prettier_config } = + prettier::read_config_file(fs, console)?; - workspace.change_file(ChangeFileParams { - path: biome_path.clone(), - content: new_content, - version: 1, - })?; + let biome_config = + deserialize_from_json_ast::(&parsed.tree(), "").into_deserialized(); - let printed = workspace.format_file(FormatFileParams { path: biome_path })?; + let Some(mut biome_config) = biome_config else { + return Ok(()); + }; - if write { - biome_config_file.set_content(printed.as_code().as_bytes())?; + let old_biome_config = biome_config.clone(); - console.log(markup!{ - {prettier_path}" has been successfully migrated." - }); - } else { - let file_name = configuration_file_path.display().to_string(); + let prettier_biome_config = prettier_config.try_into().map_err(|err:ParseFormatNumberError| { + CliDiagnostic::MigrateError(MigrationDiagnostic { reason:err.to_string() }) + })?; - let diagnostic = MigrateDiffDiagnostic { - file_name, - diff: ContentDiffAdvice { - old: biome_config_content, - new: printed.as_code().to_string(), - }, - }; + biome_config.merge_with(prettier_biome_config); - console.error(markup! {{PrintDiagnostic::simple(&diagnostic)}}); + if let Ok(ignore_patterns) = ignorefile::read_ignore_file(fs, prettier::IGNORE_FILE) { + if !ignore_patterns.patterns.is_empty() { + biome_config + .formatter + .get_or_insert(Default::default()) + .ignore + .get_or_insert(Default::default()) + .extend(ignore_patterns.patterns); + } - console.log(markup! { - "Run the command with the option ""--write"" to apply the changes." + if ignore_patterns.has_negated_patterns { + console.log(markup! { + {prettier::IGNORE_FILE}" contains negated glob patterns that start with ""!"".\nThese patterns cannot be migrated because Biome doesn't support them." }) - } - } - } - - Some(MigrateSubCommand::Eslint { - include_inspired, - include_nursery, - }) => { - let eslint::Config { - path: eslint_path, - data: eslint_config, - } = eslint::read_eslint_config(fs, console)?; - - let biome_config = - deserialize_from_json_ast::(&parsed.tree(), "") - .into_deserialized(); - - let Some(mut biome_config) = biome_config else { - return Ok(()); - }; - - let (biome_eslint_config, results) = - eslint_config.into_biome_config(&eslint_to_biome::MigrationOptions { - include_inspired, - include_nursery, - }); - - let old_biome_config = biome_config.clone(); - - biome_config.merge_with(biome_eslint_config); - - if let Ok(ignore_patterns) = ignorefile::read_ignore_file(fs, eslint::IGNORE_FILE) { - if !ignore_patterns.patterns.is_empty() { - biome_config - .linter - .get_or_insert(Default::default()) - .ignore - .get_or_insert(Default::default()) - .extend(ignore_patterns.patterns); - } - - if ignore_patterns.has_negated_patterns { - console.log(markup! { + } else if write && biome_config != old_biome_config { + console.log(markup! { + {prettier::IGNORE_FILE}" has been successfully migrated." + }); + } + } + + if biome_config == old_biome_config { + console.log(markup! { + "No changes to apply to the Biome configuration file." + }); + } else { + let new_content = serde_json::to_string(&biome_config) + .map_err(|err| CliDiagnostic::MigrateError(MigrationDiagnostic { reason:err.to_string() }))?; + + workspace.change_file(ChangeFileParams { path:biome_path.clone(), content:new_content, version:1 })?; + + let printed = workspace.format_file(FormatFileParams { path:biome_path })?; + + if write { + biome_config_file.set_content(printed.as_code().as_bytes())?; + + console.log(markup! { + {prettier_path}" has been successfully migrated." + }); + } else { + let file_name = configuration_file_path.display().to_string(); + + let diagnostic = MigrateDiffDiagnostic { + file_name, + diff:ContentDiffAdvice { old:biome_config_content, new:printed.as_code().to_string() }, + }; + + console.error(markup! {{PrintDiagnostic::simple(&diagnostic)}}); + + console.log(markup! { + "Run the command with the option ""--write"" to apply the changes." + }) + } + } + }, + + Some(MigrateSubCommand::Eslint { include_inspired, include_nursery }) => { + let eslint::Config { path: eslint_path, data: eslint_config } = eslint::read_eslint_config(fs, console)?; + + let biome_config = + deserialize_from_json_ast::(&parsed.tree(), "").into_deserialized(); + + let Some(mut biome_config) = biome_config else { + return Ok(()); + }; + + let (biome_eslint_config, results) = eslint_config + .into_biome_config(&eslint_to_biome::MigrationOptions { include_inspired, include_nursery }); + + let old_biome_config = biome_config.clone(); + + biome_config.merge_with(biome_eslint_config); + + if let Ok(ignore_patterns) = ignorefile::read_ignore_file(fs, eslint::IGNORE_FILE) { + if !ignore_patterns.patterns.is_empty() { + biome_config + .linter + .get_or_insert(Default::default()) + .ignore + .get_or_insert(Default::default()) + .extend(ignore_patterns.patterns); + } + + if ignore_patterns.has_negated_patterns { + console.log(markup! { {eslint::IGNORE_FILE}" contains negated glob patterns that start with ""!"".\nThese patterns cannot be migrated because Biome doesn't support them." }) - } else if write && biome_config != old_biome_config { - console.log(markup!{ - {eslint::IGNORE_FILE}" has been successfully migrated." - }); - } - } - - if biome_config == old_biome_config { - console.log(markup! { - "No changes to apply to the Biome configuration file." - }); - } else { - let new_content = serde_json::to_string(&biome_config).map_err(|err| { - CliDiagnostic::MigrateError(MigrationDiagnostic { - reason: err.to_string(), - }) - })?; - - workspace.change_file(ChangeFileParams { - path: biome_path.clone(), - content: new_content, - version: 1, - })?; - - let printed = workspace.format_file(FormatFileParams { path: biome_path })?; - - if write { - biome_config_file.set_content(printed.as_code().as_bytes())?; - - console.log(markup!{ - {eslint_path}" has been successfully migrated." - }); - } else { - let file_name = configuration_file_path.display().to_string(); - - let diagnostic = MigrateDiffDiagnostic { - file_name, - diff: ContentDiffAdvice { - old: biome_config_content, - new: printed.as_code().to_string(), - }, - }; - - console.error(markup! {{PrintDiagnostic::simple(&diagnostic)}}); - - console.log(markup! { - "Run the command with the option ""--write"" to apply the changes." - }) - } - } - - if results.has_inspired_rules { - console.log(markup! { + } else if write && biome_config != old_biome_config { + console.log(markup! { + {eslint::IGNORE_FILE}" has been successfully migrated." + }); + } + } + + if biome_config == old_biome_config { + console.log(markup! { + "No changes to apply to the Biome configuration file." + }); + } else { + let new_content = serde_json::to_string(&biome_config) + .map_err(|err| CliDiagnostic::MigrateError(MigrationDiagnostic { reason:err.to_string() }))?; + + workspace.change_file(ChangeFileParams { path:biome_path.clone(), content:new_content, version:1 })?; + + let printed = workspace.format_file(FormatFileParams { path:biome_path })?; + + if write { + biome_config_file.set_content(printed.as_code().as_bytes())?; + + console.log(markup! { + {eslint_path}" has been successfully migrated." + }); + } else { + let file_name = configuration_file_path.display().to_string(); + + let diagnostic = MigrateDiffDiagnostic { + file_name, + diff:ContentDiffAdvice { old:biome_config_content, new:printed.as_code().to_string() }, + }; + + console.error(markup! {{PrintDiagnostic::simple(&diagnostic)}}); + + console.log(markup! { + "Run the command with the option ""--write"" to apply the changes." + }) + } + } + + if results.has_inspired_rules { + console.log(markup! { "Run the command with the option ""--include-inspired"" to also migrate inspired rules." }) - } - } - - None => { - let has_deprecated_configuration = - configuration_file_path.file_name() == Some(OsStr::new("rome.json")); - - let mut errors = 0; - - let mut tree = parsed.tree(); - - let mut actions = Vec::new(); - - loop { - let (action, _) = migrate_configuration( - &tree, - configuration_file_path.as_path(), - biome_configuration::VERSION.to_string(), - |signal| { - let current_diagnostic = signal.diagnostic(); - - if current_diagnostic.is_some() { - errors += 1; - } - - if let Some(action) = signal.actions().next() { - return ControlFlow::Break(action); - } - - ControlFlow::Continue(()) - }, - ); - - match action { - Some(action) => { - if let (root, Some((range, _))) = - action.mutation.commit_with_text_range_and_edit(true) - { - tree = match JsonRoot::cast(root) { - Some(tree) => tree, - None => { - return Err(CliDiagnostic::check_error(category!("migrate"))) - } - }; - - actions.push(FixAction { - rule_name: action.rule_name.map(|(group, rule)| { - (Cow::Borrowed(group), Cow::Borrowed(rule)) - }), - range, - }); - } - } - - None => { - break; - } - } - } - - let new_configuration_content = tree.to_string(); - - if biome_config_content != new_configuration_content || has_deprecated_configuration { - if write { - let mut configuration_file = if has_deprecated_configuration { - let biome_file_path = - configuration_directory_path.join(ConfigName::biome_json()); - - fs.create_new(biome_file_path.as_path())? - } else { - biome_config_file - }; - - configuration_file.set_content(tree.to_string().as_bytes())?; - - console.log(markup!{ + } + }, + + None => { + let has_deprecated_configuration = configuration_file_path.file_name() == Some(OsStr::new("rome.json")); + + let mut errors = 0; + + let mut tree = parsed.tree(); + + let mut actions = Vec::new(); + + loop { + let (action, _) = migrate_configuration( + &tree, + configuration_file_path.as_path(), + biome_configuration::VERSION.to_string(), + |signal| { + let current_diagnostic = signal.diagnostic(); + + if current_diagnostic.is_some() { + errors += 1; + } + + if let Some(action) = signal.actions().next() { + return ControlFlow::Break(action); + } + + ControlFlow::Continue(()) + }, + ); + + match action { + Some(action) => { + if let (root, Some((range, _))) = action.mutation.commit_with_text_range_and_edit(true) { + tree = match JsonRoot::cast(root) { + Some(tree) => tree, + None => { + return Err(CliDiagnostic::check_error(category!("migrate"))); + }, + }; + + actions.push(FixAction { + rule_name:action + .rule_name + .map(|(group, rule)| (Cow::Borrowed(group), Cow::Borrowed(rule))), + range, + }); + } + }, + + None => { + break; + }, + } + } + + let new_configuration_content = tree.to_string(); + + if biome_config_content != new_configuration_content || has_deprecated_configuration { + if write { + let mut configuration_file = if has_deprecated_configuration { + let biome_file_path = configuration_directory_path.join(ConfigName::biome_json()); + + fs.create_new(biome_file_path.as_path())? + } else { + biome_config_file + }; + + configuration_file.set_content(tree.to_string().as_bytes())?; + + console.log(markup!{ "The configuration "{{configuration_file_path.display().to_string()}}" has been successfully migrated." }) - } else { - let file_name = configuration_file_path.display().to_string(); - - let diagnostic = if has_deprecated_configuration { - MigrateDiffDiagnostic { - file_name, - diff: ContentDiffAdvice { - old: "rome.json".to_string(), - new: "biome.json".to_string(), - }, - } - } else { - MigrateDiffDiagnostic { - file_name, - diff: ContentDiffAdvice { - old: biome_config_content, - new: new_configuration_content, - }, - } - }; - - if diagnostic.tags().is_verbose() { - if verbose { - console.error(markup! {{PrintDiagnostic::verbose(&diagnostic)}}) - } - } else { - console.error(markup! {{PrintDiagnostic::simple(&diagnostic)}}) - } - - console.log(markup! { - "Run the command with the option ""--write"" to apply the changes." - }) - } - } else { - console.log(markup! { - - "Your configuration file is up to date." - - }) - } - } - } - - Ok(()) + } else { + let file_name = configuration_file_path.display().to_string(); + + let diagnostic = if has_deprecated_configuration { + MigrateDiffDiagnostic { + file_name, + diff:ContentDiffAdvice { old:"rome.json".to_string(), new:"biome.json".to_string() }, + } + } else { + MigrateDiffDiagnostic { + file_name, + diff:ContentDiffAdvice { old:biome_config_content, new:new_configuration_content }, + } + }; + + if diagnostic.tags().is_verbose() { + if verbose { + console.error(markup! {{PrintDiagnostic::verbose(&diagnostic)}}) + } + } else { + console.error(markup! {{PrintDiagnostic::simple(&diagnostic)}}) + } + + console.log(markup! { + "Run the command with the option ""--write"" to apply the changes." + }) + } + } else { + console.log(markup! { + + "Your configuration file is up to date." + + }) + } + }, + } + + Ok(()) } diff --git a/crates/biome_cli/Source/execute/migrate/eslint.rs b/crates/biome_cli/Source/execute/migrate/eslint.rs index 49a9630ddee5..9afe24bf2d3f 100644 --- a/crates/biome_cli/Source/execute/migrate/eslint.rs +++ b/crates/biome_cli/Source/execute/migrate/eslint.rs @@ -1,38 +1,39 @@ -use biome_console::{markup, Console, ConsoleExt}; -use biome_deserialize::json::deserialize_from_json_str; -use biome_deserialize::Merge; +use std::{ + borrow::Cow, + ffi::OsStr, + path::{Path, PathBuf}, +}; + +use biome_console::{Console, ConsoleExt, markup}; +use biome_deserialize::{Merge, json::deserialize_from_json_str}; use biome_diagnostics::{DiagnosticExt, PrintDiagnostic}; use biome_fs::{FileSystem, OpenOptions}; use biome_json_parser::JsonParserOptions; use biome_service::DynRef; -use std::borrow::Cow; -use std::ffi::OsStr; -use std::path::{Path, PathBuf}; -use crate::diagnostics::MigrationDiagnostic; -use crate::CliDiagnostic; +use super::{eslint_eslint, node}; +use crate::{CliDiagnostic, diagnostics::MigrationDiagnostic}; -use super::eslint_eslint; -use super::node; - -/// This modules includes implementations for loading and deserializing an eslint configuration. +/// This modules includes implementations for loading and deserializing an +/// eslint configuration. /// -/// See [super::eslint_eslint] for the data representation of an ESLint configuration. +/// See [super::eslint_eslint] for the data representation of an ESLint +/// configuration. /// /// Each ESLint plugin has its own module in which rule options are defined. -/// For example, the ESLint TypeScript plugin is defined in [super::eslint_typescript]. -/// Note that we don't need to deserialise every existing rule option. -/// We only need to deserialise options that have equivalent biome options. -/// This greatly reduces the amount of work involved. +/// For example, the ESLint TypeScript plugin is defined in +/// [super::eslint_typescript]. Note that we don't need to deserialise every +/// existing rule option. We only need to deserialise options that have +/// equivalent biome options. This greatly reduces the amount of work involved. /// ESLint flat configuration filenames. /// /// See https://eslint.org/docs/latest/use/configure/configuration-files-new -const FLAT_CONFIG_FILES: [&str; 3] = [ - // Prefixed with `./` to ensure that it is loadable via Node.js's `import()` - "./eslint.config.js", - "./eslint.config.mjs", - "./eslint.config.cjs", +const FLAT_CONFIG_FILES:[&str; 3] = [ + // Prefixed with `./` to ensure that it is loadable via Node.js's `import()` + "./eslint.config.js", + "./eslint.config.mjs", + "./eslint.config.cjs", ]; /// List of ESLint **legacy** configuration filenames. @@ -41,369 +42,336 @@ const FLAT_CONFIG_FILES: [&str; 3] = [ /// /// Order is important. /// It translates the priority of the files. -/// For example, ESLint looks for `./.eslintrc.js` before looking for `./.eslintrc.json`. -const LEGACY_CONFIG_FILES: [&str; 6] = [ - // Prefixed with `./` to ensure that it is loadable via Node.js's `import()` - "./.eslintrc.js", - // Prefixed with `./` to ensure that it is loadable via Node.js's `import()` - "./.eslintrc.cjs", - ".eslintrc.yaml", - ".eslintrc.yml", - ".eslintrc.json", - ".eslintrc", +/// For example, ESLint looks for `./.eslintrc.js` before looking for +/// `./.eslintrc.json`. +const LEGACY_CONFIG_FILES:[&str; 6] = [ + // Prefixed with `./` to ensure that it is loadable via Node.js's `import()` + "./.eslintrc.js", + // Prefixed with `./` to ensure that it is loadable via Node.js's `import()` + "./.eslintrc.cjs", + ".eslintrc.yaml", + ".eslintrc.yml", + ".eslintrc.json", + ".eslintrc", ]; /// An ESLint config can be embedded in `package.json` -const PACKAGE_JSON: &str = "package.json"; +const PACKAGE_JSON:&str = "package.json"; /// ESLint Ignore file. Use the same syntax as gitignore. -pub(crate) const IGNORE_FILE: &str = ".eslintignore"; +pub(crate) const IGNORE_FILE:&str = ".eslintignore"; -/// Returns the ESLint configuration file in the working directory with the highest priority. +/// Returns the ESLint configuration file in the working directory with the +/// highest priority. /// /// This function respects the priority between ESLint configuration files. -/// For example, it looks for `./.eslintrc.js` before looking for `./.eslintrc.json`. -/// It first ries to load a flat configuration file. +/// For example, it looks for `./.eslintrc.js` before looking for +/// `./.eslintrc.json`. It first ries to load a flat configuration file. /// -/// Unlike ESLint, it doesn't look for a configuration file in parent directories -/// when no configuration file is found in the working directory. +/// Unlike ESLint, it doesn't look for a configuration file in parent +/// directories when no configuration file is found in the working directory. /// /// Deserialization errors are reported using `console`. -/// Other errors (File Not found, unsupported config format, ...) are directly returned. +/// Other errors (File Not found, unsupported config format, ...) are directly +/// returned. /// -/// We extract the ESLint configuration from a JavaScript file, by invoking `node`. +/// We extract the ESLint configuration from a JavaScript file, by invoking +/// `node`. /// /// The `extends` field is recursively resolved. pub(crate) fn read_eslint_config( - fs: &DynRef<'_, dyn FileSystem>, - console: &mut dyn Console, + fs:&DynRef<'_, dyn FileSystem>, + console:&mut dyn Console, ) -> Result { - for config_path_str in FLAT_CONFIG_FILES { - let path = Path::new(config_path_str); - - if fs.path_exists(path) { - return load_flat_config_data(path, console).map(|data| Config { - path: config_path_str, - data: data.into(), - }); - } - } - - for config_path_str in LEGACY_CONFIG_FILES { - let path = Path::new(config_path_str); - - if fs.path_exists(path) { - return load_legacy_config_data(fs, path, console).map(|data| Config { - path: config_path_str, - data: data.into(), - }); - } - } - // We don't report an error if ESLint config is not embedded in `PACKAGE_JSON`. - if let Ok(data) = load_legacy_config_data(fs, Path::new(PACKAGE_JSON), console) { - return Ok(Config { - path: PACKAGE_JSON, - data: data.into(), - }); - } - - Err(CliDiagnostic::MigrateError(MigrationDiagnostic { reason: "The default ESLint configuration file `.eslintrc[.*]` was not found in the working directory.".to_string()})) + for config_path_str in FLAT_CONFIG_FILES { + let path = Path::new(config_path_str); + + if fs.path_exists(path) { + return load_flat_config_data(path, console).map(|data| Config { path:config_path_str, data:data.into() }); + } + } + + for config_path_str in LEGACY_CONFIG_FILES { + let path = Path::new(config_path_str); + + if fs.path_exists(path) { + return load_legacy_config_data(fs, path, console) + .map(|data| Config { path:config_path_str, data:data.into() }); + } + } + // We don't report an error if ESLint config is not embedded in `PACKAGE_JSON`. + if let Ok(data) = load_legacy_config_data(fs, Path::new(PACKAGE_JSON), console) { + return Ok(Config { path:PACKAGE_JSON, data:data.into() }); + } + + Err(CliDiagnostic::MigrateError(MigrationDiagnostic { + reason:"The default ESLint configuration file `.eslintrc[.*]` was not found in the working directory." + .to_string(), + })) } #[derive(Debug)] pub(crate) struct Config { - /// Path of the ESlint config file - pub(crate) path: &'static str, - /// Resolved ESlint config - pub(crate) data: eslint_eslint::AnyConfigData, + /// Path of the ESlint config file + pub(crate) path:&'static str, + /// Resolved ESlint config + pub(crate) data:eslint_eslint::AnyConfigData, } /// Load an ESlint Flat config /// See https://eslint.org/docs/latest/use/configure/configuration-files-new -fn load_flat_config_data( - path: &Path, - console: &mut dyn Console, -) -> Result { - let node::Resolution { content, .. } = node::load_config(&path.to_string_lossy())?; - - let (deserialized, diagnostics) = deserialize_from_json_str::( - &content, - JsonParserOptions::default(), - "", - ) - .consume(); - - let path_str = path.to_string_lossy(); - - for diagnostic in diagnostics.into_iter().filter(|diag| { - matches!( - diag.severity(), - biome_diagnostics::Severity::Fatal - | biome_diagnostics::Severity::Error - | biome_diagnostics::Severity::Warning - ) - }) { - let diagnostic = diagnostic.with_file_path(path_str.to_string()); - - console.error(markup! {{PrintDiagnostic::simple(&diagnostic)}}); - } - - if let Some(result) = deserialized { - Ok(result) - } else { - Err(CliDiagnostic::MigrateError(MigrationDiagnostic { - reason: "Could not deserialize the Eslint configuration file".to_string(), - })) - } +fn load_flat_config_data(path:&Path, console:&mut dyn Console) -> Result { + let node::Resolution { content, .. } = node::load_config(&path.to_string_lossy())?; + + let (deserialized, diagnostics) = + deserialize_from_json_str::(&content, JsonParserOptions::default(), "") + .consume(); + + let path_str = path.to_string_lossy(); + + for diagnostic in diagnostics.into_iter().filter(|diag| { + matches!( + diag.severity(), + biome_diagnostics::Severity::Fatal + | biome_diagnostics::Severity::Error + | biome_diagnostics::Severity::Warning + ) + }) { + let diagnostic = diagnostic.with_file_path(path_str.to_string()); + + console.error(markup! {{PrintDiagnostic::simple(&diagnostic)}}); + } + + if let Some(result) = deserialized { + Ok(result) + } else { + Err(CliDiagnostic::MigrateError(MigrationDiagnostic { + reason:"Could not deserialize the Eslint configuration file".to_string(), + })) + } } /// Load an ESlint legacy config /// See https://eslint.org/docs/latest/use/configure/configuration-files fn load_legacy_config_data( - fs: &DynRef<'_, dyn FileSystem>, - path: &Path, - console: &mut dyn Console, + fs:&DynRef<'_, dyn FileSystem>, + path:&Path, + console:&mut dyn Console, ) -> Result { - let (deserialized, diagnostics) = match path.extension().and_then(OsStr::to_str) { - None | Some("json") => { - let mut file = fs.open_with_options(path, OpenOptions::default().read(true))?; - - let mut content = String::new(); - - file.read_to_string(&mut content)?; - - if path.file_name().is_some_and(|name| name == PACKAGE_JSON) { - let (deserialized, diagnostics) = - deserialize_from_json_str::( - &content, - JsonParserOptions::default() - .with_allow_trailing_commas() - .with_allow_comments(), - "", - ) - .consume(); - ( - deserialized.and_then(|mut packagejson| { - if let Some(eslint_config) = packagejson.eslint_config.as_mut() { - eslint_config - .ignore_patterns - .extend(packagejson.eslint_ignore); - } - - packagejson.eslint_config - }), - diagnostics, - ) - } else { - deserialize_from_json_str::( - &content, - JsonParserOptions::default() - .with_allow_trailing_commas() - .with_allow_comments(), - "", - ) - .consume() - } - } - - Some("js" | "cjs") => { - let node::Resolution { content, .. } = node::load_config(&path.to_string_lossy())?; - - deserialize_from_json_str::( - &content, - JsonParserOptions::default(), - "", - ) - .consume() - } - - Some(ext) => { - return Err(CliDiagnostic::MigrateError(MigrationDiagnostic { - reason: format!( - "ESLint configuration ending with the extension `{ext}` are not supported." - ), - })) - } - }; - - let path_str = path.to_string_lossy(); - - for diagnostic in diagnostics.into_iter().filter(|diag| { - matches!( - diag.severity(), - biome_diagnostics::Severity::Fatal - | biome_diagnostics::Severity::Error - | biome_diagnostics::Severity::Warning - ) - }) { - let diagnostic = diagnostic.with_file_path(path_str.to_string()); - - console.error(markup! {{PrintDiagnostic::simple(&diagnostic)}}); - } - - if let Some(mut result) = deserialized { - // recursively resolve the `extends` field. - while !result.extends.is_empty() { - resolve_extends(&mut result, console); - } - - Ok(result) - } else { - Err(CliDiagnostic::MigrateError(MigrationDiagnostic { - reason: "Could not deserialize the Eslint configuration file".to_string(), - })) - } + let (deserialized, diagnostics) = match path.extension().and_then(OsStr::to_str) { + None | Some("json") => { + let mut file = fs.open_with_options(path, OpenOptions::default().read(true))?; + + let mut content = String::new(); + + file.read_to_string(&mut content)?; + + if path.file_name().is_some_and(|name| name == PACKAGE_JSON) { + let (deserialized, diagnostics) = deserialize_from_json_str::( + &content, + JsonParserOptions::default().with_allow_trailing_commas().with_allow_comments(), + "", + ) + .consume(); + ( + deserialized.and_then(|mut packagejson| { + if let Some(eslint_config) = packagejson.eslint_config.as_mut() { + eslint_config.ignore_patterns.extend(packagejson.eslint_ignore); + } + + packagejson.eslint_config + }), + diagnostics, + ) + } else { + deserialize_from_json_str::( + &content, + JsonParserOptions::default().with_allow_trailing_commas().with_allow_comments(), + "", + ) + .consume() + } + }, + + Some("js" | "cjs") => { + let node::Resolution { content, .. } = node::load_config(&path.to_string_lossy())?; + + deserialize_from_json_str::(&content, JsonParserOptions::default(), "") + .consume() + }, + + Some(ext) => { + return Err(CliDiagnostic::MigrateError(MigrationDiagnostic { + reason:format!("ESLint configuration ending with the extension `{ext}` are not supported."), + })); + }, + }; + + let path_str = path.to_string_lossy(); + + for diagnostic in diagnostics.into_iter().filter(|diag| { + matches!( + diag.severity(), + biome_diagnostics::Severity::Fatal + | biome_diagnostics::Severity::Error + | biome_diagnostics::Severity::Warning + ) + }) { + let diagnostic = diagnostic.with_file_path(path_str.to_string()); + + console.error(markup! {{PrintDiagnostic::simple(&diagnostic)}}); + } + + if let Some(mut result) = deserialized { + // recursively resolve the `extends` field. + while !result.extends.is_empty() { + resolve_extends(&mut result, console); + } + + Ok(result) + } else { + Err(CliDiagnostic::MigrateError(MigrationDiagnostic { + reason:"Could not deserialize the Eslint configuration file".to_string(), + })) + } } -/// Returns the configuration from a preset or an error if the resolution failed. +/// Returns the configuration from a preset or an error if the resolution +/// failed. /// /// This handles: /// - native ESLint presets such as `eslint:recommended`; /// - plugin presets such as `plugin:@typescript-eslint/recommended`; /// - and shared configurations such as `standard`. -fn load_eslint_extends_config( - name: &str, -) -> Result { - let (specifier, resolved_path, deserialized) = if let Some((protocol, rest)) = - name.split_once(':') - { - let (module_name, config_name) = match protocol { - // e.g. `eslint:recommended` - // - module_name: `@eslint/js` - // - config_name: `recommended` - "eslint" => (Cow::Borrowed("@eslint/js"), rest), - // e.g. `plugin:@typescript-eslint/recommended` - // - module_name: `@typescript-eslint/eslint-plugin` - // - config_name: `recommended` - // e.g. `plugin:unicorn/recommended` - // - module_name: `eslint-plugin-unicorn` - // - config_name: `recommended` - "plugin" => { - let Some(config_name) = rest.split('/').last() else { - return Err(CliDiagnostic::MigrateError(MigrationDiagnostic { - reason: format!( - "The configuration {rest} cannot be resolved. Make sure that your ESLint configuration file is valid." - ), - })); - }; - - let rest = rest.trim_end_matches(config_name); - - let module_name = rest.trim_end_matches('/'); - - let module_name = EslintPackage::Plugin.resolve_name(module_name); - (module_name, config_name) - } - - name => { - return Err(CliDiagnostic::MigrateError(MigrationDiagnostic { - reason: format!( - "The module {name} cannot be resolved. This is likely an internal error." - ), - })); - } - }; - // load ESLint preset - let node::Resolution { - content, - resolved_path, - } = node::load_config(&module_name)?; - - let deserialized = deserialize_from_json_str::( - &content, - JsonParserOptions::default(), - "", - ) - .into_deserialized(); - - if let Some(mut deserialized) = deserialized { - let deserialized = deserialized.configs.remove(config_name); - - if deserialized.is_none() { - return Err(CliDiagnostic::MigrateError(MigrationDiagnostic { - reason: format!("The ESLint configuration '{config_name}' cannot be extracted from the module '{module_name}'. Make sure that '{config_name}' is a valid configuration name.") - })); - } - (module_name, resolved_path, deserialized) - } else { - (module_name, resolved_path, None) - } - } else { - // load ESLint shared config - let module_name = if matches!(name.as_bytes().first(), Some(b'.' | b'/' | b'#')) { - // local path - Cow::Borrowed(name) - } else { - EslintPackage::Config.resolve_name(name) - }; - // Try to load `module_name` or else try to load diretcly `name`. - let node::Resolution { - content, - resolved_path, - } = node::load_config(&module_name).or_else(|err| { - if module_name != name { - node::load_config(name) - } else { - Err(err) - } - })?; - - let deserialized = deserialize_from_json_str::( - &content, - JsonParserOptions::default(), - "", - ) - .into_deserialized(); - (module_name, resolved_path, deserialized) - }; - - let Some(mut deserialized) = deserialized else { - return Err(CliDiagnostic::MigrateError(MigrationDiagnostic { - reason: format!("The ESLint configuration of the module '{specifier}' cannot be extracted. This is likely an internal error.") - })); - }; - // Resolve relative path in `extends`. - deserialized.extends.iter_mut().for_each(|extends_item| { - if extends_item.starts_with('.') { - let Some(resolved_path) = Path::new(&resolved_path).parent() else { - return; - }; - - let mut path = PathBuf::new(); - - path.push(resolved_path); - - path.push(Path::new(&extends_item)); - *extends_item = path.to_string_lossy().to_string(); - } - }); - - Ok(deserialized) +fn load_eslint_extends_config(name:&str) -> Result { + let (specifier, resolved_path, deserialized) = if let Some((protocol, rest)) = name.split_once(':') { + let (module_name, config_name) = match protocol { + // e.g. `eslint:recommended` + // - module_name: `@eslint/js` + // - config_name: `recommended` + "eslint" => (Cow::Borrowed("@eslint/js"), rest), + // e.g. `plugin:@typescript-eslint/recommended` + // - module_name: `@typescript-eslint/eslint-plugin` + // - config_name: `recommended` + // e.g. `plugin:unicorn/recommended` + // - module_name: `eslint-plugin-unicorn` + // - config_name: `recommended` + "plugin" => { + let Some(config_name) = rest.split('/').last() else { + return Err(CliDiagnostic::MigrateError(MigrationDiagnostic { + reason:format!( + "The configuration {rest} cannot be resolved. Make sure that your ESLint configuration \ + file is valid." + ), + })); + }; + + let rest = rest.trim_end_matches(config_name); + + let module_name = rest.trim_end_matches('/'); + + let module_name = EslintPackage::Plugin.resolve_name(module_name); + (module_name, config_name) + }, + + name => { + return Err(CliDiagnostic::MigrateError(MigrationDiagnostic { + reason:format!("The module {name} cannot be resolved. This is likely an internal error."), + })); + }, + }; + // load ESLint preset + let node::Resolution { content, resolved_path } = node::load_config(&module_name)?; + + let deserialized = + deserialize_from_json_str::(&content, JsonParserOptions::default(), "") + .into_deserialized(); + + if let Some(mut deserialized) = deserialized { + let deserialized = deserialized.configs.remove(config_name); + + if deserialized.is_none() { + return Err(CliDiagnostic::MigrateError(MigrationDiagnostic { + reason:format!( + "The ESLint configuration '{config_name}' cannot be extracted from the module \ + '{module_name}'. Make sure that '{config_name}' is a valid configuration name." + ), + })); + } + (module_name, resolved_path, deserialized) + } else { + (module_name, resolved_path, None) + } + } else { + // load ESLint shared config + let module_name = if matches!(name.as_bytes().first(), Some(b'.' | b'/' | b'#')) { + // local path + Cow::Borrowed(name) + } else { + EslintPackage::Config.resolve_name(name) + }; + // Try to load `module_name` or else try to load diretcly `name`. + let node::Resolution { content, resolved_path } = node::load_config(&module_name) + .or_else(|err| if module_name != name { node::load_config(name) } else { Err(err) })?; + + let deserialized = + deserialize_from_json_str::(&content, JsonParserOptions::default(), "") + .into_deserialized(); + (module_name, resolved_path, deserialized) + }; + + let Some(mut deserialized) = deserialized else { + return Err(CliDiagnostic::MigrateError(MigrationDiagnostic { + reason:format!( + "The ESLint configuration of the module '{specifier}' cannot be extracted. This is likely an internal \ + error." + ), + })); + }; + // Resolve relative path in `extends`. + deserialized.extends.iter_mut().for_each(|extends_item| { + if extends_item.starts_with('.') { + let Some(resolved_path) = Path::new(&resolved_path).parent() else { + return; + }; + + let mut path = PathBuf::new(); + + path.push(resolved_path); + + path.push(Path::new(&extends_item)); + *extends_item = path.to_string_lossy().to_string(); + } + }); + + Ok(deserialized) } /// Load and merge included configuration via `self.extends`. /// /// Unknown presets are ignored. /// `self.extends` is replaced by an empty array. -fn resolve_extends(config: &mut eslint_eslint::LegacyConfigData, console: &mut dyn Console) { - let extensions: Vec<_> = config - .extends - .iter() - .filter_map(|preset| match load_eslint_extends_config(preset) { - Ok(config) => Some(config), - Err(diag) => { - console.error(markup! {{PrintDiagnostic::simple(&diag)}}); - - None - } - }) - .collect(); - - config.extends.clear(); - - for ext in extensions { - config.merge_with(ext); - } +fn resolve_extends(config:&mut eslint_eslint::LegacyConfigData, console:&mut dyn Console) { + let extensions:Vec<_> = config + .extends + .iter() + .filter_map(|preset| { + match load_eslint_extends_config(preset) { + Ok(config) => Some(config), + Err(diag) => { + console.error(markup! {{PrintDiagnostic::simple(&diag)}}); + + None + }, + } + }) + .collect(); + + config.extends.clear(); + + for ext in extensions { + config.merge_with(ext); + } } /// ESLint to specific rules to resolve a module name. @@ -411,83 +379,80 @@ fn resolve_extends(config: &mut eslint_eslint::LegacyConfigData, console: &mut d /// See also https://eslint.org/docs/latest/extend/plugins #[derive(Debug)] enum EslintPackage { - Config, - Plugin, + Config, + Plugin, } impl EslintPackage { - fn resolve_name<'a>(&self, name: &'a str) -> Cow<'a, str> { - let artifact = match self { - EslintPackage::Config => "eslint-config-", - EslintPackage::Plugin => "eslint-plugin-", - }; - - if name.starts_with('@') { - // handle scoped package - if let Some((scope, rest)) = name.split_once('/') { - let package = rest.split('/').next().unwrap_or(rest); - - if rest.starts_with(artifact) || package == artifact.trim_end_matches('-') { - Cow::Borrowed(name) - } else { - Cow::Owned(format!("{scope}/{artifact}{rest}")) - } - } else { - let artifact = artifact.trim_end_matches('-'); - - Cow::Owned(format!("{name}/{artifact}")) - } - } else if name.starts_with(artifact) { - Cow::Borrowed(name) - } else { - Cow::Owned(format!("{artifact}{name}")) - } - } + fn resolve_name<'a>(&self, name:&'a str) -> Cow<'a, str> { + let artifact = match self { + EslintPackage::Config => "eslint-config-", + EslintPackage::Plugin => "eslint-plugin-", + }; + + if name.starts_with('@') { + // handle scoped package + if let Some((scope, rest)) = name.split_once('/') { + let package = rest.split('/').next().unwrap_or(rest); + + if rest.starts_with(artifact) || package == artifact.trim_end_matches('-') { + Cow::Borrowed(name) + } else { + Cow::Owned(format!("{scope}/{artifact}{rest}")) + } + } else { + let artifact = artifact.trim_end_matches('-'); + + Cow::Owned(format!("{name}/{artifact}")) + } + } else if name.starts_with(artifact) { + Cow::Borrowed(name) + } else { + Cow::Owned(format!("{artifact}{name}")) + } + } } #[cfg(test)] mod tests { - use super::*; - - #[test] - fn eslint_package_resolve_name() { - assert_eq!( - EslintPackage::Config.resolve_name("@scope/package"), - "@scope/eslint-config-package" - ); - - assert_eq!( - EslintPackage::Config.resolve_name("@scope/eslint-config-package"), - "@scope/eslint-config-package" - ); - - assert_eq!( - EslintPackage::Config.resolve_name("@scope/eslint-config"), - "@scope/eslint-config" - ); - - assert_eq!( - EslintPackage::Config.resolve_name("@scope/package/path"), - "@scope/eslint-config-package/path" - ); - - assert_eq!( - EslintPackage::Config.resolve_name("@scope/eslint-config-package/path"), - "@scope/eslint-config-package/path" - ); - - assert_eq!( - EslintPackage::Config.resolve_name("@scope/eslint-config/path"), - "@scope/eslint-config/path" - ); - - assert_eq!( - EslintPackage::Config.resolve_name("package"), - "eslint-config-package" - ); - - assert_eq!( - EslintPackage::Config.resolve_name("eslint-config-package"), - "eslint-config-package" - ); - } + use super::*; + + #[test] + fn eslint_package_resolve_name() { + assert_eq!( + EslintPackage::Config.resolve_name("@scope/package"), + "@scope/eslint-config-package" + ); + + assert_eq!( + EslintPackage::Config.resolve_name("@scope/eslint-config-package"), + "@scope/eslint-config-package" + ); + + assert_eq!( + EslintPackage::Config.resolve_name("@scope/eslint-config"), + "@scope/eslint-config" + ); + + assert_eq!( + EslintPackage::Config.resolve_name("@scope/package/path"), + "@scope/eslint-config-package/path" + ); + + assert_eq!( + EslintPackage::Config.resolve_name("@scope/eslint-config-package/path"), + "@scope/eslint-config-package/path" + ); + + assert_eq!( + EslintPackage::Config.resolve_name("@scope/eslint-config/path"), + "@scope/eslint-config/path" + ); + + assert_eq!(EslintPackage::Config.resolve_name("package"), "eslint-config-package"); + + assert_eq!( + EslintPackage::Config.resolve_name("eslint-config-package"), + "eslint-config-package" + ); + } } diff --git a/crates/biome_cli/Source/execute/migrate/eslint_any_rule_to_biome.rs b/crates/biome_cli/Source/execute/migrate/eslint_any_rule_to_biome.rs index 16387c6c1a02..7eb4c81b6efa 100644 --- a/crates/biome_cli/Source/execute/migrate/eslint_any_rule_to_biome.rs +++ b/crates/biome_cli/Source/execute/migrate/eslint_any_rule_to_biome.rs @@ -2,2327 +2,2105 @@ use super::{eslint_eslint, eslint_to_biome}; pub(crate) fn migrate_eslint_any_rule( - rules: &mut biome_configuration::Rules, - eslint_name: &str, - rule_severity: eslint_eslint::Severity, - options: &eslint_to_biome::MigrationOptions, - results: &mut eslint_to_biome::MigrationResults, + rules:&mut biome_configuration::Rules, + eslint_name:&str, + rule_severity:eslint_eslint::Severity, + options:&eslint_to_biome::MigrationOptions, + results:&mut eslint_to_biome::MigrationResults, ) -> bool { - match eslint_name { - "@mysticatea/no-this-in-static" => { - let group = rules.complexity.get_or_insert_with(Default::default); - - let rule = group.no_this_in_static.get_or_insert(Default::default()); - - rule.set_level(rule_severity.into()); - } - "@next/google-font-display" => { - if !options.include_nursery { - return false; - } - - let group = rules.nursery.get_or_insert_with(Default::default); - - let rule = group - .use_google_font_display - .get_or_insert(Default::default()); + match eslint_name { + "@mysticatea/no-this-in-static" => { + let group = rules.complexity.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "@next/google-font-preconnect" => { - if !options.include_nursery { - return false; - } - - let group = rules.nursery.get_or_insert_with(Default::default); - - let rule = group - .use_google_font_preconnect - .get_or_insert(Default::default()); + let rule = group.no_this_in_static.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@next/no-document-import-in-page" => { - if !options.include_nursery { - return false; - } + rule.set_level(rule_severity.into()); + }, + "@next/google-font-display" => { + if !options.include_nursery { + return false; + } - let group = rules.nursery.get_or_insert_with(Default::default); + let group = rules.nursery.get_or_insert_with(Default::default); - let rule = group - .no_document_import_in_page - .get_or_insert(Default::default()); + let rule = group.use_google_font_display.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@next/no-head-element" => { - if !options.include_nursery { - return false; - } + rule.set_level(rule_severity.into()); + }, + "@next/google-font-preconnect" => { + if !options.include_nursery { + return false; + } - let group = rules.nursery.get_or_insert_with(Default::default); + let group = rules.nursery.get_or_insert_with(Default::default); - let rule = group.no_head_element.get_or_insert(Default::default()); + let rule = group.use_google_font_preconnect.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@next/no-head-import-in-document" => { - if !options.include_nursery { - return false; - } + rule.set_level(rule_severity.into()); + }, + "@next/no-document-import-in-page" => { + if !options.include_nursery { + return false; + } - let group = rules.nursery.get_or_insert_with(Default::default); + let group = rules.nursery.get_or_insert_with(Default::default); - let rule = group - .no_head_import_in_document - .get_or_insert(Default::default()); + let rule = group.no_document_import_in_page.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@next/no-img-element" => { - if !options.include_nursery { - return false; - } + rule.set_level(rule_severity.into()); + }, + "@next/no-head-element" => { + if !options.include_nursery { + return false; + } - let group = rules.nursery.get_or_insert_with(Default::default); + let group = rules.nursery.get_or_insert_with(Default::default); - let rule = group.no_img_element.get_or_insert(Default::default()); + let rule = group.no_head_element.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@stylistic/jsx-self-closing-comp" => { - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@next/no-head-import-in-document" => { + if !options.include_nursery { + return false; + } - let rule = group - .use_self_closing_elements - .get_or_insert(Default::default()); + let group = rules.nursery.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/adjacent-overload-signatures" => { - if !options.include_nursery { - return false; - } + let rule = group.no_head_import_in_document.get_or_insert(Default::default()); - let group = rules.nursery.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@next/no-img-element" => { + if !options.include_nursery { + return false; + } - let rule = group - .use_adjacent_overload_signatures - .get_or_insert(Default::default()); + let group = rules.nursery.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/array-type" => { - let group = rules.style.get_or_insert_with(Default::default); + let rule = group.no_img_element.get_or_insert(Default::default()); - let rule = group - .use_consistent_array_type - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "@stylistic/jsx-self-closing-comp" => { + let group = rules.style.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/ban-types" => { - let group = rules.complexity.get_or_insert_with(Default::default); + let rule = group.use_self_closing_elements.get_or_insert(Default::default()); - let rule = group.no_banned_types.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/adjacent-overload-signatures" => { + if !options.include_nursery { + return false; + } - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/consistent-type-exports" => { - if !options.include_inspired { - results.has_inspired_rules = true; + let group = rules.nursery.get_or_insert_with(Default::default); - return false; - } + let rule = group.use_adjacent_overload_signatures.get_or_insert(Default::default()); - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/array-type" => { + let group = rules.style.get_or_insert_with(Default::default); - let rule = group.use_export_type.get_or_insert(Default::default()); + let rule = group.use_consistent_array_type.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/consistent-type-imports" => { - if !options.include_inspired { - results.has_inspired_rules = true; + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/ban-types" => { + let group = rules.complexity.get_or_insert_with(Default::default); - return false; - } + let rule = group.no_banned_types.get_or_insert(Default::default()); - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/consistent-type-exports" => { + if !options.include_inspired { + results.has_inspired_rules = true; - let rule = group.use_import_type.get_or_insert(Default::default()); + return false; + } - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/default-param-last" => { - let group = rules.style.get_or_insert_with(Default::default); + let group = rules.style.get_or_insert_with(Default::default); - let rule = group - .use_default_parameter_last - .get_or_insert(Default::default()); + let rule = group.use_export_type.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/dot-notation" => { - let group = rules.complexity.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/consistent-type-imports" => { + if !options.include_inspired { + results.has_inspired_rules = true; - let rule = group.use_literal_keys.get_or_insert(Default::default()); + return false; + } - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/explicit-function-return-type" => { - if !options.include_nursery { - return false; - } + let group = rules.style.get_or_insert_with(Default::default); - let group = rules.nursery.get_or_insert_with(Default::default); + let rule = group.use_import_type.get_or_insert(Default::default()); - let rule = group.use_explicit_type.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/default-param-last" => { + let group = rules.style.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/explicit-member-accessibility" => { - if !options.include_nursery { - return false; - } + let rule = group.use_default_parameter_last.get_or_insert(Default::default()); - let group = rules.nursery.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/dot-notation" => { + let group = rules.complexity.get_or_insert_with(Default::default); - let rule = group - .use_consistent_member_accessibility - .get_or_insert(Default::default()); + let rule = group.use_literal_keys.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/naming-convention" => { - if !options.include_inspired { - results.has_inspired_rules = true; + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/explicit-function-return-type" => { + if !options.include_nursery { + return false; + } - return false; - } + let group = rules.nursery.get_or_insert_with(Default::default); - let group = rules.style.get_or_insert_with(Default::default); + let rule = group.use_explicit_type.get_or_insert(Default::default()); - let rule = group - .use_naming_convention - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/explicit-member-accessibility" => { + if !options.include_nursery { + return false; + } - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/no-array-constructor" => { - let group = rules.correctness.get_or_insert_with(Default::default); + let group = rules.nursery.get_or_insert_with(Default::default); - let rule = group.use_array_literals.get_or_insert(Default::default()); + let rule = group.use_consistent_member_accessibility.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/no-dupe-class-members" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/naming-convention" => { + if !options.include_inspired { + results.has_inspired_rules = true; - let rule = group - .no_duplicate_class_members - .get_or_insert(Default::default()); + return false; + } - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/no-empty-function" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + let group = rules.style.get_or_insert_with(Default::default); - let rule = group - .no_empty_block_statements - .get_or_insert(Default::default()); + let rule = group.use_naming_convention.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/no-empty-interface" => { - if !options.include_inspired { - results.has_inspired_rules = true; + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/no-array-constructor" => { + let group = rules.correctness.get_or_insert_with(Default::default); - return false; - } + let rule = group.use_array_literals.get_or_insert(Default::default()); - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/no-dupe-class-members" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group.no_empty_interface.get_or_insert(Default::default()); + let rule = group.no_duplicate_class_members.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/no-explicit-any" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/no-empty-function" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group.no_explicit_any.get_or_insert(Default::default()); + let rule = group.no_empty_block_statements.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/no-extra-non-null-assertion" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/no-empty-interface" => { + if !options.include_inspired { + results.has_inspired_rules = true; - let rule = group - .no_extra_non_null_assertion - .get_or_insert(Default::default()); + return false; + } - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/no-extraneous-class" => { - let group = rules.complexity.get_or_insert_with(Default::default); + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group.no_static_only_class.get_or_insert(Default::default()); + let rule = group.no_empty_interface.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/no-inferrable-types" => { - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/no-explicit-any" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group.no_inferrable_types.get_or_insert(Default::default()); + let rule = group.no_explicit_any.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/no-invalid-void-type" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/no-extra-non-null-assertion" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group - .no_confusing_void_type - .get_or_insert(Default::default()); + let rule = group.no_extra_non_null_assertion.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/no-loss-of-precision" => { - let group = rules.correctness.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/no-extraneous-class" => { + let group = rules.complexity.get_or_insert_with(Default::default); - let rule = group.no_precision_loss.get_or_insert(Default::default()); + let rule = group.no_static_only_class.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/no-misused-new" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/no-inferrable-types" => { + let group = rules.style.get_or_insert_with(Default::default); - let rule = group - .no_misleading_instantiator - .get_or_insert(Default::default()); + let rule = group.no_inferrable_types.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/no-namespace" => { - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/no-invalid-void-type" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group.no_namespace.get_or_insert(Default::default()); + let rule = group.no_confusing_void_type.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/no-non-null-assertion" => { - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/no-loss-of-precision" => { + let group = rules.correctness.get_or_insert_with(Default::default); - let rule = group - .no_non_null_assertion - .get_or_insert(Default::default()); + let rule = group.no_precision_loss.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/no-redeclare" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/no-misused-new" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group.no_redeclare.get_or_insert(Default::default()); + let rule = group.no_misleading_instantiator.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/no-require-imports" => { - if !options.include_nursery { - return false; - } + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/no-namespace" => { + let group = rules.style.get_or_insert_with(Default::default); - let group = rules.nursery.get_or_insert_with(Default::default); + let rule = group.no_namespace.get_or_insert(Default::default()); - let rule = group.no_common_js.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/no-non-null-assertion" => { + let group = rules.style.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/no-restricted-imports" => { - if !options.include_nursery { - return false; - } + let rule = group.no_non_null_assertion.get_or_insert(Default::default()); - let group = rules.nursery.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/no-redeclare" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group - .no_restricted_imports - .get_or_insert(Default::default()); + let rule = group.no_redeclare.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/no-restricted-types" => { - if !options.include_nursery { - return false; - } + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/no-require-imports" => { + if !options.include_nursery { + return false; + } - let group = rules.nursery.get_or_insert_with(Default::default); + let group = rules.nursery.get_or_insert_with(Default::default); - let rule = group.no_restricted_types.get_or_insert(Default::default()); + let rule = group.no_common_js.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/no-this-alias" => { - if !options.include_inspired { - results.has_inspired_rules = true; + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/no-restricted-imports" => { + if !options.include_nursery { + return false; + } - return false; - } + let group = rules.nursery.get_or_insert_with(Default::default); - let group = rules.complexity.get_or_insert_with(Default::default); + let rule = group.no_restricted_imports.get_or_insert(Default::default()); - let rule = group - .no_useless_this_alias - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/no-restricted-types" => { + if !options.include_nursery { + return false; + } - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/no-unnecessary-type-constraint" => { - let group = rules.complexity.get_or_insert_with(Default::default); + let group = rules.nursery.get_or_insert_with(Default::default); - let rule = group - .no_useless_type_constraint - .get_or_insert(Default::default()); + let rule = group.no_restricted_types.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/no-unsafe-declaration-merging" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/no-this-alias" => { + if !options.include_inspired { + results.has_inspired_rules = true; - let rule = group - .no_unsafe_declaration_merging - .get_or_insert(Default::default()); + return false; + } - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/no-unused-vars" => { - let group = rules.correctness.get_or_insert_with(Default::default); + let group = rules.complexity.get_or_insert_with(Default::default); - let rule = group.no_unused_variables.get_or_insert(Default::default()); + let rule = group.no_useless_this_alias.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/no-use-before-define" => { - let group = rules.correctness.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/no-unnecessary-type-constraint" => { + let group = rules.complexity.get_or_insert_with(Default::default); - let rule = group - .no_invalid_use_before_declaration - .get_or_insert(Default::default()); + let rule = group.no_useless_type_constraint.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/no-useless-constructor" => { - let group = rules.complexity.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/no-unsafe-declaration-merging" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group - .no_useless_constructor - .get_or_insert(Default::default()); + let rule = group.no_unsafe_declaration_merging.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/no-useless-empty-export" => { - let group = rules.complexity.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/no-unused-vars" => { + let group = rules.correctness.get_or_insert_with(Default::default); - let rule = group - .no_useless_empty_export - .get_or_insert(Default::default()); + let rule = group.no_unused_variables.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/only-throw-error" => { - if !options.include_inspired { - results.has_inspired_rules = true; + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/no-use-before-define" => { + let group = rules.correctness.get_or_insert_with(Default::default); - return false; - } + let rule = group.no_invalid_use_before_declaration.get_or_insert(Default::default()); - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/no-useless-constructor" => { + let group = rules.complexity.get_or_insert_with(Default::default); - let rule = group.use_throw_only_error.get_or_insert(Default::default()); + let rule = group.no_useless_constructor.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/parameter-properties" => { - if !options.include_inspired { - results.has_inspired_rules = true; + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/no-useless-empty-export" => { + let group = rules.complexity.get_or_insert_with(Default::default); - return false; - } + let rule = group.no_useless_empty_export.get_or_insert(Default::default()); - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/only-throw-error" => { + if !options.include_inspired { + results.has_inspired_rules = true; - let rule = group - .no_parameter_properties - .get_or_insert(Default::default()); + return false; + } - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/prefer-as-const" => { - let group = rules.style.get_or_insert_with(Default::default); + let group = rules.style.get_or_insert_with(Default::default); - let rule = group - .use_as_const_assertion - .get_or_insert(Default::default()); + let rule = group.use_throw_only_error.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/prefer-enum-initializers" => { - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/parameter-properties" => { + if !options.include_inspired { + results.has_inspired_rules = true; - let rule = group - .use_enum_initializers - .get_or_insert(Default::default()); + return false; + } - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/prefer-for-of" => { - let group = rules.style.get_or_insert_with(Default::default); + let group = rules.style.get_or_insert_with(Default::default); - let rule = group.use_for_of.get_or_insert(Default::default()); + let rule = group.no_parameter_properties.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/prefer-function-type" => { - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/prefer-as-const" => { + let group = rules.style.get_or_insert_with(Default::default); - let rule = group - .use_shorthand_function_type - .get_or_insert(Default::default()); + let rule = group.use_as_const_assertion.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/prefer-literal-enum-member" => { - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/prefer-enum-initializers" => { + let group = rules.style.get_or_insert_with(Default::default); - let rule = group - .use_literal_enum_members - .get_or_insert(Default::default()); + let rule = group.use_enum_initializers.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/prefer-namespace-keyword" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/prefer-for-of" => { + let group = rules.style.get_or_insert_with(Default::default); - let rule = group - .use_namespace_keyword - .get_or_insert(Default::default()); + let rule = group.use_for_of.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/prefer-optional-chain" => { - let group = rules.complexity.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/prefer-function-type" => { + let group = rules.style.get_or_insert_with(Default::default); - let rule = group.use_optional_chain.get_or_insert(Default::default()); + let rule = group.use_shorthand_function_type.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "@typescript-eslint/require-await" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/prefer-literal-enum-member" => { + let group = rules.style.get_or_insert_with(Default::default); - let rule = group.use_await.get_or_insert(Default::default()); + let rule = group.use_literal_enum_members.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "barrel-files/avoid-barrel-files" => { - if !options.include_inspired { - results.has_inspired_rules = true; + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/prefer-namespace-keyword" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - return false; - } + let rule = group.use_namespace_keyword.get_or_insert(Default::default()); - let group = rules.performance.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/prefer-optional-chain" => { + let group = rules.complexity.get_or_insert_with(Default::default); - let rule = group.no_barrel_file.get_or_insert(Default::default()); + let rule = group.use_optional_chain.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "barrel-files/avoid-namespace-import" => { - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "@typescript-eslint/require-await" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group.no_namespace_import.get_or_insert(Default::default()); + let rule = group.use_await.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "barrel-files/avoid-re-export-all" => { - let group = rules.performance.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "barrel-files/avoid-barrel-files" => { + if !options.include_inspired { + results.has_inspired_rules = true; - let rule = group.no_re_export_all.get_or_insert(Default::default()); + return false; + } - rule.set_level(rule_severity.into()); - } - "constructor-super" => { - let group = rules.correctness.get_or_insert_with(Default::default); + let group = rules.performance.get_or_insert_with(Default::default); - let rule = group - .no_invalid_constructor_super - .get_or_insert(Default::default()); + let rule = group.no_barrel_file.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "curly" => { - let group = rules.style.get_or_insert_with(Default::default); - - let rule = group.use_block_statements.get_or_insert(Default::default()); - - rule.set_level(rule_severity.into()); - } - "default-case" => { - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "barrel-files/avoid-namespace-import" => { + let group = rules.style.get_or_insert_with(Default::default); - let rule = group - .use_default_switch_clause - .get_or_insert(Default::default()); + let rule = group.no_namespace_import.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "default-case-last" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "barrel-files/avoid-re-export-all" => { + let group = rules.performance.get_or_insert_with(Default::default); - let rule = group - .use_default_switch_clause_last - .get_or_insert(Default::default()); + let rule = group.no_re_export_all.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "default-param-last" => { - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "constructor-super" => { + let group = rules.correctness.get_or_insert_with(Default::default); - let rule = group - .use_default_parameter_last - .get_or_insert(Default::default()); + let rule = group.no_invalid_constructor_super.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "dot-notation" => { - let group = rules.complexity.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "curly" => { + let group = rules.style.get_or_insert_with(Default::default); - let rule = group.use_literal_keys.get_or_insert(Default::default()); + let rule = group.use_block_statements.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "eqeqeq" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "default-case" => { + let group = rules.style.get_or_insert_with(Default::default); - let rule = group.no_double_equals.get_or_insert(Default::default()); + let rule = group.use_default_switch_clause.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "for-direction" => { - let group = rules.correctness.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "default-case-last" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group - .use_valid_for_direction - .get_or_insert(Default::default()); + let rule = group.use_default_switch_clause_last.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "getter-return" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "default-param-last" => { + let group = rules.style.get_or_insert_with(Default::default); - let rule = group.use_getter_return.get_or_insert(Default::default()); + let rule = group.use_default_parameter_last.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "guard-for-in" => { - if !options.include_nursery { - return false; - } + rule.set_level(rule_severity.into()); + }, + "dot-notation" => { + let group = rules.complexity.get_or_insert_with(Default::default); - let group = rules.nursery.get_or_insert_with(Default::default); + let rule = group.use_literal_keys.get_or_insert(Default::default()); - let rule = group.use_guard_for_in.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "eqeqeq" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "import-access/eslint-plugin-import-access" => { - if !options.include_inspired { - results.has_inspired_rules = true; + let rule = group.no_double_equals.get_or_insert(Default::default()); - return false; - } + rule.set_level(rule_severity.into()); + }, + "for-direction" => { + let group = rules.correctness.get_or_insert_with(Default::default); - if !options.include_nursery { - return false; - } + let rule = group.use_valid_for_direction.get_or_insert(Default::default()); - let group = rules.nursery.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "getter-return" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group - .use_import_restrictions - .get_or_insert(Default::default()); + let rule = group.use_getter_return.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "import/exports-last" => { - if !options.include_nursery { - return false; - } - let group = rules.nursery.get_or_insert_with(Default::default); - let rule = group.use_exports_last.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "import/no-commonjs" => { - if !options.include_nursery { - return false; - } + rule.set_level(rule_severity.into()); + }, + "guard-for-in" => { + if !options.include_nursery { + return false; + } - let group = rules.nursery.get_or_insert_with(Default::default); + let group = rules.nursery.get_or_insert_with(Default::default); - let rule = group.no_common_js.get_or_insert(Default::default()); + let rule = group.use_guard_for_in.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "import/no-default-export" => { - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "import-access/eslint-plugin-import-access" => { + if !options.include_inspired { + results.has_inspired_rules = true; - let rule = group.no_default_export.get_or_insert(Default::default()); + return false; + } - rule.set_level(rule_severity.into()); - } - "import/no-extraneous-dependencies" => { - let group = rules.correctness.get_or_insert_with(Default::default); + if !options.include_nursery { + return false; + } - let rule = group - .no_undeclared_dependencies - .get_or_insert(Default::default()); + let group = rules.nursery.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "import/no-nodejs-modules" => { - let group = rules.correctness.get_or_insert_with(Default::default); + let rule = group.use_import_restrictions.get_or_insert(Default::default()); - let rule = group.no_nodejs_modules.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "import/exports-last" => { + if !options.include_nursery { + return false; + } + let group = rules.nursery.get_or_insert_with(Default::default); + let rule = group.use_exports_last.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "import/no-commonjs" => { + if !options.include_nursery { + return false; + } - rule.set_level(rule_severity.into()); - } - "jest/max-nested-describe" => { - let group = rules.complexity.get_or_insert_with(Default::default); + let group = rules.nursery.get_or_insert_with(Default::default); - let rule = group - .no_excessive_nested_test_suites - .get_or_insert(Default::default()); + let rule = group.no_common_js.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "jest/no-disabled-tests" => { - if !options.include_inspired { - results.has_inspired_rules = true; + rule.set_level(rule_severity.into()); + }, + "import/no-default-export" => { + let group = rules.style.get_or_insert_with(Default::default); - return false; - } + let rule = group.no_default_export.get_or_insert(Default::default()); - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "import/no-extraneous-dependencies" => { + let group = rules.correctness.get_or_insert_with(Default::default); - let rule = group.no_skipped_tests.get_or_insert(Default::default()); + let rule = group.no_undeclared_dependencies.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "jest/no-done-callback" => { - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "import/no-nodejs-modules" => { + let group = rules.correctness.get_or_insert_with(Default::default); - let rule = group.no_done_callback.get_or_insert(Default::default()); + let rule = group.no_nodejs_modules.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "jest/no-duplicate-hooks" => { - if !options.include_inspired { - results.has_inspired_rules = true; + rule.set_level(rule_severity.into()); + }, + "jest/max-nested-describe" => { + let group = rules.complexity.get_or_insert_with(Default::default); - return false; - } + let rule = group.no_excessive_nested_test_suites.get_or_insert(Default::default()); - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "jest/no-disabled-tests" => { + if !options.include_inspired { + results.has_inspired_rules = true; - let rule = group - .no_duplicate_test_hooks - .get_or_insert(Default::default()); + return false; + } - rule.set_level(rule_severity.into()); - } - "jest/no-export" => { - if !options.include_inspired { - results.has_inspired_rules = true; + let group = rules.suspicious.get_or_insert_with(Default::default); - return false; - } + let rule = group.no_skipped_tests.get_or_insert(Default::default()); - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "jest/no-done-callback" => { + let group = rules.style.get_or_insert_with(Default::default); - let rule = group.no_exports_in_test.get_or_insert(Default::default()); + let rule = group.no_done_callback.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "jest/no-focused-tests" => { - if !options.include_inspired { - results.has_inspired_rules = true; + rule.set_level(rule_severity.into()); + }, + "jest/no-duplicate-hooks" => { + if !options.include_inspired { + results.has_inspired_rules = true; - return false; - } + return false; + } - let group = rules.suspicious.get_or_insert_with(Default::default); + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group.no_focused_tests.get_or_insert(Default::default()); + let rule = group.no_duplicate_test_hooks.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "jest/no-standalone-expect" => { - if !options.include_inspired { - results.has_inspired_rules = true; + rule.set_level(rule_severity.into()); + }, + "jest/no-export" => { + if !options.include_inspired { + results.has_inspired_rules = true; - return false; - } + return false; + } - let group = rules.suspicious.get_or_insert_with(Default::default); + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group - .no_misplaced_assertion - .get_or_insert(Default::default()); + let rule = group.no_exports_in_test.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "jsx-a11y/alt-text" => { - let group = rules.a11y.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "jest/no-focused-tests" => { + if !options.include_inspired { + results.has_inspired_rules = true; - let rule = group.use_alt_text.get_or_insert(Default::default()); + return false; + } - rule.set_level(rule_severity.into()); - } - "jsx-a11y/anchor-has-content" => { - let group = rules.a11y.get_or_insert_with(Default::default); + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group.use_anchor_content.get_or_insert(Default::default()); + let rule = group.no_focused_tests.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "jsx-a11y/anchor-is-valid" => { - let group = rules.a11y.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "jest/no-standalone-expect" => { + if !options.include_inspired { + results.has_inspired_rules = true; - let rule = group.use_valid_anchor.get_or_insert(Default::default()); + return false; + } - rule.set_level(rule_severity.into()); - } - "jsx-a11y/aria-activedescendant-has-tabindex" => { - let group = rules.a11y.get_or_insert_with(Default::default); + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group - .use_aria_activedescendant_with_tabindex - .get_or_insert(Default::default()); + let rule = group.no_misplaced_assertion.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "jsx-a11y/aria-props" => { - let group = rules.a11y.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/alt-text" => { + let group = rules.a11y.get_or_insert_with(Default::default); - let rule = group.use_valid_aria_props.get_or_insert(Default::default()); + let rule = group.use_alt_text.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "jsx-a11y/aria-proptypes" => { - let group = rules.a11y.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/anchor-has-content" => { + let group = rules.a11y.get_or_insert_with(Default::default); - let rule = group - .use_valid_aria_values - .get_or_insert(Default::default()); + let rule = group.use_anchor_content.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "jsx-a11y/aria-role" => { - let group = rules.a11y.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/anchor-is-valid" => { + let group = rules.a11y.get_or_insert_with(Default::default); - let rule = group.use_valid_aria_role.get_or_insert(Default::default()); + let rule = group.use_valid_anchor.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "jsx-a11y/aria-unsupported-elements" => { - let group = rules.a11y.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/aria-activedescendant-has-tabindex" => { + let group = rules.a11y.get_or_insert_with(Default::default); - let rule = group - .no_aria_unsupported_elements - .get_or_insert(Default::default()); + let rule = group.use_aria_activedescendant_with_tabindex.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "jsx-a11y/autocomplete-valid" => { - if !options.include_nursery { - return false; - } + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/aria-props" => { + let group = rules.a11y.get_or_insert_with(Default::default); - let group = rules.nursery.get_or_insert_with(Default::default); + let rule = group.use_valid_aria_props.get_or_insert(Default::default()); - let rule = group - .use_valid_autocomplete - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/aria-proptypes" => { + let group = rules.a11y.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "jsx-a11y/click-events-have-key-events" => { - let group = rules.a11y.get_or_insert_with(Default::default); + let rule = group.use_valid_aria_values.get_or_insert(Default::default()); - let rule = group - .use_key_with_click_events - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/aria-role" => { + let group = rules.a11y.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "jsx-a11y/heading-has-content" => { - let group = rules.a11y.get_or_insert_with(Default::default); + let rule = group.use_valid_aria_role.get_or_insert(Default::default()); - let rule = group.use_heading_content.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/aria-unsupported-elements" => { + let group = rules.a11y.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "jsx-a11y/html-has-lang" => { - let group = rules.a11y.get_or_insert_with(Default::default); + let rule = group.no_aria_unsupported_elements.get_or_insert(Default::default()); - let rule = group.use_html_lang.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/autocomplete-valid" => { + if !options.include_nursery { + return false; + } - rule.set_level(rule_severity.into()); - } - "jsx-a11y/iframe-has-title" => { - let group = rules.a11y.get_or_insert_with(Default::default); + let group = rules.nursery.get_or_insert_with(Default::default); - let rule = group.use_iframe_title.get_or_insert(Default::default()); + let rule = group.use_valid_autocomplete.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "jsx-a11y/img-redundant-alt" => { - let group = rules.a11y.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/click-events-have-key-events" => { + let group = rules.a11y.get_or_insert_with(Default::default); - let rule = group.no_redundant_alt.get_or_insert(Default::default()); + let rule = group.use_key_with_click_events.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "jsx-a11y/interactive-supports-focus" => { - let group = rules.a11y.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/heading-has-content" => { + let group = rules.a11y.get_or_insert_with(Default::default); - let rule = group - .use_focusable_interactive - .get_or_insert(Default::default()); + let rule = group.use_heading_content.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "jsx-a11y/label-has-associated-control" => { - let group = rules.a11y.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/html-has-lang" => { + let group = rules.a11y.get_or_insert_with(Default::default); - let rule = group - .no_label_without_control - .get_or_insert(Default::default()); + let rule = group.use_html_lang.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "jsx-a11y/lang" => { - let group = rules.a11y.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/iframe-has-title" => { + let group = rules.a11y.get_or_insert_with(Default::default); - let rule = group.use_valid_lang.get_or_insert(Default::default()); + let rule = group.use_iframe_title.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "jsx-a11y/media-has-caption" => { - let group = rules.a11y.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/img-redundant-alt" => { + let group = rules.a11y.get_or_insert_with(Default::default); - let rule = group.use_media_caption.get_or_insert(Default::default()); - - rule.set_level(rule_severity.into()); - } - "jsx-a11y/mouse-events-have-key-events" => { - let group = rules.a11y.get_or_insert_with(Default::default); - - let rule = group - .use_key_with_mouse_events - .get_or_insert(Default::default()); - - rule.set_level(rule_severity.into()); - } - "jsx-a11y/no-access-key" => { - let group = rules.a11y.get_or_insert_with(Default::default); - - let rule = group.no_access_key.get_or_insert(Default::default()); - - rule.set_level(rule_severity.into()); - } - "jsx-a11y/no-aria-hidden-on-focusable" => { - let group = rules.a11y.get_or_insert_with(Default::default); - - let rule = group - .no_aria_hidden_on_focusable - .get_or_insert(Default::default()); + let rule = group.no_redundant_alt.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "jsx-a11y/no-autofocus" => { - let group = rules.a11y.get_or_insert_with(Default::default); - - let rule = group.no_autofocus.get_or_insert(Default::default()); - - rule.set_level(rule_severity.into()); - } - "jsx-a11y/no-distracting-elements" => { - let group = rules.a11y.get_or_insert_with(Default::default); - - let rule = group - .no_distracting_elements - .get_or_insert(Default::default()); - - rule.set_level(rule_severity.into()); - } - "jsx-a11y/no-interactive-element-to-noninteractive-role" => { - let group = rules.a11y.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/interactive-supports-focus" => { + let group = rules.a11y.get_or_insert_with(Default::default); - let rule = group - .no_interactive_element_to_noninteractive_role - .get_or_insert(Default::default()); + let rule = group.use_focusable_interactive.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "jsx-a11y/no-noninteractive-element-to-interactive-role" => { - let group = rules.a11y.get_or_insert_with(Default::default); - - let rule = group - .no_noninteractive_element_to_interactive_role - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/label-has-associated-control" => { + let group = rules.a11y.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "jsx-a11y/no-noninteractive-tabindex" => { - let group = rules.a11y.get_or_insert_with(Default::default); - - let rule = group - .no_noninteractive_tabindex - .get_or_insert(Default::default()); - - rule.set_level(rule_severity.into()); - } - "jsx-a11y/no-redundant-roles" => { - let group = rules.a11y.get_or_insert_with(Default::default); - - let rule = group.no_redundant_roles.get_or_insert(Default::default()); - - rule.set_level(rule_severity.into()); - } - "jsx-a11y/no-static-element-interactions" => { - if !options.include_nursery { - return false; - } + let rule = group.no_label_without_control.get_or_insert(Default::default()); - let group = rules.nursery.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/lang" => { + let group = rules.a11y.get_or_insert_with(Default::default); - let rule = group - .no_static_element_interactions - .get_or_insert(Default::default()); - - rule.set_level(rule_severity.into()); - } - "jsx-a11y/prefer-tag-over-role" => { - let group = rules.a11y.get_or_insert_with(Default::default); + let rule = group.use_valid_lang.get_or_insert(Default::default()); - let rule = group - .use_semantic_elements - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/media-has-caption" => { + let group = rules.a11y.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "jsx-a11y/role-has-required-aria-props" => { - let group = rules.a11y.get_or_insert_with(Default::default); - - let rule = group - .use_aria_props_for_role - .get_or_insert(Default::default()); + let rule = group.use_media_caption.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "jsx-a11y/role-supports-aria-props" => { - if !options.include_nursery { - return false; - } + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/mouse-events-have-key-events" => { + let group = rules.a11y.get_or_insert_with(Default::default); - let group = rules.nursery.get_or_insert_with(Default::default); + let rule = group.use_key_with_mouse_events.get_or_insert(Default::default()); - let rule = group - .use_aria_props_supported_by_role - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/no-access-key" => { + let group = rules.a11y.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "jsx-a11y/scope" => { - let group = rules.a11y.get_or_insert_with(Default::default); + let rule = group.no_access_key.get_or_insert(Default::default()); - let rule = group.no_header_scope.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/no-aria-hidden-on-focusable" => { + let group = rules.a11y.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "jsx-a11y/tabindex-no-positive" => { - let group = rules.a11y.get_or_insert_with(Default::default); + let rule = group.no_aria_hidden_on_focusable.get_or_insert(Default::default()); - let rule = group.no_positive_tabindex.get_or_insert(Default::default()); - - rule.set_level(rule_severity.into()); - } - "n/no-process-env" => { - if !options.include_nursery { - return false; - } + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/no-autofocus" => { + let group = rules.a11y.get_or_insert_with(Default::default); - let group = rules.nursery.get_or_insert_with(Default::default); - - let rule = group.no_process_env.get_or_insert(Default::default()); + let rule = group.no_autofocus.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-array-constructor" => { - let group = rules.correctness.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/no-distracting-elements" => { + let group = rules.a11y.get_or_insert_with(Default::default); - let rule = group.use_array_literals.get_or_insert(Default::default()); + let rule = group.no_distracting_elements.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-async-promise-executor" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/no-interactive-element-to-noninteractive-role" => { + let group = rules.a11y.get_or_insert_with(Default::default); - let rule = group - .no_async_promise_executor - .get_or_insert(Default::default()); + let rule = group + .no_interactive_element_to_noninteractive_role + .get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-case-declarations" => { - let group = rules.correctness.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/no-noninteractive-element-to-interactive-role" => { + let group = rules.a11y.get_or_insert_with(Default::default); - let rule = group - .no_switch_declarations - .get_or_insert(Default::default()); - - rule.set_level(rule_severity.into()); - } - "no-class-assign" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + let rule = group + .no_noninteractive_element_to_interactive_role + .get_or_insert(Default::default()); - let rule = group.no_class_assign.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/no-noninteractive-tabindex" => { + let group = rules.a11y.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "no-compare-neg-zero" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + let rule = group.no_noninteractive_tabindex.get_or_insert(Default::default()); - let rule = group.no_compare_neg_zero.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/no-redundant-roles" => { + let group = rules.a11y.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "no-cond-assign" => { - if !options.include_inspired { - results.has_inspired_rules = true; + let rule = group.no_redundant_roles.get_or_insert(Default::default()); - return false; - } + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/no-static-element-interactions" => { + if !options.include_nursery { + return false; + } - let group = rules.suspicious.get_or_insert_with(Default::default); + let group = rules.nursery.get_or_insert_with(Default::default); - let rule = group - .no_assign_in_expressions - .get_or_insert(Default::default()); + let rule = group.no_static_element_interactions.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-console" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/prefer-tag-over-role" => { + let group = rules.a11y.get_or_insert_with(Default::default); - let rule = group.no_console.get_or_insert(Default::default()); + let rule = group.use_semantic_elements.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-const-assign" => { - let group = rules.correctness.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/role-has-required-aria-props" => { + let group = rules.a11y.get_or_insert_with(Default::default); - let rule = group.no_const_assign.get_or_insert(Default::default()); + let rule = group.use_aria_props_for_role.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-constant-condition" => { - let group = rules.correctness.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/role-supports-aria-props" => { + if !options.include_nursery { + return false; + } - let rule = group - .no_constant_condition - .get_or_insert(Default::default()); + let group = rules.nursery.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "no-constructor-return" => { - let group = rules.correctness.get_or_insert_with(Default::default); + let rule = group.use_aria_props_supported_by_role.get_or_insert(Default::default()); - let rule = group - .no_constructor_return - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/scope" => { + let group = rules.a11y.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "no-control-regex" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + let rule = group.no_header_scope.get_or_insert(Default::default()); - let rule = group - .no_control_characters_in_regex - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "jsx-a11y/tabindex-no-positive" => { + let group = rules.a11y.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "no-debugger" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + let rule = group.no_positive_tabindex.get_or_insert(Default::default()); - let rule = group.no_debugger.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "n/no-process-env" => { + if !options.include_nursery { + return false; + } - rule.set_level(rule_severity.into()); - } - "no-dupe-args" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + let group = rules.nursery.get_or_insert_with(Default::default); - let rule = group - .no_duplicate_parameters - .get_or_insert(Default::default()); + let rule = group.no_process_env.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-dupe-class-members" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-array-constructor" => { + let group = rules.correctness.get_or_insert_with(Default::default); - let rule = group - .no_duplicate_class_members - .get_or_insert(Default::default()); + let rule = group.use_array_literals.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-dupe-else-if" => { - if !options.include_nursery { - return false; - } + rule.set_level(rule_severity.into()); + }, + "no-async-promise-executor" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let group = rules.nursery.get_or_insert_with(Default::default); + let rule = group.no_async_promise_executor.get_or_insert(Default::default()); - let rule = group.no_duplicate_else_if.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "no-case-declarations" => { + let group = rules.correctness.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "no-dupe-keys" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + let rule = group.no_switch_declarations.get_or_insert(Default::default()); - let rule = group - .no_duplicate_object_keys - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "no-class-assign" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "no-duplicate-case" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + let rule = group.no_class_assign.get_or_insert(Default::default()); - let rule = group.no_duplicate_case.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "no-compare-neg-zero" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "no-else-return" => { - if !options.include_inspired { - results.has_inspired_rules = true; + let rule = group.no_compare_neg_zero.get_or_insert(Default::default()); - return false; - } + rule.set_level(rule_severity.into()); + }, + "no-cond-assign" => { + if !options.include_inspired { + results.has_inspired_rules = true; - let group = rules.style.get_or_insert_with(Default::default); + return false; + } - let rule = group.no_useless_else.get_or_insert(Default::default()); + let group = rules.suspicious.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "no-empty" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + let rule = group.no_assign_in_expressions.get_or_insert(Default::default()); - let rule = group - .no_empty_block_statements - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "no-console" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "no-empty-character-class" => { - let group = rules.correctness.get_or_insert_with(Default::default); + let rule = group.no_console.get_or_insert(Default::default()); - let rule = group - .no_empty_character_class_in_regex - .get_or_insert(Default::default()); - - rule.set_level(rule_severity.into()); - } - "no-empty-function" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-const-assign" => { + let group = rules.correctness.get_or_insert_with(Default::default); - let rule = group - .no_empty_block_statements - .get_or_insert(Default::default()); + let rule = group.no_const_assign.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-empty-pattern" => { - let group = rules.correctness.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-constant-condition" => { + let group = rules.correctness.get_or_insert_with(Default::default); - let rule = group.no_empty_pattern.get_or_insert(Default::default()); + let rule = group.no_constant_condition.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-empty-static-block" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-constructor-return" => { + let group = rules.correctness.get_or_insert_with(Default::default); - let rule = group - .no_empty_block_statements - .get_or_insert(Default::default()); + let rule = group.no_constructor_return.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-eval" => { - let group = rules.security.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-control-regex" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group.no_global_eval.get_or_insert(Default::default()); + let rule = group.no_control_characters_in_regex.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-ex-assign" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-debugger" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group.no_catch_assign.get_or_insert(Default::default()); + let rule = group.no_debugger.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-extra-boolean-cast" => { - let group = rules.complexity.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-dupe-args" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group - .no_extra_boolean_cast - .get_or_insert(Default::default()); + let rule = group.no_duplicate_parameters.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-extra-label" => { - let group = rules.complexity.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-dupe-class-members" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group.no_useless_label.get_or_insert(Default::default()); + let rule = group.no_duplicate_class_members.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-fallthrough" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-dupe-else-if" => { + if !options.include_nursery { + return false; + } - let rule = group - .no_fallthrough_switch_clause - .get_or_insert(Default::default()); + let group = rules.nursery.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "no-func-assign" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + let rule = group.no_duplicate_else_if.get_or_insert(Default::default()); - let rule = group.no_function_assign.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "no-dupe-keys" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "no-global-assign" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + let rule = group.no_duplicate_object_keys.get_or_insert(Default::default()); - let rule = group.no_global_assign.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "no-duplicate-case" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "no-import-assign" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + let rule = group.no_duplicate_case.get_or_insert(Default::default()); - let rule = group.no_import_assign.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "no-else-return" => { + if !options.include_inspired { + results.has_inspired_rules = true; - rule.set_level(rule_severity.into()); - } - "no-inner-declarations" => { - let group = rules.correctness.get_or_insert_with(Default::default); + return false; + } - let rule = group - .no_inner_declarations - .get_or_insert(Default::default()); + let group = rules.style.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "no-irregular-whitespace" => { - if !options.include_nursery { - return false; - } + let rule = group.no_useless_else.get_or_insert(Default::default()); - let group = rules.nursery.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-empty" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group - .no_irregular_whitespace - .get_or_insert(Default::default()); + let rule = group.no_empty_block_statements.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-label-var" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-empty-character-class" => { + let group = rules.correctness.get_or_insert_with(Default::default); - let rule = group.no_label_var.get_or_insert(Default::default()); + let rule = group.no_empty_character_class_in_regex.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-labels" => { - if !options.include_inspired { - results.has_inspired_rules = true; + rule.set_level(rule_severity.into()); + }, + "no-empty-function" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - return false; - } + let rule = group.no_empty_block_statements.get_or_insert(Default::default()); - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-empty-pattern" => { + let group = rules.correctness.get_or_insert_with(Default::default); - let rule = group.no_confusing_labels.get_or_insert(Default::default()); + let rule = group.no_empty_pattern.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-lone-blocks" => { - let group = rules.complexity.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-empty-static-block" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group - .no_useless_lone_block_statements - .get_or_insert(Default::default()); + let rule = group.no_empty_block_statements.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-lonely-if" => { - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-eval" => { + let group = rules.security.get_or_insert_with(Default::default); - let rule = group - .use_collapsed_else_if - .get_or_insert(Default::default()); + let rule = group.no_global_eval.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-loss-of-precision" => { - let group = rules.correctness.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-ex-assign" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group.no_precision_loss.get_or_insert(Default::default()); + let rule = group.no_catch_assign.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-misleading-character-class" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-extra-boolean-cast" => { + let group = rules.complexity.get_or_insert_with(Default::default); - let rule = group - .no_misleading_character_class - .get_or_insert(Default::default()); + let rule = group.no_extra_boolean_cast.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-negated-condition" => { - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-extra-label" => { + let group = rules.complexity.get_or_insert_with(Default::default); - let rule = group.no_negation_else.get_or_insert(Default::default()); + let rule = group.no_useless_label.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-nested-ternary" => { - if !options.include_nursery { - return false; - } + rule.set_level(rule_severity.into()); + }, + "no-fallthrough" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let group = rules.nursery.get_or_insert_with(Default::default); + let rule = group.no_fallthrough_switch_clause.get_or_insert(Default::default()); - let rule = group.no_nested_ternary.get_or_insert(Default::default()); - - rule.set_level(rule_severity.into()); - } - "no-new-native-nonconstructor" => { - let group = rules.correctness.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-func-assign" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group - .no_invalid_builtin_instantiation - .get_or_insert(Default::default()); + let rule = group.no_function_assign.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-new-symbol" => { - let group = rules.correctness.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-global-assign" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group.no_new_symbol.get_or_insert(Default::default()); - - rule.set_level(rule_severity.into()); - } - "no-new-wrappers" => { - let group = rules.style.get_or_insert_with(Default::default); + let rule = group.no_global_assign.get_or_insert(Default::default()); - let rule = group - .use_consistent_builtin_instantiation - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "no-import-assign" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "no-nonoctal-decimal-escape" => { - let group = rules.correctness.get_or_insert_with(Default::default); + let rule = group.no_import_assign.get_or_insert(Default::default()); - let rule = group - .no_nonoctal_decimal_escape - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "no-inner-declarations" => { + let group = rules.correctness.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "no-obj-calls" => { - let group = rules.correctness.get_or_insert_with(Default::default); + let rule = group.no_inner_declarations.get_or_insert(Default::default()); - let rule = group - .no_global_object_calls - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "no-irregular-whitespace" => { + if !options.include_nursery { + return false; + } - rule.set_level(rule_severity.into()); - } - "no-octal-escape" => { - if !options.include_nursery { - return false; - } + let group = rules.nursery.get_or_insert_with(Default::default); - let group = rules.nursery.get_or_insert_with(Default::default); + let rule = group.no_irregular_whitespace.get_or_insert(Default::default()); - let rule = group.no_octal_escape.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "no-label-var" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "no-param-reassign" => { - let group = rules.style.get_or_insert_with(Default::default); + let rule = group.no_label_var.get_or_insert(Default::default()); - let rule = group.no_parameter_assign.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "no-labels" => { + if !options.include_inspired { + results.has_inspired_rules = true; - rule.set_level(rule_severity.into()); - } - "no-prototype-builtins" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + return false; + } - let rule = group - .no_prototype_builtins - .get_or_insert(Default::default()); + let group = rules.suspicious.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "no-redeclare" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + let rule = group.no_confusing_labels.get_or_insert(Default::default()); - let rule = group.no_redeclare.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "no-lone-blocks" => { + let group = rules.complexity.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "no-regex-spaces" => { - let group = rules.complexity.get_or_insert_with(Default::default); + let rule = group.no_useless_lone_block_statements.get_or_insert(Default::default()); - let rule = group - .no_multiple_spaces_in_regular_expression_literals - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "no-lonely-if" => { + let group = rules.style.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "no-restricted-globals" => { - let group = rules.style.get_or_insert_with(Default::default); + let rule = group.use_collapsed_else_if.get_or_insert(Default::default()); - let rule = group - .no_restricted_globals - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "no-loss-of-precision" => { + let group = rules.correctness.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "no-restricted-imports" => { - if !options.include_nursery { - return false; - } + let rule = group.no_precision_loss.get_or_insert(Default::default()); - let group = rules.nursery.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-misleading-character-class" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group - .no_restricted_imports - .get_or_insert(Default::default()); + let rule = group.no_misleading_character_class.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-secrets/no-secrets" => { - if !options.include_inspired { - results.has_inspired_rules = true; + rule.set_level(rule_severity.into()); + }, + "no-negated-condition" => { + let group = rules.style.get_or_insert_with(Default::default); - return false; - } + let rule = group.no_negation_else.get_or_insert(Default::default()); - if !options.include_nursery { - return false; - } + rule.set_level(rule_severity.into()); + }, + "no-nested-ternary" => { + if !options.include_nursery { + return false; + } - let group = rules.nursery.get_or_insert_with(Default::default); + let group = rules.nursery.get_or_insert_with(Default::default); - let rule = group.no_secrets.get_or_insert(Default::default()); + let rule = group.no_nested_ternary.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-self-assign" => { - let group = rules.correctness.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-new-native-nonconstructor" => { + let group = rules.correctness.get_or_insert_with(Default::default); - let rule = group.no_self_assign.get_or_insert(Default::default()); + let rule = group.no_invalid_builtin_instantiation.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-self-compare" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-new-symbol" => { + let group = rules.correctness.get_or_insert_with(Default::default); - let rule = group.no_self_compare.get_or_insert(Default::default()); + let rule = group.no_new_symbol.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-sequences" => { - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-new-wrappers" => { + let group = rules.style.get_or_insert_with(Default::default); - let rule = group.no_comma_operator.get_or_insert(Default::default()); + let rule = group.use_consistent_builtin_instantiation.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-setter-return" => { - let group = rules.correctness.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-nonoctal-decimal-escape" => { + let group = rules.correctness.get_or_insert_with(Default::default); - let rule = group.no_setter_return.get_or_insert(Default::default()); + let rule = group.no_nonoctal_decimal_escape.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-shadow-restricted-names" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-obj-calls" => { + let group = rules.correctness.get_or_insert_with(Default::default); - let rule = group - .no_shadow_restricted_names - .get_or_insert(Default::default()); + let rule = group.no_global_object_calls.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-sparse-arrays" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-octal-escape" => { + if !options.include_nursery { + return false; + } - let rule = group.no_sparse_array.get_or_insert(Default::default()); + let group = rules.nursery.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "no-template-curly-in-string" => { - if !options.include_nursery { - return false; - } + let rule = group.no_octal_escape.get_or_insert(Default::default()); - let group = rules.nursery.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-param-reassign" => { + let group = rules.style.get_or_insert_with(Default::default); - let rule = group - .no_template_curly_in_string - .get_or_insert(Default::default()); + let rule = group.no_parameter_assign.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-this-before-super" => { - let group = rules.correctness.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-prototype-builtins" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group.no_unreachable_super.get_or_insert(Default::default()); + let rule = group.no_prototype_builtins.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-throw-literal" => { - if !options.include_inspired { - results.has_inspired_rules = true; + rule.set_level(rule_severity.into()); + }, + "no-redeclare" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - return false; - } + let rule = group.no_redeclare.get_or_insert(Default::default()); - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-regex-spaces" => { + let group = rules.complexity.get_or_insert_with(Default::default); - let rule = group.use_throw_only_error.get_or_insert(Default::default()); + let rule = group + .no_multiple_spaces_in_regular_expression_literals + .get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-undef" => { - let group = rules.correctness.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-restricted-globals" => { + let group = rules.style.get_or_insert_with(Default::default); - let rule = group - .no_undeclared_variables - .get_or_insert(Default::default()); + let rule = group.no_restricted_globals.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-undef-init" => { - let group = rules.complexity.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-restricted-imports" => { + if !options.include_nursery { + return false; + } - let rule = group - .no_useless_undefined_initialization - .get_or_insert(Default::default()); + let group = rules.nursery.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "no-unneeded-ternary" => { - let group = rules.complexity.get_or_insert_with(Default::default); + let rule = group.no_restricted_imports.get_or_insert(Default::default()); - let rule = group.no_useless_ternary.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "no-secrets/no-secrets" => { + if !options.include_inspired { + results.has_inspired_rules = true; - rule.set_level(rule_severity.into()); - } - "no-unreachable" => { - let group = rules.correctness.get_or_insert_with(Default::default); + return false; + } - let rule = group.no_unreachable.get_or_insert(Default::default()); + if !options.include_nursery { + return false; + } - rule.set_level(rule_severity.into()); - } - "no-unsafe-finally" => { - let group = rules.correctness.get_or_insert_with(Default::default); + let group = rules.nursery.get_or_insert_with(Default::default); - let rule = group.no_unsafe_finally.get_or_insert(Default::default()); + let rule = group.no_secrets.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-unsafe-negation" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-self-assign" => { + let group = rules.correctness.get_or_insert_with(Default::default); - let rule = group.no_unsafe_negation.get_or_insert(Default::default()); + let rule = group.no_self_assign.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-unsafe-optional-chaining" => { - let group = rules.correctness.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-self-compare" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group - .no_unsafe_optional_chaining - .get_or_insert(Default::default()); + let rule = group.no_self_compare.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-unused-labels" => { - let group = rules.correctness.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-sequences" => { + let group = rules.style.get_or_insert_with(Default::default); - let rule = group.no_unused_labels.get_or_insert(Default::default()); + let rule = group.no_comma_operator.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-unused-private-class-members" => { - let group = rules.correctness.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-setter-return" => { + let group = rules.correctness.get_or_insert_with(Default::default); - let rule = group - .no_unused_private_class_members - .get_or_insert(Default::default()); + let rule = group.no_setter_return.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-unused-vars" => { - let group = rules.correctness.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-shadow-restricted-names" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group.no_unused_variables.get_or_insert(Default::default()); + let rule = group.no_shadow_restricted_names.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-use-before-define" => { - let group = rules.correctness.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-sparse-arrays" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group - .no_invalid_use_before_declaration - .get_or_insert(Default::default()); + let rule = group.no_sparse_array.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-useless-catch" => { - let group = rules.complexity.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-template-curly-in-string" => { + if !options.include_nursery { + return false; + } - let rule = group.no_useless_catch.get_or_insert(Default::default()); + let group = rules.nursery.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "no-useless-concat" => { - let group = rules.complexity.get_or_insert_with(Default::default); + let rule = group.no_template_curly_in_string.get_or_insert(Default::default()); - let rule = group - .no_useless_string_concat - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "no-this-before-super" => { + let group = rules.correctness.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "no-useless-constructor" => { - let group = rules.complexity.get_or_insert_with(Default::default); + let rule = group.no_unreachable_super.get_or_insert(Default::default()); - let rule = group - .no_useless_constructor - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "no-throw-literal" => { + if !options.include_inspired { + results.has_inspired_rules = true; - rule.set_level(rule_severity.into()); - } - "no-useless-escape" => { - if !options.include_nursery { - return false; - } + return false; + } - let group = rules.nursery.get_or_insert_with(Default::default); + let group = rules.style.get_or_insert_with(Default::default); - let rule = group - .no_useless_escape_in_regex - .get_or_insert(Default::default()); + let rule = group.use_throw_only_error.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-useless-rename" => { - let group = rules.complexity.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-undef" => { + let group = rules.correctness.get_or_insert_with(Default::default); - let rule = group.no_useless_rename.get_or_insert(Default::default()); + let rule = group.no_undeclared_variables.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-var" => { - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-undef-init" => { + let group = rules.complexity.get_or_insert_with(Default::default); - let rule = group.no_var.get_or_insert(Default::default()); + let rule = group.no_useless_undefined_initialization.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-void" => { - let group = rules.complexity.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-unneeded-ternary" => { + let group = rules.complexity.get_or_insert_with(Default::default); - let rule = group.no_void.get_or_insert(Default::default()); + let rule = group.no_useless_ternary.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "no-with" => { - let group = rules.complexity.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-unreachable" => { + let group = rules.correctness.get_or_insert_with(Default::default); - let rule = group.no_with.get_or_insert(Default::default()); + let rule = group.no_unreachable.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "one-var" => { - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-unsafe-finally" => { + let group = rules.correctness.get_or_insert_with(Default::default); - let rule = group - .use_single_var_declarator - .get_or_insert(Default::default()); + let rule = group.no_unsafe_finally.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "operator-assignment" => { - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-unsafe-negation" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group.use_shorthand_assign.get_or_insert(Default::default()); + let rule = group.no_unsafe_negation.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "prefer-arrow-callback" => { - if !options.include_inspired { - results.has_inspired_rules = true; + rule.set_level(rule_severity.into()); + }, + "no-unsafe-optional-chaining" => { + let group = rules.correctness.get_or_insert_with(Default::default); - return false; - } + let rule = group.no_unsafe_optional_chaining.get_or_insert(Default::default()); - let group = rules.complexity.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-unused-labels" => { + let group = rules.correctness.get_or_insert_with(Default::default); - let rule = group.use_arrow_function.get_or_insert(Default::default()); + let rule = group.no_unused_labels.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "prefer-const" => { - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-unused-private-class-members" => { + let group = rules.correctness.get_or_insert_with(Default::default); - let rule = group.use_const.get_or_insert(Default::default()); + let rule = group.no_unused_private_class_members.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "prefer-exponentiation-operator" => { - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-unused-vars" => { + let group = rules.correctness.get_or_insert_with(Default::default); - let rule = group - .use_exponentiation_operator - .get_or_insert(Default::default()); + let rule = group.no_unused_variables.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "prefer-numeric-literals" => { - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-use-before-define" => { + let group = rules.correctness.get_or_insert_with(Default::default); - let rule = group.use_numeric_literals.get_or_insert(Default::default()); + let rule = group.no_invalid_use_before_declaration.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "prefer-object-has-own" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-useless-catch" => { + let group = rules.complexity.get_or_insert_with(Default::default); - let rule = group - .no_prototype_builtins - .get_or_insert(Default::default()); + let rule = group.no_useless_catch.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "prefer-regex-literals" => { - let group = rules.complexity.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-useless-concat" => { + let group = rules.complexity.get_or_insert_with(Default::default); - let rule = group.use_regex_literals.get_or_insert(Default::default()); + let rule = group.no_useless_string_concat.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "prefer-rest-params" => { - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-useless-constructor" => { + let group = rules.complexity.get_or_insert_with(Default::default); - let rule = group.no_arguments.get_or_insert(Default::default()); + let rule = group.no_useless_constructor.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "prefer-template" => { - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-useless-escape" => { + if !options.include_nursery { + return false; + } - let rule = group.use_template.get_or_insert(Default::default()); + let group = rules.nursery.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "react-hooks/exhaustive-deps" => { - let group = rules.correctness.get_or_insert_with(Default::default); + let rule = group.no_useless_escape_in_regex.get_or_insert(Default::default()); - let rule = group - .use_exhaustive_dependencies - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "no-useless-rename" => { + let group = rules.complexity.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "react-hooks/rules-of-hooks" => { - let group = rules.correctness.get_or_insert_with(Default::default); + let rule = group.no_useless_rename.get_or_insert(Default::default()); - let rule = group - .use_hook_at_top_level - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "no-var" => { + let group = rules.style.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "react-refresh/only-export-components" => { - if !options.include_inspired { - results.has_inspired_rules = true; + let rule = group.no_var.get_or_insert(Default::default()); - return false; - } + rule.set_level(rule_severity.into()); + }, + "no-void" => { + let group = rules.complexity.get_or_insert_with(Default::default); - if !options.include_nursery { - return false; - } + let rule = group.no_void.get_or_insert(Default::default()); - let group = rules.nursery.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "no-with" => { + let group = rules.complexity.get_or_insert_with(Default::default); - let rule = group - .use_component_export_only_modules - .get_or_insert(Default::default()); + let rule = group.no_with.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "react/button-has-type" => { - let group = rules.a11y.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "one-var" => { + let group = rules.style.get_or_insert_with(Default::default); - let rule = group.use_button_type.get_or_insert(Default::default()); + let rule = group.use_single_var_declarator.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "react/jsx-boolean-value" => { - if !options.include_inspired { - results.has_inspired_rules = true; + rule.set_level(rule_severity.into()); + }, + "operator-assignment" => { + let group = rules.style.get_or_insert_with(Default::default); - return false; - } + let rule = group.use_shorthand_assign.get_or_insert(Default::default()); - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "prefer-arrow-callback" => { + if !options.include_inspired { + results.has_inspired_rules = true; - let rule = group.no_implicit_boolean.get_or_insert(Default::default()); + return false; + } - rule.set_level(rule_severity.into()); - } - "react/jsx-curly-brace-presence" => { - if !options.include_inspired { - results.has_inspired_rules = true; + let group = rules.complexity.get_or_insert_with(Default::default); - return false; - } + let rule = group.use_arrow_function.get_or_insert(Default::default()); - if !options.include_nursery { - return false; - } + rule.set_level(rule_severity.into()); + }, + "prefer-const" => { + let group = rules.style.get_or_insert_with(Default::default); - let group = rules.nursery.get_or_insert_with(Default::default); + let rule = group.use_const.get_or_insert(Default::default()); - let rule = group - .use_consistent_curly_braces - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "prefer-exponentiation-operator" => { + let group = rules.style.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "react/jsx-fragments" => { - let group = rules.style.get_or_insert_with(Default::default); + let rule = group.use_exponentiation_operator.get_or_insert(Default::default()); - let rule = group.use_fragment_syntax.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "prefer-numeric-literals" => { + let group = rules.style.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "react/jsx-key" => { - let group = rules.correctness.get_or_insert_with(Default::default); + let rule = group.use_numeric_literals.get_or_insert(Default::default()); - let rule = group - .use_jsx_key_in_iterable - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "prefer-object-has-own" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "react/jsx-no-comment-textnodes" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + let rule = group.no_prototype_builtins.get_or_insert(Default::default()); - let rule = group.no_comment_text.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "prefer-regex-literals" => { + let group = rules.complexity.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "react/jsx-no-duplicate-props" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + let rule = group.use_regex_literals.get_or_insert(Default::default()); - let rule = group - .no_duplicate_jsx_props - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "prefer-rest-params" => { + let group = rules.style.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "react/jsx-no-target-blank" => { - let group = rules.a11y.get_or_insert_with(Default::default); + let rule = group.no_arguments.get_or_insert(Default::default()); - let rule = group.no_blank_target.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "prefer-template" => { + let group = rules.style.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "react/jsx-no-useless-fragment" => { - let group = rules.complexity.get_or_insert_with(Default::default); + let rule = group.use_template.get_or_insert(Default::default()); - let rule = group.no_useless_fragments.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "react-hooks/exhaustive-deps" => { + let group = rules.correctness.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "react/no-array-index-key" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + let rule = group.use_exhaustive_dependencies.get_or_insert(Default::default()); - let rule = group.no_array_index_key.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "react-hooks/rules-of-hooks" => { + let group = rules.correctness.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "react/no-children-prop" => { - let group = rules.correctness.get_or_insert_with(Default::default); + let rule = group.use_hook_at_top_level.get_or_insert(Default::default()); - let rule = group.no_children_prop.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "react-refresh/only-export-components" => { + if !options.include_inspired { + results.has_inspired_rules = true; - rule.set_level(rule_severity.into()); - } - "react/no-danger" => { - let group = rules.security.get_or_insert_with(Default::default); + return false; + } - let rule = group - .no_dangerously_set_inner_html - .get_or_insert(Default::default()); + if !options.include_nursery { + return false; + } - rule.set_level(rule_severity.into()); - } - "react/no-danger-with-children" => { - let group = rules.security.get_or_insert_with(Default::default); + let group = rules.nursery.get_or_insert_with(Default::default); - let rule = group - .no_dangerously_set_inner_html_with_children - .get_or_insert(Default::default()); + let rule = group.use_component_export_only_modules.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "react/void-dom-elements-no-children" => { - let group = rules.correctness.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "react/button-has-type" => { + let group = rules.a11y.get_or_insert_with(Default::default); - let rule = group - .no_void_elements_with_children - .get_or_insert(Default::default()); + let rule = group.use_button_type.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "require-await" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "react/jsx-boolean-value" => { + if !options.include_inspired { + results.has_inspired_rules = true; - let rule = group.use_await.get_or_insert(Default::default()); + return false; + } - rule.set_level(rule_severity.into()); - } - "require-yield" => { - let group = rules.correctness.get_or_insert_with(Default::default); + let group = rules.style.get_or_insert_with(Default::default); - let rule = group.use_yield.get_or_insert(Default::default()); + let rule = group.no_implicit_boolean.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "solidjs/no-react-specific-props" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "react/jsx-curly-brace-presence" => { + if !options.include_inspired { + results.has_inspired_rules = true; - let rule = group - .no_react_specific_props - .get_or_insert(Default::default()); + return false; + } - rule.set_level(rule_severity.into()); - } - "sonarjs/cognitive-complexity" => { - let group = rules.complexity.get_or_insert_with(Default::default); + if !options.include_nursery { + return false; + } - let rule = group - .no_excessive_cognitive_complexity - .get_or_insert(Default::default()); + let group = rules.nursery.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "sonarjs/prefer-while" => { - let group = rules.style.get_or_insert_with(Default::default); + let rule = group.use_consistent_curly_braces.get_or_insert(Default::default()); - let rule = group.use_while.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "react/jsx-fragments" => { + let group = rules.style.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "unicorn/error-message" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + let rule = group.use_fragment_syntax.get_or_insert(Default::default()); - let rule = group.use_error_message.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "react/jsx-key" => { + let group = rules.correctness.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "unicorn/explicit-length-check" => { - let group = rules.style.get_or_insert_with(Default::default); + let rule = group.use_jsx_key_in_iterable.get_or_insert(Default::default()); - let rule = group - .use_explicit_length_check - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "react/jsx-no-comment-textnodes" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "unicorn/filename-case" => { - if !options.include_inspired { - results.has_inspired_rules = true; + let rule = group.no_comment_text.get_or_insert(Default::default()); - return false; - } + rule.set_level(rule_severity.into()); + }, + "react/jsx-no-duplicate-props" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let group = rules.style.get_or_insert_with(Default::default); + let rule = group.no_duplicate_jsx_props.get_or_insert(Default::default()); - let rule = group - .use_filenaming_convention - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "react/jsx-no-target-blank" => { + let group = rules.a11y.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "unicorn/new-for-builtins" => { - let group = rules.correctness.get_or_insert_with(Default::default); + let rule = group.no_blank_target.get_or_insert(Default::default()); - let rule = group - .no_invalid_builtin_instantiation - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "react/jsx-no-useless-fragment" => { + let group = rules.complexity.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "unicorn/no-array-for-each" => { - let group = rules.complexity.get_or_insert_with(Default::default); + let rule = group.no_useless_fragments.get_or_insert(Default::default()); - let rule = group.no_for_each.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "react/no-array-index-key" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "unicorn/no-document-cookie" => { - if !options.include_nursery { - return false; - } + let rule = group.no_array_index_key.get_or_insert(Default::default()); - let group = rules.nursery.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "react/no-children-prop" => { + let group = rules.correctness.get_or_insert_with(Default::default); - let rule = group.no_document_cookie.get_or_insert(Default::default()); + let rule = group.no_children_prop.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "unicorn/no-for-loop" => { - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "react/no-danger" => { + let group = rules.security.get_or_insert_with(Default::default); - let rule = group.use_for_of.get_or_insert(Default::default()); + let rule = group.no_dangerously_set_inner_html.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "unicorn/no-instanceof-array" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "react/no-danger-with-children" => { + let group = rules.security.get_or_insert_with(Default::default); - let rule = group.use_is_array.get_or_insert(Default::default()); + let rule = group + .no_dangerously_set_inner_html_with_children + .get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "unicorn/no-lonely-if" => { - if !options.include_nursery { - return false; - } + rule.set_level(rule_severity.into()); + }, + "react/void-dom-elements-no-children" => { + let group = rules.correctness.get_or_insert_with(Default::default); - let group = rules.nursery.get_or_insert_with(Default::default); + let rule = group.no_void_elements_with_children.get_or_insert(Default::default()); - let rule = group.use_collapsed_if.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "require-await" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "unicorn/no-static-only-class" => { - let group = rules.complexity.get_or_insert_with(Default::default); + let rule = group.use_await.get_or_insert(Default::default()); - let rule = group.no_static_only_class.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "require-yield" => { + let group = rules.correctness.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "unicorn/no-thenable" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + let rule = group.use_yield.get_or_insert(Default::default()); - let rule = group.no_then_property.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "solidjs/no-react-specific-props" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "unicorn/no-useless-switch-case" => { - let group = rules.complexity.get_or_insert_with(Default::default); + let rule = group.no_react_specific_props.get_or_insert(Default::default()); - let rule = group - .no_useless_switch_case - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "sonarjs/cognitive-complexity" => { + let group = rules.complexity.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "unicorn/no-useless-undefined" => { - if !options.include_nursery { - return false; - } + let rule = group.no_excessive_cognitive_complexity.get_or_insert(Default::default()); - let group = rules.nursery.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "sonarjs/prefer-while" => { + let group = rules.style.get_or_insert_with(Default::default); - let rule = group.no_useless_undefined.get_or_insert(Default::default()); + let rule = group.use_while.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "unicorn/prefer-array-flat-map" => { - let group = rules.complexity.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "unicorn/error-message" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group.use_flat_map.get_or_insert(Default::default()); + let rule = group.use_error_message.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "unicorn/prefer-at" => { - if !options.include_inspired { - results.has_inspired_rules = true; + rule.set_level(rule_severity.into()); + }, + "unicorn/explicit-length-check" => { + let group = rules.style.get_or_insert_with(Default::default); - return false; - } + let rule = group.use_explicit_length_check.get_or_insert(Default::default()); - if !options.include_nursery { - return false; - } + rule.set_level(rule_severity.into()); + }, + "unicorn/filename-case" => { + if !options.include_inspired { + results.has_inspired_rules = true; - let group = rules.nursery.get_or_insert_with(Default::default); + return false; + } - let rule = group.use_at_index.get_or_insert(Default::default()); + let group = rules.style.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "unicorn/prefer-date-now" => { - let group = rules.complexity.get_or_insert_with(Default::default); + let rule = group.use_filenaming_convention.get_or_insert(Default::default()); - let rule = group.use_date_now.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "unicorn/new-for-builtins" => { + let group = rules.correctness.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "unicorn/prefer-module" => { - if !options.include_inspired { - results.has_inspired_rules = true; + let rule = group.no_invalid_builtin_instantiation.get_or_insert(Default::default()); - return false; - } + rule.set_level(rule_severity.into()); + }, + "unicorn/no-array-for-each" => { + let group = rules.complexity.get_or_insert_with(Default::default); - if !options.include_nursery { - return false; - } + let rule = group.no_for_each.get_or_insert(Default::default()); - let group = rules.nursery.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "unicorn/no-document-cookie" => { + if !options.include_nursery { + return false; + } - let rule = group - .no_global_dirname_filename - .get_or_insert(Default::default()); + let group = rules.nursery.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "unicorn/prefer-node-protocol" => { - let group = rules.style.get_or_insert_with(Default::default); + let rule = group.no_document_cookie.get_or_insert(Default::default()); - let rule = group - .use_nodejs_import_protocol - .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "unicorn/no-for-loop" => { + let group = rules.style.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "unicorn/prefer-number-properties" => { - let group = rules.style.get_or_insert_with(Default::default); + let rule = group.use_for_of.get_or_insert(Default::default()); - let rule = group.use_number_namespace.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "unicorn/no-instanceof-array" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "unicorn/prefer-string-slice" => { - if !options.include_nursery { - return false; - } + let rule = group.use_is_array.get_or_insert(Default::default()); - let group = rules.nursery.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "unicorn/no-lonely-if" => { + if !options.include_nursery { + return false; + } - let rule = group.no_substr.get_or_insert(Default::default()); + let group = rules.nursery.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "unicorn/prefer-string-trim-start-end" => { - if !options.include_nursery { - return false; - } + let rule = group.use_collapsed_if.get_or_insert(Default::default()); - let group = rules.nursery.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "unicorn/no-static-only-class" => { + let group = rules.complexity.get_or_insert_with(Default::default); - let rule = group.use_trim_start_end.get_or_insert(Default::default()); + let rule = group.no_static_only_class.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "unicorn/require-number-to-fixed-digits-argument" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "unicorn/no-thenable" => { + let group = rules.suspicious.get_or_insert_with(Default::default); - let rule = group - .use_number_to_fixed_digits_argument - .get_or_insert(Default::default()); + let rule = group.no_then_property.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "unicorn/throw-new-error" => { - let group = rules.style.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "unicorn/no-useless-switch-case" => { + let group = rules.complexity.get_or_insert_with(Default::default); - let rule = group.use_throw_new_error.get_or_insert(Default::default()); + let rule = group.no_useless_switch_case.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } - "unused-imports/no-unused-imports" => { - let group = rules.correctness.get_or_insert_with(Default::default); + rule.set_level(rule_severity.into()); + }, + "unicorn/no-useless-undefined" => { + if !options.include_nursery { + return false; + } - let rule = group.no_unused_imports.get_or_insert(Default::default()); + let group = rules.nursery.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "unused-imports/no-unused-vars" => { - let group = rules.correctness.get_or_insert_with(Default::default); + let rule = group.no_useless_undefined.get_or_insert(Default::default()); - let rule = group.no_unused_variables.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "unicorn/prefer-array-flat-map" => { + let group = rules.complexity.get_or_insert_with(Default::default); - rule.set_level(rule_severity.into()); - } - "use-isnan" => { - let group = rules.correctness.get_or_insert_with(Default::default); + let rule = group.use_flat_map.get_or_insert(Default::default()); - let rule = group.use_is_nan.get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + }, + "unicorn/prefer-at" => { + if !options.include_inspired { + results.has_inspired_rules = true; - rule.set_level(rule_severity.into()); - } - "valid-typeof" => { - let group = rules.suspicious.get_or_insert_with(Default::default); + return false; + } - let rule = group.use_valid_typeof.get_or_insert(Default::default()); + if !options.include_nursery { + return false; + } - rule.set_level(rule_severity.into()); - } - "yoda" => { - let group = rules.style.get_or_insert_with(Default::default); + let group = rules.nursery.get_or_insert_with(Default::default); - let rule = group.no_yoda_expression.get_or_insert(Default::default()); + let rule = group.use_at_index.get_or_insert(Default::default()); - rule.set_level(rule_severity.into()); - } + rule.set_level(rule_severity.into()); + }, + "unicorn/prefer-date-now" => { + let group = rules.complexity.get_or_insert_with(Default::default); - _ => { - return false; - } - } + let rule = group.use_date_now.get_or_insert(Default::default()); - true + rule.set_level(rule_severity.into()); + }, + "unicorn/prefer-module" => { + if !options.include_inspired { + results.has_inspired_rules = true; + + return false; + } + + if !options.include_nursery { + return false; + } + + let group = rules.nursery.get_or_insert_with(Default::default); + + let rule = group.no_global_dirname_filename.get_or_insert(Default::default()); + + rule.set_level(rule_severity.into()); + }, + "unicorn/prefer-node-protocol" => { + let group = rules.style.get_or_insert_with(Default::default); + + let rule = group.use_nodejs_import_protocol.get_or_insert(Default::default()); + + rule.set_level(rule_severity.into()); + }, + "unicorn/prefer-number-properties" => { + let group = rules.style.get_or_insert_with(Default::default); + + let rule = group.use_number_namespace.get_or_insert(Default::default()); + + rule.set_level(rule_severity.into()); + }, + "unicorn/prefer-string-slice" => { + if !options.include_nursery { + return false; + } + + let group = rules.nursery.get_or_insert_with(Default::default); + + let rule = group.no_substr.get_or_insert(Default::default()); + + rule.set_level(rule_severity.into()); + }, + "unicorn/prefer-string-trim-start-end" => { + if !options.include_nursery { + return false; + } + + let group = rules.nursery.get_or_insert_with(Default::default); + + let rule = group.use_trim_start_end.get_or_insert(Default::default()); + + rule.set_level(rule_severity.into()); + }, + "unicorn/require-number-to-fixed-digits-argument" => { + let group = rules.suspicious.get_or_insert_with(Default::default); + + let rule = group.use_number_to_fixed_digits_argument.get_or_insert(Default::default()); + + rule.set_level(rule_severity.into()); + }, + "unicorn/throw-new-error" => { + let group = rules.style.get_or_insert_with(Default::default); + + let rule = group.use_throw_new_error.get_or_insert(Default::default()); + + rule.set_level(rule_severity.into()); + }, + "unused-imports/no-unused-imports" => { + let group = rules.correctness.get_or_insert_with(Default::default); + + let rule = group.no_unused_imports.get_or_insert(Default::default()); + + rule.set_level(rule_severity.into()); + }, + "unused-imports/no-unused-vars" => { + let group = rules.correctness.get_or_insert_with(Default::default); + + let rule = group.no_unused_variables.get_or_insert(Default::default()); + + rule.set_level(rule_severity.into()); + }, + "use-isnan" => { + let group = rules.correctness.get_or_insert_with(Default::default); + + let rule = group.use_is_nan.get_or_insert(Default::default()); + + rule.set_level(rule_severity.into()); + }, + "valid-typeof" => { + let group = rules.suspicious.get_or_insert_with(Default::default); + + let rule = group.use_valid_typeof.get_or_insert(Default::default()); + + rule.set_level(rule_severity.into()); + }, + "yoda" => { + let group = rules.style.get_or_insert_with(Default::default); + + let rule = group.no_yoda_expression.get_or_insert(Default::default()); + + rule.set_level(rule_severity.into()); + }, + + _ => { + return false; + }, + } + + true } diff --git a/crates/biome_cli/Source/execute/migrate/eslint_eslint.rs b/crates/biome_cli/Source/execute/migrate/eslint_eslint.rs index c65b5e493969..bc7103ed21a8 100644 --- a/crates/biome_cli/Source/execute/migrate/eslint_eslint.rs +++ b/crates/biome_cli/Source/execute/migrate/eslint_eslint.rs @@ -1,40 +1,47 @@ +use std::{ + any::TypeId, + borrow::Cow, + hash::{Hash, Hasher}, + marker::PhantomData, + ops::{Deref, DerefMut}, + vec, +}; + use biome_deserialize::{ - Deserializable, DeserializableType, DeserializableTypes, DeserializableValue, - DeserializationDiagnostic, DeserializationVisitor, Merge, + Deserializable, + DeserializableType, + DeserializableTypes, + DeserializableValue, + DeserializationDiagnostic, + DeserializationVisitor, + Merge, }; use biome_deserialize_macros::Deserializable; use biome_rowan::TextRange; use indexmap::IndexSet; use rustc_hash::FxHashMap; -use std::borrow::Cow; -use std::hash::{Hash, Hasher}; -use std::ops::DerefMut; -use std::vec; -use std::{any::TypeId, marker::PhantomData, ops::Deref}; use super::{eslint_jsxa11y, eslint_typescript, eslint_unicorn, ignorefile}; -/// This modules includes implementations for deserializing an eslint configuration. +/// This modules includes implementations for deserializing an eslint +/// configuration. /// /// The defined types follow the ESLint configuration schema described at /// . /// -/// See [super::eslint_to_biome] for converting an ESLint config to a Biome config. +/// See [super::eslint_to_biome] for converting an ESLint config to a Biome +/// config. #[derive(Debug)] pub(crate) enum AnyConfigData { - Flat(FlatConfigData), - Legacy(LegacyConfigData), + Flat(FlatConfigData), + Legacy(LegacyConfigData), } impl From for AnyConfigData { - fn from(value: FlatConfigData) -> Self { - AnyConfigData::Flat(value) - } + fn from(value:FlatConfigData) -> Self { AnyConfigData::Flat(value) } } impl From for AnyConfigData { - fn from(value: LegacyConfigData) -> Self { - AnyConfigData::Legacy(value) - } + fn from(value:LegacyConfigData) -> Self { AnyConfigData::Legacy(value) } } #[derive(Debug, Default, Deserializable)] @@ -43,111 +50,102 @@ pub(crate) struct FlatConfigData(pub(crate) Vec); #[derive(Debug, Default, Deserializable)] #[deserializable(unknown_fields = "allow")] pub(crate) struct FlatConfigObject { - pub(crate) files: Vec, - /// The glob patterns that ignore to lint. - pub(crate) ignores: Vec, - // using `Option` is important to distinguish a global ignores from a config objerct - pub(crate) language_options: Option, - // using `Option` is important to distinguish a global ignores from a config objerct - pub(crate) rules: Option, + pub(crate) files:Vec, + /// The glob patterns that ignore to lint. + pub(crate) ignores:Vec, + // using `Option` is important to distinguish a global ignores from a config objerct + pub(crate) language_options:Option, + // using `Option` is important to distinguish a global ignores from a config objerct + pub(crate) rules:Option, } impl FlatConfigObject { - /// Rteurns `true` if this config contains only `ignores`. - /// - /// See https://eslint.org/docs/latest/use/configure/configuration-files-new#globally-ignoring-files-with-ignores - pub(crate) fn is_global_ignores(&self) -> bool { - !self.ignores.is_empty() - && self.files.is_empty() - && self.language_options.is_none() - && self.rules.is_none() - } - - /// Rteurns `true` if this config doesn't specify `files` or `ignores`. - pub(crate) fn is_global_config(&self) -> bool { - self.ignores.is_empty() && self.files.is_empty() - } + /// Rteurns `true` if this config contains only `ignores`. + /// + /// See https://eslint.org/docs/latest/use/configure/configuration-files-new#globally-ignoring-files-with-ignores + pub(crate) fn is_global_ignores(&self) -> bool { + !self.ignores.is_empty() && self.files.is_empty() && self.language_options.is_none() && self.rules.is_none() + } + + /// Rteurns `true` if this config doesn't specify `files` or `ignores`. + pub(crate) fn is_global_config(&self) -> bool { self.ignores.is_empty() && self.files.is_empty() } } impl Merge for FlatConfigObject { - fn merge_with(&mut self, other: Self) { - self.files.extend(other.files); + fn merge_with(&mut self, other:Self) { + self.files.extend(other.files); - self.ignores.extend(other.ignores); + self.ignores.extend(other.ignores); - self.language_options.merge_with(other.language_options); + self.language_options.merge_with(other.language_options); - self.rules.merge_with(other.rules); - } + self.rules.merge_with(other.rules); + } } #[derive(Debug, Default, Deserializable)] #[deserializable(unknown_fields = "allow")] pub(crate) struct FlatLanguageOptions { - pub(crate) globals: Globals, + pub(crate) globals:Globals, } impl Merge for FlatLanguageOptions { - fn merge_with(&mut self, other: Self) { - self.globals.merge_with(other.globals); - } + fn merge_with(&mut self, other:Self) { self.globals.merge_with(other.globals); } } #[derive(Debug, Default, Deserializable)] #[deserializable(unknown_fields = "allow")] pub(crate) struct EslintPackageJson { - pub(crate) eslint_config: Option, - pub(crate) eslint_ignore: Vec, + pub(crate) eslint_config:Option, + pub(crate) eslint_ignore:Vec, } #[derive(Debug, Default, Deserializable)] #[deserializable(unknown_fields = "allow")] pub(crate) struct LegacyConfigData { - pub(crate) extends: ShorthandVec, - pub(crate) globals: Globals, - /// The glob patterns that ignore to lint. - pub(crate) ignore_patterns: ShorthandVec, - /// The parser options. - pub(crate) rules: Rules, - pub(crate) overrides: Vec, + pub(crate) extends:ShorthandVec, + pub(crate) globals:Globals, + /// The glob patterns that ignore to lint. + pub(crate) ignore_patterns:ShorthandVec, + /// The parser options. + pub(crate) rules:Rules, + pub(crate) overrides:Vec, } impl Merge for LegacyConfigData { - fn merge_with(&mut self, mut other: Self) { - self.extends.merge_with(other.extends); + fn merge_with(&mut self, mut other:Self) { + self.extends.merge_with(other.extends); - self.globals.merge_with(other.globals); + self.globals.merge_with(other.globals); - self.ignore_patterns.merge_with(other.ignore_patterns); + self.ignore_patterns.merge_with(other.ignore_patterns); - self.rules.merge_with(other.rules); + self.rules.merge_with(other.rules); - self.overrides.append(&mut other.overrides); - } + self.overrides.append(&mut other.overrides); + } } #[derive(Debug, Default)] pub(crate) struct IgnorePattern(pub(crate) String); impl Deref for IgnorePattern { - type Target = String; + type Target = String; - fn deref(&self) -> &Self::Target { - &self.0 - } + fn deref(&self) -> &Self::Target { &self.0 } } impl biome_deserialize::Deserializable for IgnorePattern { - fn deserialize( - value: &impl DeserializableValue, - name: &str, - diagnostics: &mut Vec, - ) -> Option { - let s = biome_deserialize::Text::deserialize(value, name, diagnostics)?; + fn deserialize( + value:&impl DeserializableValue, + name:&str, + diagnostics:&mut Vec, + ) -> Option { + let s = biome_deserialize::Text::deserialize(value, name, diagnostics)?; - match ignorefile::convert_pattern(s.text()) { - Ok(pattern) => Some(Self(pattern)), - Err(msg) => { - diagnostics.push(DeserializationDiagnostic::new(msg).with_range(value.range())); + match ignorefile::convert_pattern(s.text()) { + Ok(pattern) => Some(Self(pattern)), + Err(msg) => { + diagnostics.push(DeserializationDiagnostic::new(msg).with_range(value.range())); - None - } - } - } + None + }, + } + } } //? ESLint plugins export metadata in their main export. @@ -155,517 +153,477 @@ impl biome_deserialize::Deserializable for IgnorePattern { #[derive(Debug, Default, Deserializable)] #[deserializable(unknown_fields = "allow")] pub(crate) struct PluginExport { - pub(crate) configs: FxHashMap, + pub(crate) configs:FxHashMap, } #[derive(Debug, Default, Deserializable)] pub(crate) struct Globals(pub(crate) FxHashMap); impl Globals { - pub(crate) fn enabled(self) -> impl Iterator { - self.0.into_iter().filter_map(|(global_name, global_conf)| { - global_conf.is_enabled().then_some(global_name) - }) - } + pub(crate) fn enabled(self) -> impl Iterator { + self.0 + .into_iter() + .filter_map(|(global_name, global_conf)| global_conf.is_enabled().then_some(global_name)) + } } impl Deref for Globals { - type Target = FxHashMap; + type Target = FxHashMap; - fn deref(&self) -> &Self::Target { - &self.0 - } + fn deref(&self) -> &Self::Target { &self.0 } } impl Merge for Globals { - fn merge_with(&mut self, other: Self) { - self.0.extend(other.0); - } + fn merge_with(&mut self, other:Self) { self.0.extend(other.0); } } #[derive(Debug)] pub(crate) enum GlobalConf { - Flag(bool), - Qualifier(GlobalConfQualifier), + Flag(bool), + Qualifier(GlobalConfQualifier), } impl GlobalConf { - pub(crate) fn is_enabled(&self) -> bool { - match self { - GlobalConf::Flag(result) => *result, - GlobalConf::Qualifier(qualifier) => !matches!(qualifier, GlobalConfQualifier::Off), - } - } + pub(crate) fn is_enabled(&self) -> bool { + match self { + GlobalConf::Flag(result) => *result, + GlobalConf::Qualifier(qualifier) => !matches!(qualifier, GlobalConfQualifier::Off), + } + } } impl Deserializable for GlobalConf { - fn deserialize( - value: &impl biome_deserialize::DeserializableValue, - name: &str, - diagnostics: &mut Vec, - ) -> Option { - if value.visitable_type()? == DeserializableType::Str { - Deserializable::deserialize(value, name, diagnostics).map(Self::Qualifier) - } else { - Deserializable::deserialize(value, name, diagnostics).map(Self::Flag) - } - } + fn deserialize( + value:&impl biome_deserialize::DeserializableValue, + name:&str, + diagnostics:&mut Vec, + ) -> Option { + if value.visitable_type()? == DeserializableType::Str { + Deserializable::deserialize(value, name, diagnostics).map(Self::Qualifier) + } else { + Deserializable::deserialize(value, name, diagnostics).map(Self::Flag) + } + } } #[derive(Debug, Deserializable)] pub(crate) enum GlobalConfQualifier { - Off, - Readable, - Readonly, - Writable, - Writeable, + Off, + Readable, + Readonly, + Writable, + Writeable, } #[derive(Debug, Default, Deserializable)] #[deserializable(unknown_fields = "allow")] pub(crate) struct OverrideConfigData { - pub(crate) extends: ShorthandVec, - pub(crate) globals: Globals, - /// The glob patterns for excluded files. - pub(crate) excluded_files: ShorthandVec, - /// The glob patterns for target files. - pub(crate) files: ShorthandVec, - pub(crate) rules: Rules, + pub(crate) extends:ShorthandVec, + pub(crate) globals:Globals, + /// The glob patterns for excluded files. + pub(crate) excluded_files:ShorthandVec, + /// The glob patterns for target files. + pub(crate) files:ShorthandVec, + pub(crate) rules:Rules, } #[derive(Debug, Default)] pub(crate) struct ShorthandVec(Vec); impl Merge for ShorthandVec { - fn merge_with(&mut self, mut other: Self) { - self.0.append(&mut other.0); - } + fn merge_with(&mut self, mut other:Self) { self.0.append(&mut other.0); } } impl From for ShorthandVec { - fn from(value: T) -> Self { - Self(vec![value]) - } + fn from(value:T) -> Self { Self(vec![value]) } } impl Deref for ShorthandVec { - type Target = Vec; + type Target = Vec; - fn deref(&self) -> &Self::Target { - &self.0 - } + fn deref(&self) -> &Self::Target { &self.0 } } impl DerefMut for ShorthandVec { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } impl IntoIterator for ShorthandVec { - type Item = T; - - type IntoIter = vec::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} -impl Deserializable for ShorthandVec { - fn deserialize( - value: &impl DeserializableValue, - name: &str, - diagnostics: &mut Vec, - ) -> Option { - Some(ShorthandVec( - if value.visitable_type()? == DeserializableType::Array { - Deserializable::deserialize(value, name, diagnostics)? - } else { - Vec::from_iter([Deserializable::deserialize(value, name, diagnostics)?]) - }, - )) - } + type IntoIter = vec::IntoIter; + type Item = T; + + fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } +} +impl Deserializable for ShorthandVec { + fn deserialize( + value:&impl DeserializableValue, + name:&str, + diagnostics:&mut Vec, + ) -> Option { + Some(ShorthandVec(if value.visitable_type()? == DeserializableType::Array { + Deserializable::deserialize(value, name, diagnostics)? + } else { + Vec::from_iter([Deserializable::deserialize(value, name, diagnostics)?]) + })) + } } /// Model the possible shapes of an ESLint's rule configuration #[derive(Debug, Clone)] pub(crate) enum RuleConf { - // `{ rule: }` and `{ rule: [] }` - Severity(Severity), - // `{ rule: }` and `{ rule: [, ] }` - Option(Severity, T), - // `{ rule: }` and `{ rule: [, , ] }` - Options(Severity, T, U), - // `{ rule: }` and `{ rule: [, , , ...] }` - Spread(Severity, Vec), + // `{ rule: }` and `{ rule: [] }` + Severity(Severity), + // `{ rule: }` and `{ rule: [, ] }` + Option(Severity, T), + // `{ rule: }` and `{ rule: [, , ] }` + Options(Severity, T, U), + // `{ rule: }` and `{ rule: [, , , ...] }` + Spread(Severity, Vec), } impl RuleConf { - pub(crate) fn severity(&self) -> Severity { - match self { - Self::Severity(severity) => *severity, - Self::Option(severity, _) => *severity, - Self::Options(severity, _, _) => *severity, - Self::Spread(severity, _) => *severity, - } - } + pub(crate) fn severity(&self) -> Severity { + match self { + Self::Severity(severity) => *severity, + Self::Option(severity, _) => *severity, + Self::Options(severity, ..) => *severity, + Self::Spread(severity, _) => *severity, + } + } } impl RuleConf { - pub(crate) fn into_vec(self) -> Vec { - match self { - RuleConf::Severity(_) => vec![], - RuleConf::Option(_, value) | RuleConf::Options(_, value, _) => vec![value], - RuleConf::Spread(_, result) => result, - } - } -} -impl RuleConf { - pub(crate) fn option_or_default(self) -> T { - match self { - RuleConf::Severity(_) | RuleConf::Options(_, _, _) | RuleConf::Spread(_, _) => { - T::default() - } - - RuleConf::Option(_, option) => option, - } - } -} -impl Deserializable for RuleConf { - fn deserialize( - value: &impl biome_deserialize::DeserializableValue, - name: &str, - diagnostics: &mut Vec, - ) -> Option { - struct Visitor(PhantomData<(T, U)>); - - impl DeserializationVisitor - for Visitor - { - type Output = RuleConf; - - const EXPECTED_TYPE: DeserializableTypes = DeserializableTypes::ARRAY; - - fn visit_array( - self, - values: impl Iterator>, - range: TextRange, - _name: &str, - diagnostics: &mut Vec, - ) -> Option { - let mut values = values.flatten(); - - let Some(first_value) = values.next() else { - diagnostics.push( - DeserializationDiagnostic::new("A severity is expected.").with_range(range), - ); - - return None; - }; - - let severity = Deserializable::deserialize(&first_value, "", diagnostics)?; - - if TypeId::of::() == TypeId::of::<()>() { - return Some(RuleConf::Severity(severity)); - } - - let Some(second_value) = values.next() else { - return Some(RuleConf::Severity(severity)); - }; - - let Some(option) = T::deserialize(&second_value, "", diagnostics) else { - // Recover by ignoring the failed deserialization - return Some(RuleConf::Severity(severity)); - }; - - let Some(third_value) = values.next() else { - return Some(RuleConf::Option(severity, option)); - }; - - if TypeId::of::() != TypeId::of::<()>() { - if let Some(option2) = U::deserialize(&third_value, "", diagnostics) { - return Some(RuleConf::Options(severity, option, option2)); - } else { - // Recover by ignoring the failed deserialization - return Some(RuleConf::Option(severity, option)); - } - } - - let Some(option2) = T::deserialize(&third_value, "", diagnostics) else { - // Recover by ignoring the failed deserialization - return Some(RuleConf::Option(severity, option)); - }; - - let mut spread = Vec::new(); - - spread.push(option); - - spread.push(option2); - - spread.extend(values.filter_map(|val| T::deserialize(&val, "", diagnostics))); - - Some(RuleConf::Spread(severity, spread)) - } - } - - if matches!( - value.visitable_type()?, - DeserializableType::Number | DeserializableType::Str - ) { - Deserializable::deserialize(value, name, diagnostics).map(RuleConf::Severity) - } else { - value.deserialize(Visitor(PhantomData), name, diagnostics) - } - } + pub(crate) fn into_vec(self) -> Vec { + match self { + RuleConf::Severity(_) => vec![], + RuleConf::Option(_, value) | RuleConf::Options(_, value, _) => vec![value], + RuleConf::Spread(_, result) => result, + } + } +} +impl RuleConf { + pub(crate) fn option_or_default(self) -> T { + match self { + RuleConf::Severity(_) | RuleConf::Options(..) | RuleConf::Spread(..) => T::default(), + + RuleConf::Option(_, option) => option, + } + } +} +impl Deserializable for RuleConf { + fn deserialize( + value:&impl biome_deserialize::DeserializableValue, + name:&str, + diagnostics:&mut Vec, + ) -> Option { + struct Visitor(PhantomData<(T, U)>); + + impl DeserializationVisitor for Visitor { + type Output = RuleConf; + + const EXPECTED_TYPE:DeserializableTypes = DeserializableTypes::ARRAY; + + fn visit_array( + self, + values:impl Iterator>, + range:TextRange, + _name:&str, + diagnostics:&mut Vec, + ) -> Option { + let mut values = values.flatten(); + + let Some(first_value) = values.next() else { + diagnostics.push(DeserializationDiagnostic::new("A severity is expected.").with_range(range)); + + return None; + }; + + let severity = Deserializable::deserialize(&first_value, "", diagnostics)?; + + if TypeId::of::() == TypeId::of::<()>() { + return Some(RuleConf::Severity(severity)); + } + + let Some(second_value) = values.next() else { + return Some(RuleConf::Severity(severity)); + }; + + let Some(option) = T::deserialize(&second_value, "", diagnostics) else { + // Recover by ignoring the failed deserialization + return Some(RuleConf::Severity(severity)); + }; + + let Some(third_value) = values.next() else { + return Some(RuleConf::Option(severity, option)); + }; + + if TypeId::of::() != TypeId::of::<()>() { + if let Some(option2) = U::deserialize(&third_value, "", diagnostics) { + return Some(RuleConf::Options(severity, option, option2)); + } else { + // Recover by ignoring the failed deserialization + return Some(RuleConf::Option(severity, option)); + } + } + + let Some(option2) = T::deserialize(&third_value, "", diagnostics) else { + // Recover by ignoring the failed deserialization + return Some(RuleConf::Option(severity, option)); + }; + + let mut spread = Vec::new(); + + spread.push(option); + + spread.push(option2); + + spread.extend(values.filter_map(|val| T::deserialize(&val, "", diagnostics))); + + Some(RuleConf::Spread(severity, spread)) + } + } + + if matches!(value.visitable_type()?, DeserializableType::Number | DeserializableType::Str) { + Deserializable::deserialize(value, name, diagnostics).map(RuleConf::Severity) + } else { + value.deserialize(Visitor(PhantomData), name, diagnostics) + } + } } #[derive(Clone, Copy, Debug, Deserializable)] #[deserializable(try_from = "NumberOrString")] pub(crate) enum Severity { - Off, - Warn, - Error, + Off, + Warn, + Error, } impl TryFrom for Severity { - type Error = &'static str; - - fn try_from(value: NumberOrString) -> Result { - match value { - NumberOrString::Number(n) => match n { - 0 => Ok(Severity::Off), - 1 => Ok(Severity::Warn), - 2 => Ok(Severity::Error), - _ => Err("Severity should be 0, 1 or 2."), - }, - NumberOrString::String(s) => match s.as_ref() { - "off" => Ok(Severity::Off), - "warn" => Ok(Severity::Warn), - "error" => Ok(Severity::Error), - _ => Err("Severity should be 'off', 'warn' or 'error'."), - }, - } - } + type Error = &'static str; + + fn try_from(value:NumberOrString) -> Result { + match value { + NumberOrString::Number(n) => { + match n { + 0 => Ok(Severity::Off), + 1 => Ok(Severity::Warn), + 2 => Ok(Severity::Error), + _ => Err("Severity should be 0, 1 or 2."), + } + }, + NumberOrString::String(s) => { + match s.as_ref() { + "off" => Ok(Severity::Off), + "warn" => Ok(Severity::Warn), + "error" => Ok(Severity::Error), + _ => Err("Severity should be 'off', 'warn' or 'error'."), + } + }, + } + } } impl From for biome_configuration::RulePlainConfiguration { - fn from(value: Severity) -> biome_configuration::RulePlainConfiguration { - match value { - Severity::Off => biome_configuration::RulePlainConfiguration::Off, - Severity::Warn => biome_configuration::RulePlainConfiguration::Warn, - Severity::Error => biome_configuration::RulePlainConfiguration::Error, - } - } + fn from(value:Severity) -> biome_configuration::RulePlainConfiguration { + match value { + Severity::Off => biome_configuration::RulePlainConfiguration::Off, + Severity::Warn => biome_configuration::RulePlainConfiguration::Warn, + Severity::Error => biome_configuration::RulePlainConfiguration::Error, + } + } } #[derive(Debug, Clone)] enum NumberOrString { - Number(u64), - String(String), + Number(u64), + String(String), } impl Deserializable for NumberOrString { - fn deserialize( - value: &impl biome_deserialize::DeserializableValue, - name: &str, - diagnostics: &mut Vec, - ) -> Option { - Some(if value.visitable_type()? == DeserializableType::Str { - Self::String(Deserializable::deserialize(value, name, diagnostics)?) - } else { - Self::Number(Deserializable::deserialize(value, name, diagnostics)?) - }) - } + fn deserialize( + value:&impl biome_deserialize::DeserializableValue, + name:&str, + diagnostics:&mut Vec, + ) -> Option { + Some(if value.visitable_type()? == DeserializableType::Str { + Self::String(Deserializable::deserialize(value, name, diagnostics)?) + } else { + Self::Number(Deserializable::deserialize(value, name, diagnostics)?) + }) + } } #[derive(Debug, Default)] pub(crate) struct Rules( - // We use `IndexSet` instead of `HashSet` to preserve the order. - // Keeping the order is important because several ESLint rules can have - // the same equivalent Biome rule. - // The severity level of the last one is thus used. - pub(crate) IndexSet, + // We use `IndexSet` instead of `HashSet` to preserve the order. + // Keeping the order is important because several ESLint rules can have + // the same equivalent Biome rule. + // The severity level of the last one is thus used. + pub(crate) IndexSet, ); impl Merge for Rules { - fn merge_with(&mut self, other: Self) { - self.0.extend(other.0); - } + fn merge_with(&mut self, other:Self) { self.0.extend(other.0); } } impl Deref for Rules { - type Target = IndexSet; + type Target = IndexSet; - fn deref(&self) -> &Self::Target { - &self.0 - } + fn deref(&self) -> &Self::Target { &self.0 } } impl Deserializable for Rules { - fn deserialize( - value: &impl biome_deserialize::DeserializableValue, - name: &str, - diagnostics: &mut Vec, - ) -> Option { - struct Visitor; - - impl DeserializationVisitor for Visitor { - type Output = Rules; - - const EXPECTED_TYPE: DeserializableTypes = DeserializableTypes::MAP; - - fn visit_map( - self, - members: impl Iterator< - Item = Option<( - impl biome_deserialize::DeserializableValue, - impl biome_deserialize::DeserializableValue, - )>, - >, - _range: biome_rowan::TextRange, - name: &str, - diagnostics: &mut Vec, - ) -> Option { - use biome_deserialize::Text; - - let mut result = IndexSet::default(); - - for (key, value) in members.flatten() { - let Some(rule_name) = Text::deserialize(&key, "", diagnostics) else { - continue; - }; - - match rule_name.text() { - // Eslint rules with options that we handle - "no-console" => { - if let Some(conf) = RuleConf::deserialize(&value, name, diagnostics) { - result.insert(Rule::NoConsole(conf)); - } - } - "no-restricted-globals" => { - if let Some(conf) = RuleConf::deserialize(&value, name, diagnostics) { - result.insert(Rule::NoRestrictedGlobals(conf)); - } - } - // Eslint plugin rules with options that we handle - "jsx-a11y/aria-role" => { - if let Some(conf) = RuleConf::deserialize(&value, name, diagnostics) { - result.insert(Rule::Jsxa11yArioaRoles(conf)); - } - } - "@typescript-eslint/array-type" => { - if let Some(conf) = RuleConf::deserialize(&value, name, diagnostics) { - result.insert(Rule::TypeScriptArrayType(conf)); - } - } - "@typescript-eslint/explicit-member-accessibility" => { - if let Some(conf) = RuleConf::deserialize(&value, name, diagnostics) { - result.insert(Rule::TypeScriptExplicitMemberAccessibility(conf)); - } - } - "@typescript-eslint/naming-convention" => { - if let Some(conf) = RuleConf::deserialize(&value, name, diagnostics) { - result.insert(Rule::TypeScriptNamingConvention(conf)); - } - } - "unicorn/filename-case" => { - if let Some(conf) = RuleConf::deserialize(&value, name, diagnostics) { - result.insert(Rule::UnicornFilenameCase(conf)); - } - } - // Other rules - rule_name => { - if let Some(conf) = - RuleConf::<()>::deserialize(&value, name, diagnostics) - { - result.insert(Rule::Any( - Cow::Owned(rule_name.to_string()), - conf.severity(), - )); - } - } - } - } - - Some(Rules(result)) - } - } - - value.deserialize(Visitor, name, diagnostics) - } + fn deserialize( + value:&impl biome_deserialize::DeserializableValue, + name:&str, + diagnostics:&mut Vec, + ) -> Option { + struct Visitor; + + impl DeserializationVisitor for Visitor { + type Output = Rules; + + const EXPECTED_TYPE:DeserializableTypes = DeserializableTypes::MAP; + + fn visit_map( + self, + members:impl Iterator< + Item = Option<( + impl biome_deserialize::DeserializableValue, + impl biome_deserialize::DeserializableValue, + )>, + >, + _range:biome_rowan::TextRange, + name:&str, + diagnostics:&mut Vec, + ) -> Option { + use biome_deserialize::Text; + + let mut result = IndexSet::default(); + + for (key, value) in members.flatten() { + let Some(rule_name) = Text::deserialize(&key, "", diagnostics) else { + continue; + }; + + match rule_name.text() { + // Eslint rules with options that we handle + "no-console" => { + if let Some(conf) = RuleConf::deserialize(&value, name, diagnostics) { + result.insert(Rule::NoConsole(conf)); + } + }, + "no-restricted-globals" => { + if let Some(conf) = RuleConf::deserialize(&value, name, diagnostics) { + result.insert(Rule::NoRestrictedGlobals(conf)); + } + }, + // Eslint plugin rules with options that we handle + "jsx-a11y/aria-role" => { + if let Some(conf) = RuleConf::deserialize(&value, name, diagnostics) { + result.insert(Rule::Jsxa11yArioaRoles(conf)); + } + }, + "@typescript-eslint/array-type" => { + if let Some(conf) = RuleConf::deserialize(&value, name, diagnostics) { + result.insert(Rule::TypeScriptArrayType(conf)); + } + }, + "@typescript-eslint/explicit-member-accessibility" => { + if let Some(conf) = RuleConf::deserialize(&value, name, diagnostics) { + result.insert(Rule::TypeScriptExplicitMemberAccessibility(conf)); + } + }, + "@typescript-eslint/naming-convention" => { + if let Some(conf) = RuleConf::deserialize(&value, name, diagnostics) { + result.insert(Rule::TypeScriptNamingConvention(conf)); + } + }, + "unicorn/filename-case" => { + if let Some(conf) = RuleConf::deserialize(&value, name, diagnostics) { + result.insert(Rule::UnicornFilenameCase(conf)); + } + }, + // Other rules + rule_name => { + if let Some(conf) = RuleConf::<()>::deserialize(&value, name, diagnostics) { + result.insert(Rule::Any(Cow::Owned(rule_name.to_string()), conf.severity())); + } + }, + } + } + + Some(Rules(result)) + } + } + + value.deserialize(Visitor, name, diagnostics) + } } #[derive(Debug, Default, Deserializable)] pub struct NoConsoleOptions { - /// Allowed calls on the console object. - pub allow: Box<[Box]>, + /// Allowed calls on the console object. + pub allow:Box<[Box]>, } impl From for biome_js_analyze::lint::suspicious::no_console::NoConsoleOptions { - fn from(val: NoConsoleOptions) -> Self { - biome_js_analyze::lint::suspicious::no_console::NoConsoleOptions { allow: val.allow } - } + fn from(val:NoConsoleOptions) -> Self { + biome_js_analyze::lint::suspicious::no_console::NoConsoleOptions { allow:val.allow } + } } #[derive(Debug)] pub(crate) enum NoRestrictedGlobal { - Plain(String), - WithMessage(GlobalWithMessage), + Plain(String), + WithMessage(GlobalWithMessage), } impl NoRestrictedGlobal { - pub(crate) fn into_name(self) -> String { - match self { - NoRestrictedGlobal::Plain(name) => name, - NoRestrictedGlobal::WithMessage(named) => named.name, - } - } + pub(crate) fn into_name(self) -> String { + match self { + NoRestrictedGlobal::Plain(name) => name, + NoRestrictedGlobal::WithMessage(named) => named.name, + } + } } impl Deserializable for NoRestrictedGlobal { - fn deserialize( - value: &impl DeserializableValue, - name: &str, - diagnostics: &mut Vec, - ) -> Option { - if value.visitable_type()? == DeserializableType::Str { - Deserializable::deserialize(value, name, diagnostics).map(NoRestrictedGlobal::Plain) - } else { - Deserializable::deserialize(value, name, diagnostics) - .map(NoRestrictedGlobal::WithMessage) - } - } + fn deserialize( + value:&impl DeserializableValue, + name:&str, + diagnostics:&mut Vec, + ) -> Option { + if value.visitable_type()? == DeserializableType::Str { + Deserializable::deserialize(value, name, diagnostics).map(NoRestrictedGlobal::Plain) + } else { + Deserializable::deserialize(value, name, diagnostics).map(NoRestrictedGlobal::WithMessage) + } + } } #[derive(Debug, Default, Deserializable)] pub(crate) struct GlobalWithMessage { - name: String, - message: String, + name:String, + message:String, } #[derive(Debug)] pub(crate) enum Rule { - /// Any rule without its options. - Any(Cow<'static, str>, Severity), - // Eslint rules with its options - // We use this to configure equivalent Bione's rules. - NoConsole(RuleConf>), - NoRestrictedGlobals(RuleConf>), - // Eslint plugins - Jsxa11yArioaRoles(RuleConf>), - TypeScriptArrayType(RuleConf), - TypeScriptExplicitMemberAccessibility( - RuleConf, - ), - TypeScriptNamingConvention(RuleConf>), - UnicornFilenameCase(RuleConf), - // If you add new variants, don't forget to update [Rules::deserialize]. + /// Any rule without its options. + Any(Cow<'static, str>, Severity), + // Eslint rules with its options + // We use this to configure equivalent Bione's rules. + NoConsole(RuleConf>), + NoRestrictedGlobals(RuleConf>), + // Eslint plugins + Jsxa11yArioaRoles(RuleConf>), + TypeScriptArrayType(RuleConf), + TypeScriptExplicitMemberAccessibility(RuleConf), + TypeScriptNamingConvention(RuleConf>), + UnicornFilenameCase(RuleConf), + // If you add new variants, don't forget to update [Rules::deserialize]. } impl Rule { - pub(crate) fn name(&self) -> Cow<'static, str> { - match self { - Rule::Any(name, _) => name.clone(), - Rule::NoConsole(_) => Cow::Borrowed("no-console"), - Rule::NoRestrictedGlobals(_) => Cow::Borrowed("no-restricted-globals"), - Rule::Jsxa11yArioaRoles(_) => Cow::Borrowed("jsx-a11y/aria-role"), - Rule::TypeScriptArrayType(_) => Cow::Borrowed("@typescript-eslint/array-type"), - Rule::TypeScriptExplicitMemberAccessibility(_) => { - Cow::Borrowed("@typescript-eslint/explicit-member-accessibility") - } - - Rule::TypeScriptNamingConvention(_) => { - Cow::Borrowed("@typescript-eslint/naming-convention") - } - - Rule::UnicornFilenameCase(_) => Cow::Borrowed("unicorn/filename-case"), - } - } + pub(crate) fn name(&self) -> Cow<'static, str> { + match self { + Rule::Any(name, _) => name.clone(), + Rule::NoConsole(_) => Cow::Borrowed("no-console"), + Rule::NoRestrictedGlobals(_) => Cow::Borrowed("no-restricted-globals"), + Rule::Jsxa11yArioaRoles(_) => Cow::Borrowed("jsx-a11y/aria-role"), + Rule::TypeScriptArrayType(_) => Cow::Borrowed("@typescript-eslint/array-type"), + Rule::TypeScriptExplicitMemberAccessibility(_) => { + Cow::Borrowed("@typescript-eslint/explicit-member-accessibility") + }, + + Rule::TypeScriptNamingConvention(_) => Cow::Borrowed("@typescript-eslint/naming-convention"), + + Rule::UnicornFilenameCase(_) => Cow::Borrowed("unicorn/filename-case"), + } + } } impl Eq for Rule {} impl PartialEq for Rule { - fn eq(&self, other: &Self) -> bool { - self.name() == other.name() - } + fn eq(&self, other:&Self) -> bool { self.name() == other.name() } } impl Hash for Rule { - fn hash(&self, state: &mut H) { - self.name().hash(state); - } + fn hash(&self, state:&mut H) { self.name().hash(state); } } diff --git a/crates/biome_cli/Source/execute/migrate/eslint_jsxa11y.rs b/crates/biome_cli/Source/execute/migrate/eslint_jsxa11y.rs index f2bd1db8e0a8..d1ed9a999037 100644 --- a/crates/biome_cli/Source/execute/migrate/eslint_jsxa11y.rs +++ b/crates/biome_cli/Source/execute/migrate/eslint_jsxa11y.rs @@ -1,21 +1,22 @@ /// Configuration related to the /// [JSX A11y Eslint plugin](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y). /// -/// Also, the module includes implementation to convert rule options to Biome's rule options. +/// Also, the module includes implementation to convert rule options to Biome's +/// rule options. use biome_deserialize_macros::Deserializable; use biome_js_analyze::lint::a11y::use_valid_aria_role; #[derive(Debug, Default, Deserializable)] pub(crate) struct AriaRoleOptions { - allowed_invalid_roles: Box<[Box]>, - #[deserializable(rename = "ignoreNonDOM")] - ignore_non_dom: bool, + allowed_invalid_roles:Box<[Box]>, + #[deserializable(rename = "ignoreNonDOM")] + ignore_non_dom:bool, } impl From for use_valid_aria_role::ValidAriaRoleOptions { - fn from(val: AriaRoleOptions) -> Self { - use_valid_aria_role::ValidAriaRoleOptions { - allow_invalid_roles: val.allowed_invalid_roles, - ignore_non_dom: val.ignore_non_dom, - } - } + fn from(val:AriaRoleOptions) -> Self { + use_valid_aria_role::ValidAriaRoleOptions { + allow_invalid_roles:val.allowed_invalid_roles, + ignore_non_dom:val.ignore_non_dom, + } + } } diff --git a/crates/biome_cli/Source/execute/migrate/eslint_to_biome.rs b/crates/biome_cli/Source/execute/migrate/eslint_to_biome.rs index ea99a8f76fa3..18520c3a1a6b 100644 --- a/crates/biome_cli/Source/execute/migrate/eslint_to_biome.rs +++ b/crates/biome_cli/Source/execute/migrate/eslint_to_biome.rs @@ -4,517 +4,461 @@ use biome_js_analyze::lint::style::no_restricted_globals; use super::{eslint_any_rule_to_biome::migrate_eslint_any_rule, eslint_eslint, eslint_typescript}; -/// This modules includes implementations for converting an ESLint config to a Biome config. +/// This modules includes implementations for converting an ESLint config to a +/// Biome config. /// /// The conversion relies on: /// - the generated [super::eslint_any_rule_to_biome::migrate_eslint_any_rule] -/// module that relies on Biome's rule metadata to determine -/// the equivalent Biome's rule of an Eslint rule -/// - hand-written handling of Biome rules that have options in the current module. +/// module that relies on Biome's rule metadata to determine the equivalent +/// Biome's rule of an Eslint rule +/// - hand-written handling of Biome rules that have options in the current +/// module. #[derive(Clone, Debug, Default)] pub(crate) struct MigrationOptions { - /// Migrate inspired rules from eslint and its plugins? - pub(crate) include_inspired: bool, - /// Migrate nursery rules from eslint and its plugins? - pub(crate) include_nursery: bool, + /// Migrate inspired rules from eslint and its plugins? + pub(crate) include_inspired:bool, + /// Migrate nursery rules from eslint and its plugins? + pub(crate) include_nursery:bool, } #[derive(Debug, Default)] pub(crate) struct MigrationResults { - // Contains inspired rules that were not migrated because `include_inspired` is disabled - pub(crate) has_inspired_rules: bool, + // Contains inspired rules that were not migrated because `include_inspired` is disabled + pub(crate) has_inspired_rules:bool, } impl eslint_eslint::AnyConfigData { - pub(crate) fn into_biome_config( - self, - options: &MigrationOptions, - ) -> (biome_config::PartialConfiguration, MigrationResults) { - match self { - Self::Flat(config) => config.into_biome_config(options), - Self::Legacy(config) => config.into_biome_config(options), - } - } + pub(crate) fn into_biome_config( + self, + options:&MigrationOptions, + ) -> (biome_config::PartialConfiguration, MigrationResults) { + match self { + Self::Flat(config) => config.into_biome_config(options), + Self::Legacy(config) => config.into_biome_config(options), + } + } } impl eslint_eslint::FlatConfigData { - pub(crate) fn into_biome_config( - self, - options: &MigrationOptions, - ) -> (biome_config::PartialConfiguration, MigrationResults) { - let mut results = MigrationResults::default(); - - let mut biome_config = biome_config::PartialConfiguration::default(); - - let mut linter = biome_config::PartialLinterConfiguration::default(); - - let mut overrides = biome_config::Overrides::default(); - - let global_config_object = if self.0.len() == 1 { - // If there is a single config object, then we use it as the global config - self.0.into_iter().next().unwrap() - } else { - let mut global_config_object = eslint_eslint::FlatConfigObject::default(); - - for flat_config_object in self.0 { - if flat_config_object.is_global_ignores() { - global_config_object - .ignores - .extend(flat_config_object.ignores); - } else if flat_config_object.is_global_config() { - global_config_object.merge_with(flat_config_object); - } else { - let mut override_pat = biome_config::OverridePattern::default(); - - if let Some(language_options) = flat_config_object.language_options { - let globals = language_options.globals.enabled().collect::(); - - let js_config = biome_config::PartialJavascriptConfiguration { - globals: Some(globals), - ..Default::default() - }; - - override_pat.javascript = Some(js_config) - } - - if !flat_config_object.ignores.is_empty() { - override_pat.ignore = - Some(flat_config_object.ignores.into_iter().collect()); - } - - if !flat_config_object.files.is_empty() { - override_pat.include = Some(flat_config_object.files.into_iter().collect()); - } - - if let Some(rules) = flat_config_object.rules { - if !rules.is_empty() { - override_pat.linter = Some(biome_config::OverrideLinterConfiguration { - rules: Some(rules.into_biome_rules(options, &mut results)), - ..Default::default() - }); - } - } - - overrides.0.push(override_pat); - } - } - - if !overrides.0.is_empty() { - biome_config.overrides = Some(overrides); - } - - global_config_object - }; - - let mut rules = if let Some(rules) = global_config_object.rules { - rules.into_biome_rules(options, &mut results) - } else { - biome_config::Rules::default() - }; - - if let Some(language_options) = global_config_object.language_options { - let globals = language_options.globals.enabled().collect::(); - - let js_config = biome_config::PartialJavascriptConfiguration { - globals: Some(globals), - ..Default::default() - }; - - biome_config.javascript = Some(js_config) - } - - rules.recommended = Some(false); - - linter.rules = Some(rules); - - if !global_config_object.ignores.is_empty() { - linter.ignore = Some(global_config_object.ignores.into_iter().collect()); - } - - if !global_config_object.files.is_empty() { - linter.include = Some(global_config_object.files.into_iter().collect()); - } - - biome_config.linter = Some(linter); - (biome_config, results) - } + pub(crate) fn into_biome_config( + self, + options:&MigrationOptions, + ) -> (biome_config::PartialConfiguration, MigrationResults) { + let mut results = MigrationResults::default(); + + let mut biome_config = biome_config::PartialConfiguration::default(); + + let mut linter = biome_config::PartialLinterConfiguration::default(); + + let mut overrides = biome_config::Overrides::default(); + + let global_config_object = if self.0.len() == 1 { + // If there is a single config object, then we use it as the global config + self.0.into_iter().next().unwrap() + } else { + let mut global_config_object = eslint_eslint::FlatConfigObject::default(); + + for flat_config_object in self.0 { + if flat_config_object.is_global_ignores() { + global_config_object.ignores.extend(flat_config_object.ignores); + } else if flat_config_object.is_global_config() { + global_config_object.merge_with(flat_config_object); + } else { + let mut override_pat = biome_config::OverridePattern::default(); + + if let Some(language_options) = flat_config_object.language_options { + let globals = language_options.globals.enabled().collect::(); + + let js_config = biome_config::PartialJavascriptConfiguration { + globals:Some(globals), + ..Default::default() + }; + + override_pat.javascript = Some(js_config) + } + + if !flat_config_object.ignores.is_empty() { + override_pat.ignore = Some(flat_config_object.ignores.into_iter().collect()); + } + + if !flat_config_object.files.is_empty() { + override_pat.include = Some(flat_config_object.files.into_iter().collect()); + } + + if let Some(rules) = flat_config_object.rules { + if !rules.is_empty() { + override_pat.linter = Some(biome_config::OverrideLinterConfiguration { + rules:Some(rules.into_biome_rules(options, &mut results)), + ..Default::default() + }); + } + } + + overrides.0.push(override_pat); + } + } + + if !overrides.0.is_empty() { + biome_config.overrides = Some(overrides); + } + + global_config_object + }; + + let mut rules = if let Some(rules) = global_config_object.rules { + rules.into_biome_rules(options, &mut results) + } else { + biome_config::Rules::default() + }; + + if let Some(language_options) = global_config_object.language_options { + let globals = language_options.globals.enabled().collect::(); + + let js_config = + biome_config::PartialJavascriptConfiguration { globals:Some(globals), ..Default::default() }; + + biome_config.javascript = Some(js_config) + } + + rules.recommended = Some(false); + + linter.rules = Some(rules); + + if !global_config_object.ignores.is_empty() { + linter.ignore = Some(global_config_object.ignores.into_iter().collect()); + } + + if !global_config_object.files.is_empty() { + linter.include = Some(global_config_object.files.into_iter().collect()); + } + + biome_config.linter = Some(linter); + (biome_config, results) + } } impl eslint_eslint::LegacyConfigData { - pub(crate) fn into_biome_config( - self, - options: &MigrationOptions, - ) -> (biome_config::PartialConfiguration, MigrationResults) { - let mut results = MigrationResults::default(); + pub(crate) fn into_biome_config( + self, + options:&MigrationOptions, + ) -> (biome_config::PartialConfiguration, MigrationResults) { + let mut results = MigrationResults::default(); - let mut biome_config = biome_config::PartialConfiguration::default(); + let mut biome_config = biome_config::PartialConfiguration::default(); - if !self.globals.is_empty() { - let globals = self.globals.enabled().collect::(); + if !self.globals.is_empty() { + let globals = self.globals.enabled().collect::(); - let js_config = biome_config::PartialJavascriptConfiguration { - globals: Some(globals), - ..Default::default() - }; + let js_config = + biome_config::PartialJavascriptConfiguration { globals:Some(globals), ..Default::default() }; - biome_config.javascript = Some(js_config) - } + biome_config.javascript = Some(js_config) + } - let mut linter = biome_config::PartialLinterConfiguration::default(); + let mut linter = biome_config::PartialLinterConfiguration::default(); - let mut rules = self.rules.into_biome_rules(options, &mut results); + let mut rules = self.rules.into_biome_rules(options, &mut results); - rules.recommended = Some(false); + rules.recommended = Some(false); - linter.rules = Some(rules); + linter.rules = Some(rules); - if !self.ignore_patterns.is_empty() { - let ignore = self - .ignore_patterns - .into_iter() - .map(|p| p.0) - .collect::(); + if !self.ignore_patterns.is_empty() { + let ignore = self.ignore_patterns.into_iter().map(|p| p.0).collect::(); - linter.ignore = Some(ignore); - } + linter.ignore = Some(ignore); + } - if !self.overrides.is_empty() { - let mut overrides = biome_config::Overrides::default(); + if !self.overrides.is_empty() { + let mut overrides = biome_config::Overrides::default(); - for override_elt in self.overrides { - let mut override_pattern = biome_config::OverridePattern::default(); + for override_elt in self.overrides { + let mut override_pattern = biome_config::OverridePattern::default(); - if !override_elt.globals.is_empty() { - let globals = override_elt.globals.enabled().collect::(); + if !override_elt.globals.is_empty() { + let globals = override_elt.globals.enabled().collect::(); - let js_config = biome_config::PartialJavascriptConfiguration { - globals: Some(globals), - ..Default::default() - }; + let js_config = + biome_config::PartialJavascriptConfiguration { globals:Some(globals), ..Default::default() }; - override_pattern.javascript = Some(js_config) - } + override_pattern.javascript = Some(js_config) + } - if !override_elt.excluded_files.is_empty() { - override_pattern.ignore = - Some(override_elt.excluded_files.into_iter().collect()); - } + if !override_elt.excluded_files.is_empty() { + override_pattern.ignore = Some(override_elt.excluded_files.into_iter().collect()); + } - if !override_elt.files.is_empty() { - override_pattern.include = Some(override_elt.files.into_iter().collect()); - } + if !override_elt.files.is_empty() { + override_pattern.include = Some(override_elt.files.into_iter().collect()); + } - if !override_elt.rules.is_empty() { - override_pattern.linter = Some(biome_config::OverrideLinterConfiguration { - rules: Some(override_elt.rules.into_biome_rules(options, &mut results)), - ..Default::default() - }); - } + if !override_elt.rules.is_empty() { + override_pattern.linter = Some(biome_config::OverrideLinterConfiguration { + rules:Some(override_elt.rules.into_biome_rules(options, &mut results)), + ..Default::default() + }); + } - overrides.0.push(override_pattern); - } + overrides.0.push(override_pattern); + } - biome_config.overrides = Some(overrides); - } + biome_config.overrides = Some(overrides); + } - biome_config.linter = Some(linter); - (biome_config, results) - } + biome_config.linter = Some(linter); + (biome_config, results) + } } impl eslint_eslint::Rules { - pub(crate) fn into_biome_rules( - self, - options: &MigrationOptions, - results: &mut MigrationResults, - ) -> biome_config::Rules { - let mut rules = biome_config::Rules::default(); - - for eslint_rule in self.0 { - migrate_eslint_rule(&mut rules, eslint_rule, options, results); - } - - rules - } + pub(crate) fn into_biome_rules( + self, + options:&MigrationOptions, + results:&mut MigrationResults, + ) -> biome_config::Rules { + let mut rules = biome_config::Rules::default(); + + for eslint_rule in self.0 { + migrate_eslint_rule(&mut rules, eslint_rule, options, results); + } + + rules + } } /// Look for an equivalent Biome rule for ESLint `rule`, /// and then mutate `rules` if a equivalent rule is found. /// Also, takes care of Biome's rules with options. fn migrate_eslint_rule( - rules: &mut biome_config::Rules, - rule: eslint_eslint::Rule, - opts: &MigrationOptions, - results: &mut MigrationResults, + rules:&mut biome_config::Rules, + rule:eslint_eslint::Rule, + opts:&MigrationOptions, + results:&mut MigrationResults, ) { - let name = rule.name(); - - match rule { - eslint_eslint::Rule::Any(name, severity) => { - let _ = migrate_eslint_any_rule(rules, &name, severity, opts, results); - } - - eslint_eslint::Rule::NoConsole(conf) => { - if migrate_eslint_any_rule(rules, &name, conf.severity(), opts, results) { - if let eslint_eslint::RuleConf::Option(severity, rule_options) = conf { - let group = rules.suspicious.get_or_insert_with(Default::default); - - group.no_console = Some(biome_config::RuleFixConfiguration::WithOptions( - biome_config::RuleWithFixOptions { - level: severity.into(), - fix: None, - options: Box::new((*rule_options).into()), - }, - )); - } - } - } - - eslint_eslint::Rule::NoRestrictedGlobals(conf) => { - if migrate_eslint_any_rule(rules, &name, conf.severity(), opts, results) { - let severity = conf.severity(); - - let globals = conf - .into_vec() - .into_iter() - .map(|g| g.into_name().into_boxed_str()); - - let group = rules.style.get_or_insert_with(Default::default); - - group.no_restricted_globals = Some(biome_config::RuleConfiguration::WithOptions( - biome_config::RuleWithOptions { - level: severity.into(), - options: Box::new(no_restricted_globals::RestrictedGlobalsOptions { - denied_globals: globals.collect::>().into_boxed_slice(), - }), - }, - )); - } - } - - eslint_eslint::Rule::Jsxa11yArioaRoles(conf) => { - if migrate_eslint_any_rule(rules, &name, conf.severity(), opts, results) { - if let eslint_eslint::RuleConf::Option(severity, rule_options) = conf { - let group = rules.a11y.get_or_insert_with(Default::default); - - group.use_valid_aria_role = - Some(biome_config::RuleFixConfiguration::WithOptions( - biome_config::RuleWithFixOptions { - level: severity.into(), - fix: None, - options: Box::new((*rule_options).into()), - }, - )); - } - } - } - - eslint_eslint::Rule::TypeScriptArrayType(conf) => { - if migrate_eslint_any_rule(rules, &name, conf.severity(), opts, results) { - if let eslint_eslint::RuleConf::Option(severity, rule_options) = conf { - let group = rules.style.get_or_insert_with(Default::default); - - group.use_consistent_array_type = - Some(biome_config::RuleFixConfiguration::WithOptions( - biome_config::RuleWithFixOptions { - level: severity.into(), - fix: None, - options: rule_options.into(), - }, - )); - } - } - } - - eslint_eslint::Rule::TypeScriptExplicitMemberAccessibility(conf) => { - if migrate_eslint_any_rule(rules, &name, conf.severity(), opts, results) { - if let eslint_eslint::RuleConf::Option(severity, rule_options) = conf { - let group = rules.nursery.get_or_insert_with(Default::default); - - group.use_consistent_member_accessibility = - Some(biome_config::RuleConfiguration::WithOptions( - biome_config::RuleWithOptions { - level: severity.into(), - options: rule_options.into(), - }, - )); - } - } - } - - eslint_eslint::Rule::TypeScriptNamingConvention(conf) => { - if migrate_eslint_any_rule(rules, &name, conf.severity(), opts, results) { - let severity = conf.severity(); - - let options = eslint_typescript::NamingConventionOptions::new( - conf.into_vec().into_iter().map(|v| *v), - ); - - let group = rules.style.get_or_insert_with(Default::default); - - group.use_naming_convention = - Some(biome_config::RuleFixConfiguration::WithOptions( - biome_config::RuleWithFixOptions { - level: severity.into(), - fix: None, - options: options.into(), - }, - )); - } - } - - eslint_eslint::Rule::UnicornFilenameCase(conf) => { - if migrate_eslint_any_rule(rules, &name, conf.severity(), opts, results) { - let group = rules.style.get_or_insert_with(Default::default); - - group.use_filenaming_convention = Some( - biome_config::RuleConfiguration::WithOptions(biome_config::RuleWithOptions { - level: conf.severity().into(), - options: Box::new(conf.option_or_default().into()), - }), - ); - } - } - } + let name = rule.name(); + + match rule { + eslint_eslint::Rule::Any(name, severity) => { + let _ = migrate_eslint_any_rule(rules, &name, severity, opts, results); + }, + + eslint_eslint::Rule::NoConsole(conf) => { + if migrate_eslint_any_rule(rules, &name, conf.severity(), opts, results) { + if let eslint_eslint::RuleConf::Option(severity, rule_options) = conf { + let group = rules.suspicious.get_or_insert_with(Default::default); + + group.no_console = Some(biome_config::RuleFixConfiguration::WithOptions( + biome_config::RuleWithFixOptions { + level:severity.into(), + fix:None, + options:Box::new((*rule_options).into()), + }, + )); + } + } + }, + + eslint_eslint::Rule::NoRestrictedGlobals(conf) => { + if migrate_eslint_any_rule(rules, &name, conf.severity(), opts, results) { + let severity = conf.severity(); + + let globals = conf.into_vec().into_iter().map(|g| g.into_name().into_boxed_str()); + + let group = rules.style.get_or_insert_with(Default::default); + + group.no_restricted_globals = + Some(biome_config::RuleConfiguration::WithOptions(biome_config::RuleWithOptions { + level:severity.into(), + options:Box::new(no_restricted_globals::RestrictedGlobalsOptions { + denied_globals:globals.collect::>().into_boxed_slice(), + }), + })); + } + }, + + eslint_eslint::Rule::Jsxa11yArioaRoles(conf) => { + if migrate_eslint_any_rule(rules, &name, conf.severity(), opts, results) { + if let eslint_eslint::RuleConf::Option(severity, rule_options) = conf { + let group = rules.a11y.get_or_insert_with(Default::default); + + group.use_valid_aria_role = Some(biome_config::RuleFixConfiguration::WithOptions( + biome_config::RuleWithFixOptions { + level:severity.into(), + fix:None, + options:Box::new((*rule_options).into()), + }, + )); + } + } + }, + + eslint_eslint::Rule::TypeScriptArrayType(conf) => { + if migrate_eslint_any_rule(rules, &name, conf.severity(), opts, results) { + if let eslint_eslint::RuleConf::Option(severity, rule_options) = conf { + let group = rules.style.get_or_insert_with(Default::default); + + group.use_consistent_array_type = Some(biome_config::RuleFixConfiguration::WithOptions( + biome_config::RuleWithFixOptions { + level:severity.into(), + fix:None, + options:rule_options.into(), + }, + )); + } + } + }, + + eslint_eslint::Rule::TypeScriptExplicitMemberAccessibility(conf) => { + if migrate_eslint_any_rule(rules, &name, conf.severity(), opts, results) { + if let eslint_eslint::RuleConf::Option(severity, rule_options) = conf { + let group = rules.nursery.get_or_insert_with(Default::default); + + group.use_consistent_member_accessibility = + Some(biome_config::RuleConfiguration::WithOptions(biome_config::RuleWithOptions { + level:severity.into(), + options:rule_options.into(), + })); + } + } + }, + + eslint_eslint::Rule::TypeScriptNamingConvention(conf) => { + if migrate_eslint_any_rule(rules, &name, conf.severity(), opts, results) { + let severity = conf.severity(); + + let options = eslint_typescript::NamingConventionOptions::new(conf.into_vec().into_iter().map(|v| *v)); + + let group = rules.style.get_or_insert_with(Default::default); + + group.use_naming_convention = Some(biome_config::RuleFixConfiguration::WithOptions( + biome_config::RuleWithFixOptions { level:severity.into(), fix:None, options:options.into() }, + )); + } + }, + + eslint_eslint::Rule::UnicornFilenameCase(conf) => { + if migrate_eslint_any_rule(rules, &name, conf.severity(), opts, results) { + let group = rules.style.get_or_insert_with(Default::default); + + group.use_filenaming_convention = + Some(biome_config::RuleConfiguration::WithOptions(biome_config::RuleWithOptions { + level:conf.severity().into(), + options:Box::new(conf.option_or_default().into()), + })); + } + }, + } } #[cfg(test)] mod tests { - use super::*; - - use eslint_eslint::*; - - use std::borrow::Cow; - - #[test] - fn flat_config_single_config_object() { - let flat_config = FlatConfigData(vec![FlatConfigObject { - files: vec!["*.js".to_string()], - ignores: vec!["*.test.js".to_string()], - language_options: None, - rules: Some(Rules( - [Rule::Any(Cow::Borrowed("eqeqeq"), Severity::Error)] - .into_iter() - .collect(), - )), - }]); - - let (biome_config, _) = flat_config.into_biome_config(&MigrationOptions::default()); - - assert!(biome_config.files.is_none()); - - assert!(biome_config.overrides.is_none()); - - assert!(biome_config.formatter.is_none()); - - assert!(biome_config.organize_imports.is_none()); - - let linter = biome_config.linter.unwrap(); - - assert_eq!( - linter.include, - Some(["*.js".to_string()].into_iter().collect()) - ); - - assert_eq!( - linter.ignore, - Some(["*.test.js".to_string()].into_iter().collect()) - ); - - assert!(linter.rules.is_some()); - } - - #[test] - fn flat_config_multiple_config_object() { - let flat_config = FlatConfigData(vec![ - FlatConfigObject { - files: vec![], - ignores: vec!["*.test.js".to_string()], - language_options: None, - rules: None, - }, - FlatConfigObject { - files: vec![], - ignores: vec![], - language_options: None, - rules: Some(Rules( - [Rule::Any(Cow::Borrowed("eqeqeq"), Severity::Error)] - .into_iter() - .collect(), - )), - }, - FlatConfigObject { - files: vec![], - ignores: vec!["*.spec.js".to_string()], - language_options: None, - rules: None, - }, - FlatConfigObject { - files: vec!["*.ts".to_string()], - ignores: vec![], - language_options: None, - rules: Some(Rules( - [Rule::Any(Cow::Borrowed("eqeqeq"), Severity::Off)] - .into_iter() - .collect(), - )), - }, - ]); - - let (biome_config, _) = flat_config.into_biome_config(&MigrationOptions::default()); - - assert!(biome_config.files.is_none()); - - assert!(biome_config.formatter.is_none()); - - assert!(biome_config.organize_imports.is_none()); - - let linter = biome_config.linter.unwrap(); - - assert!(linter.include.is_none()); - - assert_eq!( - linter.ignore, - Some( - ["*.test.js".to_string(), "*.spec.js".to_string()] - .into_iter() - .collect() - ) - ); - - assert_eq!( - linter.rules.unwrap().suspicious.unwrap().no_double_equals, - Some(biome_config::RuleFixConfiguration::Plain( - biome_config::RulePlainConfiguration::Error - )) - ); - - let overrides = biome_config.overrides.unwrap(); - - assert_eq!(overrides.0.len(), 1); - - let override0 = overrides.0.into_iter().next().unwrap(); - - assert_eq!( - override0.include, - Some(["*.ts".to_string()].into_iter().collect()) - ); - - assert!(override0.ignore.is_none()); - - assert_eq!( - override0 - .linter - .unwrap() - .rules - .unwrap() - .suspicious - .unwrap() - .no_double_equals, - Some(biome_config::RuleFixConfiguration::Plain( - biome_config::RulePlainConfiguration::Off - )) - ); - } + use std::borrow::Cow; + + use eslint_eslint::*; + + use super::*; + + #[test] + fn flat_config_single_config_object() { + let flat_config = FlatConfigData(vec![FlatConfigObject { + files:vec!["*.js".to_string()], + ignores:vec!["*.test.js".to_string()], + language_options:None, + rules:Some(Rules( + [Rule::Any(Cow::Borrowed("eqeqeq"), Severity::Error)].into_iter().collect(), + )), + }]); + + let (biome_config, _) = flat_config.into_biome_config(&MigrationOptions::default()); + + assert!(biome_config.files.is_none()); + + assert!(biome_config.overrides.is_none()); + + assert!(biome_config.formatter.is_none()); + + assert!(biome_config.organize_imports.is_none()); + + let linter = biome_config.linter.unwrap(); + + assert_eq!(linter.include, Some(["*.js".to_string()].into_iter().collect())); + + assert_eq!(linter.ignore, Some(["*.test.js".to_string()].into_iter().collect())); + + assert!(linter.rules.is_some()); + } + + #[test] + fn flat_config_multiple_config_object() { + let flat_config = FlatConfigData(vec![ + FlatConfigObject { + files:vec![], + ignores:vec!["*.test.js".to_string()], + language_options:None, + rules:None, + }, + FlatConfigObject { + files:vec![], + ignores:vec![], + language_options:None, + rules:Some(Rules( + [Rule::Any(Cow::Borrowed("eqeqeq"), Severity::Error)].into_iter().collect(), + )), + }, + FlatConfigObject { + files:vec![], + ignores:vec!["*.spec.js".to_string()], + language_options:None, + rules:None, + }, + FlatConfigObject { + files:vec!["*.ts".to_string()], + ignores:vec![], + language_options:None, + rules:Some(Rules([Rule::Any(Cow::Borrowed("eqeqeq"), Severity::Off)].into_iter().collect())), + }, + ]); + + let (biome_config, _) = flat_config.into_biome_config(&MigrationOptions::default()); + + assert!(biome_config.files.is_none()); + + assert!(biome_config.formatter.is_none()); + + assert!(biome_config.organize_imports.is_none()); + + let linter = biome_config.linter.unwrap(); + + assert!(linter.include.is_none()); + + assert_eq!( + linter.ignore, + Some(["*.test.js".to_string(), "*.spec.js".to_string()].into_iter().collect()) + ); + + assert_eq!( + linter.rules.unwrap().suspicious.unwrap().no_double_equals, + Some(biome_config::RuleFixConfiguration::Plain( + biome_config::RulePlainConfiguration::Error + )) + ); + + let overrides = biome_config.overrides.unwrap(); + + assert_eq!(overrides.0.len(), 1); + + let override0 = overrides.0.into_iter().next().unwrap(); + + assert_eq!(override0.include, Some(["*.ts".to_string()].into_iter().collect())); + + assert!(override0.ignore.is_none()); + + assert_eq!( + override0.linter.unwrap().rules.unwrap().suspicious.unwrap().no_double_equals, + Some(biome_config::RuleFixConfiguration::Plain( + biome_config::RulePlainConfiguration::Off + )) + ); + } } diff --git a/crates/biome_cli/Source/execute/migrate/eslint_typescript.rs b/crates/biome_cli/Source/execute/migrate/eslint_typescript.rs index ace79054b102..050ba8b980dd 100644 --- a/crates/biome_cli/Source/execute/migrate/eslint_typescript.rs +++ b/crates/biome_cli/Source/execute/migrate/eslint_typescript.rs @@ -2,701 +2,659 @@ use std::{cmp::Ordering, str::FromStr}; /// Configuration related to [TypeScript Eslint](https://typescript-eslint.io/). /// -/// Also, the module includes implementation to convert rule options to Biome's rule options. +/// Also, the module includes implementation to convert rule options to Biome's +/// rule options. use biome_deserialize::Deserializable; use biome_deserialize_macros::Deserializable; use biome_js_analyze::{ - lint::nursery::use_consistent_member_accessibility, - lint::style::{use_consistent_array_type, use_naming_convention}, - utils::restricted_regex::RestrictedRegex, + lint::{ + nursery::use_consistent_member_accessibility, + style::{use_consistent_array_type, use_naming_convention}, + }, + utils::restricted_regex::RestrictedRegex, }; use super::eslint_eslint; #[derive(Debug, Default, Deserializable)] pub(crate) struct ArrayTypeOptions { - default: ArrayType, - readonly: Option, + default:ArrayType, + readonly:Option, } impl From for use_consistent_array_type::ConsistentArrayTypeOptions { - fn from(val: ArrayTypeOptions) -> Self { - use_consistent_array_type::ConsistentArrayTypeOptions { - syntax: val.default.into(), - } - } + fn from(val:ArrayTypeOptions) -> Self { + use_consistent_array_type::ConsistentArrayTypeOptions { syntax:val.default.into() } + } } #[derive(Debug, Default, Deserializable)] pub(crate) enum ArrayType { - #[default] - Array, - #[deserializable(rename = "array-simple")] - ArraySimple, - Generic, + #[default] + Array, + #[deserializable(rename = "array-simple")] + ArraySimple, + Generic, } impl From for use_consistent_array_type::ConsistentArrayType { - fn from(val: ArrayType) -> Self { - match val { - // NOTE: we translate `array-simple` to `array`. - ArrayType::Array | ArrayType::ArraySimple => { - use_consistent_array_type::ConsistentArrayType::Shorthand - } - - ArrayType::Generic => use_consistent_array_type::ConsistentArrayType::Generic, - } - } + fn from(val:ArrayType) -> Self { + match val { + // NOTE: we translate `array-simple` to `array`. + ArrayType::Array | ArrayType::ArraySimple => use_consistent_array_type::ConsistentArrayType::Shorthand, + + ArrayType::Generic => use_consistent_array_type::ConsistentArrayType::Generic, + } + } } #[derive(Debug, Default, Deserializable)] #[deserializable(unknown_fields = "allow")] pub(crate) struct ExplicitMemberAccessibilityOptions { - accessibility: Option, + accessibility:Option, } impl From - for use_consistent_member_accessibility::ConsistentMemberAccessibilityOptions + for use_consistent_member_accessibility::ConsistentMemberAccessibilityOptions { - fn from(value: ExplicitMemberAccessibilityOptions) -> Self { - use_consistent_member_accessibility::ConsistentMemberAccessibilityOptions { - accessibility: value.accessibility.map(|x| x.into()).unwrap_or_default(), - } - } + fn from(value:ExplicitMemberAccessibilityOptions) -> Self { + use_consistent_member_accessibility::ConsistentMemberAccessibilityOptions { + accessibility:value.accessibility.map(|x| x.into()).unwrap_or_default(), + } + } } #[derive(Clone, Copy, Debug, Default, Deserializable)] pub(crate) enum AccessibilityLevel { - #[default] - #[deserializable(rename = "no-public")] - NoPublic, - Explicit, - None, + #[default] + #[deserializable(rename = "no-public")] + NoPublic, + Explicit, + None, } impl From for use_consistent_member_accessibility::Accessibility { - fn from(value: AccessibilityLevel) -> Self { - match value { - AccessibilityLevel::NoPublic => Self::NoPublic, - AccessibilityLevel::Explicit => Self::Explicit, - AccessibilityLevel::None => Self::None, - } - } + fn from(value:AccessibilityLevel) -> Self { + match value { + AccessibilityLevel::NoPublic => Self::NoPublic, + AccessibilityLevel::Explicit => Self::Explicit, + AccessibilityLevel::None => Self::None, + } + } } #[derive(Debug)] pub(crate) struct NamingConventionOptions(Vec); impl NamingConventionOptions { - pub(crate) fn new(overrides: impl IntoIterator) -> Self { - let mut inner: Vec<_> = overrides.into_iter().collect(); - // Order of the least general selection to the most geenral selection - inner.sort_by(|a, b| a.precedence(b)); + pub(crate) fn new(overrides:impl IntoIterator) -> Self { + let mut inner:Vec<_> = overrides.into_iter().collect(); + // Order of the least general selection to the most geenral selection + inner.sort_by(|a, b| a.precedence(b)); - Self(inner) - } + Self(inner) + } } impl From for use_naming_convention::NamingConventionOptions { - fn from(val: NamingConventionOptions) -> Self { - let mut conventions = Vec::new(); - - for selection in val.0 { - if selection.types.is_some() || selection.filter.is_some() || selection.custom.is_some() - { - // We don't support types/filter/custom - continue; - } - - let matching = if selection.leading_underscore.is_some() - || selection.trailing_underscore.is_some() - { - let leading_underscore = selection - .leading_underscore - .map_or("", |underscore| underscore.as_regex_part()); - - let trailing_underscore = selection - .trailing_underscore - .map_or("", |underscore| underscore.as_regex_part()); - - let regex = format!("{leading_underscore}([^_]*){trailing_underscore}"); - - RestrictedRegex::from_str(®ex).ok() - } else { - None - }; - - let prefix = selection - .prefix - .iter() - .map(|p| regex::escape(p)) - .collect::>() - .join("|"); - - let suffix = selection - .suffix - .iter() - .map(|p| regex::escape(p)) - .collect::>() - .join("|"); - - let prefix = if prefix.is_empty() { - prefix - } else { - format!("(?:{prefix})") - }; - - let suffix = if suffix.is_empty() { - suffix - } else { - format!("(?:{suffix})") - }; - - let matching = if !prefix.is_empty() || !suffix.is_empty() { - if matching.is_some() { - continue; - } - - RestrictedRegex::try_from(format!("{prefix}(.*){suffix}")).ok() - } else { - matching - }; - - let selectors = selection.selectors(); - - let formats = if let Some(format) = selection.format { - format - .into_iter() - .map(use_naming_convention::Format::from) - .collect() - } else { - use_naming_convention::Formats::default() - }; - - for selector in selectors { - conventions.push(use_naming_convention::Convention { - selector, - matching: matching.clone(), - formats, - }); - } - } - - use_naming_convention::NamingConventionOptions { - strict_case: false, - require_ascii: false, - conventions: conventions.into_boxed_slice(), - enum_member_case: use_naming_convention::Format::default(), - } - } + fn from(val:NamingConventionOptions) -> Self { + let mut conventions = Vec::new(); + + for selection in val.0 { + if selection.types.is_some() || selection.filter.is_some() || selection.custom.is_some() { + // We don't support types/filter/custom + continue; + } + + let matching = if selection.leading_underscore.is_some() || selection.trailing_underscore.is_some() { + let leading_underscore = + selection.leading_underscore.map_or("", |underscore| underscore.as_regex_part()); + + let trailing_underscore = selection + .trailing_underscore + .map_or("", |underscore| underscore.as_regex_part()); + + let regex = format!("{leading_underscore}([^_]*){trailing_underscore}"); + + RestrictedRegex::from_str(®ex).ok() + } else { + None + }; + + let prefix = selection.prefix.iter().map(|p| regex::escape(p)).collect::>().join("|"); + + let suffix = selection.suffix.iter().map(|p| regex::escape(p)).collect::>().join("|"); + + let prefix = if prefix.is_empty() { prefix } else { format!("(?:{prefix})") }; + + let suffix = if suffix.is_empty() { suffix } else { format!("(?:{suffix})") }; + + let matching = if !prefix.is_empty() || !suffix.is_empty() { + if matching.is_some() { + continue; + } + + RestrictedRegex::try_from(format!("{prefix}(.*){suffix}")).ok() + } else { + matching + }; + + let selectors = selection.selectors(); + + let formats = if let Some(format) = selection.format { + format.into_iter().map(use_naming_convention::Format::from).collect() + } else { + use_naming_convention::Formats::default() + }; + + for selector in selectors { + conventions.push(use_naming_convention::Convention { selector, matching:matching.clone(), formats }); + } + } + + use_naming_convention::NamingConventionOptions { + strict_case:false, + require_ascii:false, + conventions:conventions.into_boxed_slice(), + enum_member_case:use_naming_convention::Format::default(), + } + } } #[derive(Debug, Default, Deserializable)] #[deserializable(unknown_fields = "allow")] pub(crate) struct NamingConventionSelection { - pub(crate) selector: eslint_eslint::ShorthandVec, - pub(crate) modifiers: Option>, - pub(crate) types: Option>, - pub(crate) custom: Option, - pub(crate) format: Option>, - pub(crate) leading_underscore: Option, - pub(crate) trailing_underscore: Option, - pub(crate) prefix: Vec, - pub(crate) suffix: Vec, - pub(crate) filter: Option, + pub(crate) selector:eslint_eslint::ShorthandVec, + pub(crate) modifiers:Option>, + pub(crate) types:Option>, + pub(crate) custom:Option, + pub(crate) format:Option>, + pub(crate) leading_underscore:Option, + pub(crate) trailing_underscore:Option, + pub(crate) prefix:Vec, + pub(crate) suffix:Vec, + pub(crate) filter:Option, } impl NamingConventionSelection { - fn precedence(&self, other: &Self) -> Ordering { - // Simplification: We compare only the first selectors. - let selector = self.selector.iter().next(); - - let other_selector = other.selector.iter().next(); - - match selector.cmp(&other_selector) { - Ordering::Equal => {} - - ord => return ord, - } - - match (&self.types, &other.types) { - (None, None) | (Some(_), Some(_)) => {} - (None, Some(_)) => return Ordering::Greater, - (Some(_), None) => return Ordering::Less, - } - - match (&self.modifiers, &other.modifiers) { - (None, None) | (Some(_), Some(_)) => {} - (None, Some(_)) => return Ordering::Greater, - (Some(_), None) => return Ordering::Less, - } - - Ordering::Equal - } - - fn selectors(&self) -> Vec { - let mut result = Vec::new(); - - let modifiers: use_naming_convention::Modifiers = self - .modifiers - .iter() - .flatten() - .filter_map(|m| m.as_modifier()) - .collect(); - - let has_class_modifier = - modifiers.contains(use_naming_convention::RestrictedModifier::Abstract); - - let has_class_member_modifier = modifiers - .contains(use_naming_convention::RestrictedModifier::Private) - || modifiers.contains(use_naming_convention::RestrictedModifier::Protected); - - let has_property_modifier = - modifiers.contains(use_naming_convention::RestrictedModifier::Readonly); - - modifiers.contains(use_naming_convention::RestrictedModifier::Private); - - let scope = self - .modifiers - .iter() - .flatten() - .find_map(|m| m.as_scope()) - .unwrap_or_default(); - - for selector in self.selector.iter() { - match selector { - Selector::AutoAccessor => { - // currently unsupported by Biome - continue; - } - - Selector::Class => { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::Class, - modifiers, - scope, - }); - } - - Selector::ClassMethod => { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::ClassMethod, - modifiers, - scope, - }); - } - - Selector::ClassProperty => { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::ClassProperty, - modifiers, - scope, - }); - } - - Selector::Enum => { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::Enum, - modifiers, - scope, - }); - } - - Selector::EnumMember => { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::EnumMember, - modifiers, - scope, - }); - } - - Selector::Function => { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::Function, - modifiers, - scope, - }); - } - - Selector::Import => { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::ImportNamespace, - modifiers, - scope, - }); - - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::ImportAlias, - modifiers, - scope, - }); - } - - Selector::Interface => { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::Interface, - modifiers, - scope, - }); - } - - Selector::ObjectLiteralMethod => { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::ObjectLiteralMethod, - modifiers, - scope, - }); - } - - Selector::ObjectLiteralProperty => { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::ObjectLiteralProperty, - modifiers, - scope, - }); - } - - Selector::Parameter => { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::FunctionParameter, - modifiers, - scope, - }); - } - - Selector::ParameterProperty => { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::ClassProperty, - modifiers, - scope, - }); - } - - Selector::TypeAlias => { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::TypeAlias, - modifiers, - scope, - }); - } - - Selector::TypeMethod => { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::TypeMethod, - modifiers, - scope, - }); - } - - Selector::TypeParameter => { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::TypeParameter, - modifiers, - scope, - }); - } - - Selector::TypeProperty => { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::TypeProperty, - modifiers, - scope, - }); - } - - Selector::Variable => { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::Variable, - modifiers, - scope, - }); - } - - Selector::Default => { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::Any, - modifiers, - scope, - }); - } - - Selector::ClassicAccessor | Selector::Accessor => { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::ClassGetter, - modifiers, - scope, - }); - - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::ClassSetter, - modifiers, - scope, - }); - - if !has_class_member_modifier { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::ObjectLiteralGetter, - modifiers, - scope, - }); - - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::ObjectLiteralSetter, - modifiers, - scope, - }); - - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::TypeGetter, - modifiers, - scope, - }); - - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::TypeSetter, - modifiers, - scope, - }); - } - } - - Selector::MemberLike => { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::ClassMember, - modifiers, - scope, - }); - - if !has_class_member_modifier { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::ObjectLiteralMember, - modifiers, - scope, - }); - - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::TypeMember, - modifiers, - scope, - }); - } - } - - Selector::Method => { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::ClassMethod, - modifiers, - scope, - }); - - if !has_class_member_modifier { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::ObjectLiteralMethod, - modifiers, - scope, - }); - - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::TypeMethod, - modifiers, - scope, - }); - } - } - - Selector::Property => { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::ClassProperty, - modifiers, - scope, - }); - - if !has_class_member_modifier { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::TypeProperty, - modifiers, - scope, - }); - - if !has_property_modifier { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::ObjectLiteralProperty, - modifiers, - scope, - }); - } - } - } - - Selector::TypeLike => { - if has_class_modifier { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::Class, - modifiers, - scope, - }); - } else { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::TypeLike, - modifiers, - scope, - }); - } - } - - Selector::VariableLike => { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::Variable, - modifiers, - scope, - }); - - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::Function, - modifiers, - scope, - }); - - if scope != use_naming_convention::Scope::Global { - result.push(use_naming_convention::Selector { - kind: use_naming_convention::Kind::FunctionParameter, - modifiers, - scope, - }); - } - } - } - } - // Remove invalid selectors. - // This avoids to generate errors when loading the Biome configuration. - result.retain(|selector| selector.check().is_ok()); - - result - } + fn precedence(&self, other:&Self) -> Ordering { + // Simplification: We compare only the first selectors. + let selector = self.selector.iter().next(); + + let other_selector = other.selector.iter().next(); + + match selector.cmp(&other_selector) { + Ordering::Equal => {}, + + ord => return ord, + } + + match (&self.types, &other.types) { + (None, None) | (Some(_), Some(_)) => {}, + (None, Some(_)) => return Ordering::Greater, + (Some(_), None) => return Ordering::Less, + } + + match (&self.modifiers, &other.modifiers) { + (None, None) | (Some(_), Some(_)) => {}, + (None, Some(_)) => return Ordering::Greater, + (Some(_), None) => return Ordering::Less, + } + + Ordering::Equal + } + + fn selectors(&self) -> Vec { + let mut result = Vec::new(); + + let modifiers:use_naming_convention::Modifiers = + self.modifiers.iter().flatten().filter_map(|m| m.as_modifier()).collect(); + + let has_class_modifier = modifiers.contains(use_naming_convention::RestrictedModifier::Abstract); + + let has_class_member_modifier = modifiers.contains(use_naming_convention::RestrictedModifier::Private) + || modifiers.contains(use_naming_convention::RestrictedModifier::Protected); + + let has_property_modifier = modifiers.contains(use_naming_convention::RestrictedModifier::Readonly); + + modifiers.contains(use_naming_convention::RestrictedModifier::Private); + + let scope = self.modifiers.iter().flatten().find_map(|m| m.as_scope()).unwrap_or_default(); + + for selector in self.selector.iter() { + match selector { + Selector::AutoAccessor => { + // currently unsupported by Biome + continue; + }, + + Selector::Class => { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::Class, + modifiers, + scope, + }); + }, + + Selector::ClassMethod => { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::ClassMethod, + modifiers, + scope, + }); + }, + + Selector::ClassProperty => { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::ClassProperty, + modifiers, + scope, + }); + }, + + Selector::Enum => { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::Enum, + modifiers, + scope, + }); + }, + + Selector::EnumMember => { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::EnumMember, + modifiers, + scope, + }); + }, + + Selector::Function => { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::Function, + modifiers, + scope, + }); + }, + + Selector::Import => { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::ImportNamespace, + modifiers, + scope, + }); + + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::ImportAlias, + modifiers, + scope, + }); + }, + + Selector::Interface => { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::Interface, + modifiers, + scope, + }); + }, + + Selector::ObjectLiteralMethod => { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::ObjectLiteralMethod, + modifiers, + scope, + }); + }, + + Selector::ObjectLiteralProperty => { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::ObjectLiteralProperty, + modifiers, + scope, + }); + }, + + Selector::Parameter => { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::FunctionParameter, + modifiers, + scope, + }); + }, + + Selector::ParameterProperty => { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::ClassProperty, + modifiers, + scope, + }); + }, + + Selector::TypeAlias => { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::TypeAlias, + modifiers, + scope, + }); + }, + + Selector::TypeMethod => { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::TypeMethod, + modifiers, + scope, + }); + }, + + Selector::TypeParameter => { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::TypeParameter, + modifiers, + scope, + }); + }, + + Selector::TypeProperty => { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::TypeProperty, + modifiers, + scope, + }); + }, + + Selector::Variable => { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::Variable, + modifiers, + scope, + }); + }, + + Selector::Default => { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::Any, + modifiers, + scope, + }); + }, + + Selector::ClassicAccessor | Selector::Accessor => { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::ClassGetter, + modifiers, + scope, + }); + + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::ClassSetter, + modifiers, + scope, + }); + + if !has_class_member_modifier { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::ObjectLiteralGetter, + modifiers, + scope, + }); + + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::ObjectLiteralSetter, + modifiers, + scope, + }); + + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::TypeGetter, + modifiers, + scope, + }); + + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::TypeSetter, + modifiers, + scope, + }); + } + }, + + Selector::MemberLike => { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::ClassMember, + modifiers, + scope, + }); + + if !has_class_member_modifier { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::ObjectLiteralMember, + modifiers, + scope, + }); + + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::TypeMember, + modifiers, + scope, + }); + } + }, + + Selector::Method => { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::ClassMethod, + modifiers, + scope, + }); + + if !has_class_member_modifier { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::ObjectLiteralMethod, + modifiers, + scope, + }); + + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::TypeMethod, + modifiers, + scope, + }); + } + }, + + Selector::Property => { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::ClassProperty, + modifiers, + scope, + }); + + if !has_class_member_modifier { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::TypeProperty, + modifiers, + scope, + }); + + if !has_property_modifier { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::ObjectLiteralProperty, + modifiers, + scope, + }); + } + } + }, + + Selector::TypeLike => { + if has_class_modifier { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::Class, + modifiers, + scope, + }); + } else { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::TypeLike, + modifiers, + scope, + }); + } + }, + + Selector::VariableLike => { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::Variable, + modifiers, + scope, + }); + + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::Function, + modifiers, + scope, + }); + + if scope != use_naming_convention::Scope::Global { + result.push(use_naming_convention::Selector { + kind:use_naming_convention::Kind::FunctionParameter, + modifiers, + scope, + }); + } + }, + } + } + // Remove invalid selectors. + // This avoids to generate errors when loading the Biome configuration. + result.retain(|selector| selector.check().is_ok()); + + result + } } #[derive(Debug)] pub(crate) struct Anything; impl Deserializable for Anything { - fn deserialize( - _value: &impl biome_deserialize::DeserializableValue, - _name: &str, - _diagnostics: &mut Vec, - ) -> Option { - Some(Anything) - } + fn deserialize( + _value:&impl biome_deserialize::DeserializableValue, + _name:&str, + _diagnostics:&mut Vec, + ) -> Option { + Some(Anything) + } } #[derive(Copy, Clone, Debug, Deserializable)] pub(crate) enum NamingConventionCase { - #[deserializable(rename = "camelCase")] - Camel, - #[deserializable(rename = "strictCamelCase")] - StrictCamel, - #[deserializable(rename = "PascalCase")] - Pascal, - #[deserializable(rename = "StrictPascalCase")] - StrictPascal, - #[deserializable(rename = "snake_case")] - Snake, - #[deserializable(rename = "UPPER_CASE")] - Upper, + #[deserializable(rename = "camelCase")] + Camel, + #[deserializable(rename = "strictCamelCase")] + StrictCamel, + #[deserializable(rename = "PascalCase")] + Pascal, + #[deserializable(rename = "StrictPascalCase")] + StrictPascal, + #[deserializable(rename = "snake_case")] + Snake, + #[deserializable(rename = "UPPER_CASE")] + Upper, } impl From for use_naming_convention::Format { - fn from(value: NamingConventionCase) -> Self { - match value { - NamingConventionCase::Camel | NamingConventionCase::StrictCamel => Self::Camel, - NamingConventionCase::Pascal | NamingConventionCase::StrictPascal => Self::Pascal, - NamingConventionCase::Snake => Self::Snake, - NamingConventionCase::Upper => Self::Constant, - } - } + fn from(value:NamingConventionCase) -> Self { + match value { + NamingConventionCase::Camel | NamingConventionCase::StrictCamel => Self::Camel, + NamingConventionCase::Pascal | NamingConventionCase::StrictPascal => Self::Pascal, + NamingConventionCase::Snake => Self::Snake, + NamingConventionCase::Upper => Self::Constant, + } + } } #[derive(Debug, Default, Deserializable, Eq, PartialEq, PartialOrd, Ord)] pub(crate) enum Selector { - // Order is important, it reflects the precedence relation between selectors - // Individual selectors - ClassicAccessor, - AutoAccessor, - Class, - ClassMethod, - ClassProperty, - Enum, - EnumMember, - Function, - Import, - Interface, - ObjectLiteralMethod, - ObjectLiteralProperty, - Parameter, - ParameterProperty, - TypeAlias, - TypeMethod, - TypeParameter, - TypeProperty, - Variable, - // group selector - Accessor, - Method, - Property, - TypeLike, - VariableLike, - MemberLike, - #[default] - Default, + // Order is important, it reflects the precedence relation between selectors + // Individual selectors + ClassicAccessor, + AutoAccessor, + Class, + ClassMethod, + ClassProperty, + Enum, + EnumMember, + Function, + Import, + Interface, + ObjectLiteralMethod, + ObjectLiteralProperty, + Parameter, + ParameterProperty, + TypeAlias, + TypeMethod, + TypeParameter, + TypeProperty, + Variable, + // group selector + Accessor, + Method, + Property, + TypeLike, + VariableLike, + MemberLike, + #[default] + Default, } #[derive(Copy, Clone, Debug, Deserializable)] pub(crate) enum Modifier { - Abstract, - Async, - Const, - Destructured, - Exported, - Global, - Override, - Private, - Protected, - Public, - Readonly, - RequiresQuotes, - #[deserializable(rename = "#private")] - SharpPrivate, - Static, - Unused, + Abstract, + Async, + Const, + Destructured, + Exported, + Global, + Override, + Private, + Protected, + Public, + Readonly, + RequiresQuotes, + #[deserializable(rename = "#private")] + SharpPrivate, + Static, + Unused, } impl Modifier { - fn as_modifier(self) -> Option { - match self { - Modifier::Abstract => Some(use_naming_convention::RestrictedModifier::Abstract), - Modifier::Private => Some(use_naming_convention::RestrictedModifier::Private), - Modifier::Protected => Some(use_naming_convention::RestrictedModifier::Protected), - Modifier::Readonly => Some(use_naming_convention::RestrictedModifier::Readonly), - Modifier::Static => Some(use_naming_convention::RestrictedModifier::Static), - _ => None, - } - } - - fn as_scope(self) -> Option { - match self { - Modifier::Global => Some(use_naming_convention::Scope::Global), - _ => None, - } - } + fn as_modifier(self) -> Option { + match self { + Modifier::Abstract => Some(use_naming_convention::RestrictedModifier::Abstract), + Modifier::Private => Some(use_naming_convention::RestrictedModifier::Private), + Modifier::Protected => Some(use_naming_convention::RestrictedModifier::Protected), + Modifier::Readonly => Some(use_naming_convention::RestrictedModifier::Readonly), + Modifier::Static => Some(use_naming_convention::RestrictedModifier::Static), + _ => None, + } + } + + fn as_scope(self) -> Option { + match self { + Modifier::Global => Some(use_naming_convention::Scope::Global), + _ => None, + } + } } #[derive(Debug, Deserializable)] pub(crate) enum Type { - Array, - Boolean, - Function, - Number, - String, + Array, + Boolean, + Function, + Number, + String, } #[derive(Clone, Copy, Debug, Deserializable)] pub(crate) enum Underscore { - Forbid, - Require, - RequireDouble, - Allow, - AllowDouble, - AllowSingleOrDouble, + Forbid, + Require, + RequireDouble, + Allow, + AllowDouble, + AllowSingleOrDouble, } impl Underscore { - fn as_regex_part(self) -> &'static str { - match self { - Self::Forbid => "", - Self::Require => "_", - Self::RequireDouble => "__", - Self::Allow => "_?", - Self::AllowDouble => "(?:__)?", - Self::AllowSingleOrDouble => "_?_?", - } - } + fn as_regex_part(self) -> &'static str { + match self { + Self::Forbid => "", + Self::Require => "_", + Self::RequireDouble => "__", + Self::Allow => "_?", + Self::AllowDouble => "(?:__)?", + Self::AllowSingleOrDouble => "_?_?", + } + } } diff --git a/crates/biome_cli/Source/execute/migrate/eslint_unicorn.rs b/crates/biome_cli/Source/execute/migrate/eslint_unicorn.rs index a30173f19427..3aeacaabc8e9 100644 --- a/crates/biome_cli/Source/execute/migrate/eslint_unicorn.rs +++ b/crates/biome_cli/Source/execute/migrate/eslint_unicorn.rs @@ -1,85 +1,85 @@ /// Configuration related to the /// [Unicorn Eslint plugin](https://github.com/sindresorhus/eslint-plugin-unicorn). /// -/// ALso, the module includes implementation to convert rule options to Biome's rule options. +/// ALso, the module includes implementation to convert rule options to Biome's +/// rule options. use biome_deserialize_macros::Deserializable; use biome_js_analyze::lint::style::use_filenaming_convention; use smallvec::SmallVec; #[derive(Clone, Debug, Default, Deserializable)] pub(crate) struct FilenameCaseOptions { - case: FilenameCase, - cases: FilenameCases, - ignore: Vec, - multiple_file_extensions: bool, + case:FilenameCase, + cases:FilenameCases, + ignore:Vec, + multiple_file_extensions:bool, } impl From for use_filenaming_convention::FilenamingConventionOptions { - fn from(val: FilenameCaseOptions) -> Self { - let filename_cases: Option = val.cases.into(); + fn from(val:FilenameCaseOptions) -> Self { + let filename_cases:Option = val.cases.into(); - use_filenaming_convention::FilenamingConventionOptions { - strict_case: true, - require_ascii: true, - matching: None, - filename_cases: filename_cases.unwrap_or_else(|| { - use_filenaming_convention::FilenameCases::from_iter([val.case.into()]) - }), - } - } + use_filenaming_convention::FilenamingConventionOptions { + strict_case:true, + require_ascii:true, + matching:None, + filename_cases:filename_cases + .unwrap_or_else(|| use_filenaming_convention::FilenameCases::from_iter([val.case.into()])), + } + } } #[derive(Clone, Debug, Default, Deserializable)] pub(crate) enum FilenameCase { - #[default] - #[deserializable(rename = "kebabCase")] - Kebab, - #[deserializable(rename = "camelCase")] - Camel, - #[deserializable(rename = "snakeCase")] - Snake, - #[deserializable(rename = "pascalCase")] - Pascal, + #[default] + #[deserializable(rename = "kebabCase")] + Kebab, + #[deserializable(rename = "camelCase")] + Camel, + #[deserializable(rename = "snakeCase")] + Snake, + #[deserializable(rename = "pascalCase")] + Pascal, } impl From for use_filenaming_convention::FilenameCase { - fn from(val: FilenameCase) -> Self { - match val { - FilenameCase::Kebab => use_filenaming_convention::FilenameCase::Kebab, - FilenameCase::Camel => use_filenaming_convention::FilenameCase::Camel, - FilenameCase::Snake => use_filenaming_convention::FilenameCase::Snake, - FilenameCase::Pascal => use_filenaming_convention::FilenameCase::Pascal, - } - } + fn from(val:FilenameCase) -> Self { + match val { + FilenameCase::Kebab => use_filenaming_convention::FilenameCase::Kebab, + FilenameCase::Camel => use_filenaming_convention::FilenameCase::Camel, + FilenameCase::Snake => use_filenaming_convention::FilenameCase::Snake, + FilenameCase::Pascal => use_filenaming_convention::FilenameCase::Pascal, + } + } } #[derive(Clone, Debug, Default, Deserializable)] pub(crate) struct FilenameCases { - kebab_case: bool, - camel_case: bool, - snake_case: bool, - pascal_case: bool, + kebab_case:bool, + camel_case:bool, + snake_case:bool, + pascal_case:bool, } impl From for Option { - fn from(val: FilenameCases) -> Self { - let mut cases: SmallVec<[use_filenaming_convention::FilenameCase; 4]> = SmallVec::new(); + fn from(val:FilenameCases) -> Self { + let mut cases:SmallVec<[use_filenaming_convention::FilenameCase; 4]> = SmallVec::new(); - if val.kebab_case { - cases.push(use_filenaming_convention::FilenameCase::Kebab); - } + if val.kebab_case { + cases.push(use_filenaming_convention::FilenameCase::Kebab); + } - if val.camel_case { - cases.push(use_filenaming_convention::FilenameCase::Camel); - } + if val.camel_case { + cases.push(use_filenaming_convention::FilenameCase::Camel); + } - if val.snake_case { - cases.push(use_filenaming_convention::FilenameCase::Snake); - } + if val.snake_case { + cases.push(use_filenaming_convention::FilenameCase::Snake); + } - if val.pascal_case { - cases.push(use_filenaming_convention::FilenameCase::Pascal); - } + if val.pascal_case { + cases.push(use_filenaming_convention::FilenameCase::Pascal); + } - if cases.is_empty() { - None - } else { - Some(use_filenaming_convention::FilenameCases::from_iter(cases)) - } - } + if cases.is_empty() { + None + } else { + Some(use_filenaming_convention::FilenameCases::from_iter(cases)) + } + } } diff --git a/crates/biome_cli/Source/execute/migrate/ignorefile.rs b/crates/biome_cli/Source/execute/migrate/ignorefile.rs index 775f26d354b6..2b30098d15fc 100644 --- a/crates/biome_cli/Source/execute/migrate/ignorefile.rs +++ b/crates/biome_cli/Source/execute/migrate/ignorefile.rs @@ -6,101 +6,89 @@ use indexmap::IndexSet; /// Read an ignore file that follows gitignore pattern syntax, /// and turn them into a list of UNIX glob patterns. -pub(crate) fn read_ignore_file( - fs: &DynRef<'_, dyn FileSystem>, - ignore_filename: &str, -) -> io::Result { - let mut file = fs.open_with_options( - Path::new(ignore_filename), - OpenOptions::default().read(true), - )?; +pub(crate) fn read_ignore_file(fs:&DynRef<'_, dyn FileSystem>, ignore_filename:&str) -> io::Result { + let mut file = fs.open_with_options(Path::new(ignore_filename), OpenOptions::default().read(true))?; - let mut content = String::new(); + let mut content = String::new(); - file.read_to_string(&mut content)?; + file.read_to_string(&mut content)?; - Ok(IgnorePatterns::from(&content)) + Ok(IgnorePatterns::from(&content)) } #[derive(Debug)] pub(crate) struct IgnorePatterns { - pub(crate) patterns: IndexSet, - pub(crate) has_negated_patterns: bool, + pub(crate) patterns:IndexSet, + pub(crate) has_negated_patterns:bool, } impl IgnorePatterns { - pub(crate) fn from(content: &str) -> Self { - let mut has_negated_patterns = false; - - let mut patterns = IndexSet::new(); - - for line in content.lines() { - // Trailing spaces are ignored - let line = line.trim_end(); - // empty lines and comments are ignored - if line.is_empty() || line.starts_with('#') { - continue; - } - - match convert_pattern(line) { - Ok(pattern) => { - patterns.insert(pattern); - } - - Err(_) => { - has_negated_patterns = true; - // Skip negated patterns because we don't support them. - continue; - } - } - } - - IgnorePatterns { - patterns, - has_negated_patterns, - } - } + pub(crate) fn from(content:&str) -> Self { + let mut has_negated_patterns = false; + + let mut patterns = IndexSet::new(); + + for line in content.lines() { + // Trailing spaces are ignored + let line = line.trim_end(); + // empty lines and comments are ignored + if line.is_empty() || line.starts_with('#') { + continue; + } + + match convert_pattern(line) { + Ok(pattern) => { + patterns.insert(pattern); + }, + + Err(_) => { + has_negated_patterns = true; + // Skip negated patterns because we don't support them. + continue; + }, + } + } + + IgnorePatterns { patterns, has_negated_patterns } + } } -pub(crate) fn convert_pattern(line: &str) -> Result { - if line.starts_with('!') { - // Skip negated patterns because we don't support them. - return Err("Negated patterns are not supported."); - } - - let result = if let Some(stripped_line) = line.strip_prefix('/') { - // Patterns tha tstarts with `/` are relative to the ignore file - format!("./{stripped_line}") - } else if line.find('/').is_some_and(|index| index < (line.len() - 1)) - || line == "**" - || line == "**/" - { - // Patterns that includes at least one `/` in the middle are relatives paths - line.to_string() - } else { - format!("**/{line}") - }; - - Ok(result) +pub(crate) fn convert_pattern(line:&str) -> Result { + if line.starts_with('!') { + // Skip negated patterns because we don't support them. + return Err("Negated patterns are not supported."); + } + + let result = if let Some(stripped_line) = line.strip_prefix('/') { + // Patterns tha tstarts with `/` are relative to the ignore file + format!("./{stripped_line}") + } else if line.find('/').is_some_and(|index| index < (line.len() - 1)) || line == "**" || line == "**/" { + // Patterns that includes at least one `/` in the middle are relatives paths + line.to_string() + } else { + format!("**/{line}") + }; + + Ok(result) } #[cfg(test)] mod tests { - use super::*; + use super::*; - #[test] - fn empty() { - const IGNORE_FILE_CONTENT: &str = r#""#; + #[test] + fn empty() { + const IGNORE_FILE_CONTENT:&str = r#""#; - let result = IgnorePatterns::from(IGNORE_FILE_CONTENT); + let result = IgnorePatterns::from(IGNORE_FILE_CONTENT); - assert!(!result.has_negated_patterns); + assert!(!result.has_negated_patterns); - assert!(result.patterns.is_empty()); - } + assert!(result.patterns.is_empty()); + } - #[test] - fn comments_and_empty_lines() { - const IGNORE_FILE_CONTENT: &str = r#" + #[test] + fn comments_and_empty_lines() { + const IGNORE_FILE_CONTENT:&str = r#" # Comment 1 # folloed by a blank line @@ -109,16 +97,16 @@ mod tests { "#; - let result = IgnorePatterns::from(IGNORE_FILE_CONTENT); + let result = IgnorePatterns::from(IGNORE_FILE_CONTENT); - assert!(!result.has_negated_patterns); + assert!(!result.has_negated_patterns); - assert!(result.patterns.is_empty()); - } + assert!(result.patterns.is_empty()); + } - #[test] - fn non_relative_patterns() { - const IGNORE_FILE_CONTENT: &str = r#" + #[test] + fn non_relative_patterns() { + const IGNORE_FILE_CONTENT:&str = r#" file-or-dir dir/ ** @@ -127,27 +115,27 @@ dir/ */ "#; - let result = IgnorePatterns::from(IGNORE_FILE_CONTENT); - - assert!(!result.has_negated_patterns); - - assert_eq!( - result.patterns, - [ - "**/file-or-dir".to_string(), - "**/dir/".to_string(), - "**".to_string(), - "**/".to_string(), - "**/*".to_string(), - "**/*/".to_string(), - ] - .into() - ); - } - - #[test] - fn relative_patterns() { - const IGNORE_FILE_CONTENT: &str = r#" + let result = IgnorePatterns::from(IGNORE_FILE_CONTENT); + + assert!(!result.has_negated_patterns); + + assert_eq!( + result.patterns, + [ + "**/file-or-dir".to_string(), + "**/dir/".to_string(), + "**".to_string(), + "**/".to_string(), + "**/*".to_string(), + "**/*/".to_string(), + ] + .into() + ); + } + + #[test] + fn relative_patterns() { + const IGNORE_FILE_CONTENT:&str = r#" dir/dubfile-or-subdir dir/subdir/ **/* @@ -156,27 +144,27 @@ dir/subdir/ **/a/b/ "#; - let result = IgnorePatterns::from(IGNORE_FILE_CONTENT); - - assert!(!result.has_negated_patterns); - - assert_eq!( - result.patterns, - [ - "dir/dubfile-or-subdir".to_string(), - "dir/subdir/".to_string(), - "**/*".to_string(), - "**/*/".to_string(), - "**/a/b".to_string(), - "**/a/b/".to_string(), - ] - .into() - ); - } - - #[test] - fn relative_patterns_starting_with_root_slash() { - const IGNORE_FILE_CONTENT: &str = r#" + let result = IgnorePatterns::from(IGNORE_FILE_CONTENT); + + assert!(!result.has_negated_patterns); + + assert_eq!( + result.patterns, + [ + "dir/dubfile-or-subdir".to_string(), + "dir/subdir/".to_string(), + "**/*".to_string(), + "**/*/".to_string(), + "**/a/b".to_string(), + "**/a/b/".to_string(), + ] + .into() + ); + } + + #[test] + fn relative_patterns_starting_with_root_slash() { + const IGNORE_FILE_CONTENT:&str = r#" /dir/dubfile-or-subdir /dir/subdir/ /**/* @@ -185,49 +173,48 @@ dir/subdir/ /**/a/b/ "#; - let result = IgnorePatterns::from(IGNORE_FILE_CONTENT); + let result = IgnorePatterns::from(IGNORE_FILE_CONTENT); - assert!(!result.has_negated_patterns); + assert!(!result.has_negated_patterns); - assert_eq!( - result.patterns, - [ - "./dir/dubfile-or-subdir".to_string(), - "./dir/subdir/".to_string(), - "./**/*".to_string(), - "./**/*/".to_string(), - "./**/a/b".to_string(), - "./**/a/b/".to_string(), - ] - .into() - ); - } + assert_eq!( + result.patterns, + [ + "./dir/dubfile-or-subdir".to_string(), + "./dir/subdir/".to_string(), + "./**/*".to_string(), + "./**/*/".to_string(), + "./**/a/b".to_string(), + "./**/a/b/".to_string(), + ] + .into() + ); + } - #[test] - fn negated_pattern() { - const IGNORE_FILE_CONTENT: &str = r#"!a"#; + #[test] + fn negated_pattern() { + const IGNORE_FILE_CONTENT:&str = r#"!a"#; - let result = IgnorePatterns::from(IGNORE_FILE_CONTENT); + let result = IgnorePatterns::from(IGNORE_FILE_CONTENT); - assert!(result.has_negated_patterns); + assert!(result.has_negated_patterns); - assert!(result.patterns.is_empty()); - } + assert!(result.patterns.is_empty()); + } - #[test] - fn take_leading_spaces_into_account() { - const IGNORE_FILE_CONTENT: &str = r#" + #[test] + fn take_leading_spaces_into_account() { + const IGNORE_FILE_CONTENT:&str = r#" # This is not a comment because there is some leading spaces "#; - let result = IgnorePatterns::from(IGNORE_FILE_CONTENT); + let result = IgnorePatterns::from(IGNORE_FILE_CONTENT); - assert!(!result.has_negated_patterns); + assert!(!result.has_negated_patterns); - assert_eq!( - result.patterns, - ["**/ # This is not a comment because there is some leading spaces".to_string()] - .into() - ); - } + assert_eq!( + result.patterns, + ["**/ # This is not a comment because there is some leading spaces".to_string()].into() + ); + } } diff --git a/crates/biome_cli/Source/execute/migrate/node.rs b/crates/biome_cli/Source/execute/migrate/node.rs index 55148f221c22..d35df3c01089 100644 --- a/crates/biome_cli/Source/execute/migrate/node.rs +++ b/crates/biome_cli/Source/execute/migrate/node.rs @@ -1,80 +1,83 @@ use std::process::Command; -use crate::{diagnostics::MigrationDiagnostic, CliDiagnostic}; +use crate::{CliDiagnostic, diagnostics::MigrationDiagnostic}; /// Imports `specifier` using Node's `import()` or node's `require()` and /// returns the JSONified content of its default export. -pub(crate) fn load_config(specifier: &str) -> Result { - let content_output = Command::new("node") - .env("NODE_NO_WARNINGS", "1") - .arg("--eval") - .arg(format!( - "{UNCYCLE_FUNCTION} import('{specifier}').then((c) => console.log(JSON.stringify(uncycle(c.default))))" - )) - .output(); +pub(crate) fn load_config(specifier:&str) -> Result { + let content_output = Command::new("node") + .env("NODE_NO_WARNINGS", "1") + .arg("--eval") + .arg(format!( + "{UNCYCLE_FUNCTION} import('{specifier}').then((c) => console.log(JSON.stringify(uncycle(c.default))))" + )) + .output(); - match content_output { - Err(_) => { - Err(CliDiagnostic::MigrateError(MigrationDiagnostic { - reason: "The `node` program doesn't exist or cannot be invoked by Biome.\n`node` is invoked to resolve ESLint configurations written in JavaScript.\nThis includes shared configurations and plugin configurations imported with ESLint's `extends`.".to_string() - })) - }, - Ok(output) => { - let path_output = Command::new("node") - .env("NODE_NO_WARNINGS", "1") - .arg("--print") - .arg(format!( - "require.resolve('{specifier}')" - )) - .output(); + match content_output { + Err(_) => { + Err(CliDiagnostic::MigrateError(MigrationDiagnostic { + reason:"The `node` program doesn't exist or cannot be invoked by Biome.\n`node` is invoked to resolve \ + ESLint configurations written in JavaScript.\nThis includes shared configurations and plugin \ + configurations imported with ESLint's `extends`." + .to_string(), + })) + }, + Ok(output) => { + let path_output = Command::new("node") + .env("NODE_NO_WARNINGS", "1") + .arg("--print") + .arg(format!("require.resolve('{specifier}')")) + .output(); - let resolved_path = path_output.ok().map_or(String::new(), |path_output| String::from_utf8_lossy(&path_output.stdout).trim().to_string()); + let resolved_path = path_output.ok().map_or(String::new(), |path_output| { + String::from_utf8_lossy(&path_output.stdout).trim().to_string() + }); - if !output.stderr.is_empty() { - // Try with `require` before giving up. - let output2 = Command::new("node") - .env("NODE_NO_WARNINGS", "1") - .arg("--eval") - .arg(format!( - "{UNCYCLE_FUNCTION} console.log(JSON.stringify(uncycle(require('{specifier}'))))" - )) - .output(); + if !output.stderr.is_empty() { + // Try with `require` before giving up. + let output2 = Command::new("node") + .env("NODE_NO_WARNINGS", "1") + .arg("--eval") + .arg(format!( + "{UNCYCLE_FUNCTION} console.log(JSON.stringify(uncycle(require('{specifier}'))))" + )) + .output(); - if let Ok(output2) = output2 { - if output2.stderr.is_empty() { - return Ok(Resolution { - content: String::from_utf8_lossy(&output2.stdout).to_string(), - resolved_path, - }); - } - } + if let Ok(output2) = output2 { + if output2.stderr.is_empty() { + return Ok(Resolution { + content:String::from_utf8_lossy(&output2.stdout).to_string(), + resolved_path, + }); + } + } - let stderr = String::from_utf8_lossy(&output.stderr); + let stderr = String::from_utf8_lossy(&output.stderr); - return Err(CliDiagnostic::MigrateError(MigrationDiagnostic { - reason: format!("`node` was invoked to resolve '{specifier}'. This invocation failed with the following error:\n{stderr}") - })); - } + return Err(CliDiagnostic::MigrateError(MigrationDiagnostic { + reason:format!( + "`node` was invoked to resolve '{specifier}'. This invocation failed with the following \ + error:\n{stderr}" + ), + })); + } - Ok(Resolution { - content: String::from_utf8_lossy(&output.stdout).to_string(), - resolved_path, - }) - } - } + Ok(Resolution { content:String::from_utf8_lossy(&output.stdout).to_string(), resolved_path }) + }, + } } #[derive(Debug)] pub(crate) struct Resolution { - /// Resolved path of the file. - /// May be empty if the resolution failed. - pub(crate) resolved_path: String, - /// File content in JSON - pub(crate) content: String, + /// Resolved path of the file. + /// May be empty if the resolution failed. + pub(crate) resolved_path:String, + /// File content in JSON + pub(crate) content:String, } /// JavaScript function used to remove cyclic references. -const UNCYCLE_FUNCTION: &str = "function uncycle(obj, seen = new Set()) { +const UNCYCLE_FUNCTION:&str = "function uncycle(obj, seen = new Set()) { seen.add(obj); for (const [key, val] of Object.entries(obj)) { diff --git a/crates/biome_cli/Source/execute/migrate/prettier.rs b/crates/biome_cli/Source/execute/migrate/prettier.rs index 3284d36170f1..e5af08369cc5 100644 --- a/crates/biome_cli/Source/execute/migrate/prettier.rs +++ b/crates/biome_cli/Source/execute/migrate/prettier.rs @@ -1,572 +1,531 @@ -use crate::diagnostics::MigrationDiagnostic; -use crate::CliDiagnostic; -use biome_console::{markup, Console, ConsoleExt}; -use biome_deserialize::{json::deserialize_from_json_str, StringSet}; +use std::{ffi::OsStr, path::Path}; + +use biome_console::{Console, ConsoleExt, markup}; +use biome_deserialize::{StringSet, json::deserialize_from_json_str}; use biome_deserialize_macros::Deserializable; use biome_diagnostics::{DiagnosticExt, PrintDiagnostic}; use biome_formatter::{ - AttributePosition, BracketSpacing, IndentWidth, LineEnding, LineWidth, ParseFormatNumberError, - QuoteStyle, + AttributePosition, + BracketSpacing, + IndentWidth, + LineEnding, + LineWidth, + ParseFormatNumberError, + QuoteStyle, }; use biome_fs::{FileSystem, OpenOptions}; use biome_js_formatter::context::{ArrowParentheses, QuoteProperties, Semicolons, TrailingCommas}; use biome_json_parser::JsonParserOptions; use biome_service::DynRef; -use std::{ffi::OsStr, path::Path}; use super::{eslint_eslint::ShorthandVec, node}; +use crate::{CliDiagnostic, diagnostics::MigrationDiagnostic}; #[derive(Debug, Default, Deserializable)] #[deserializable(unknown_fields = "allow")] pub(crate) struct PrettierPackageJson { - pub(crate) prettier: Option, + pub(crate) prettier:Option, } #[derive(Debug)] pub(crate) struct Config { - /// Path of the ESlint config file - pub(crate) path: &'static str, - /// Resolved ESlint config - pub(crate) data: PrettierConfiguration, + /// Path of the ESlint config file + pub(crate) path:&'static str, + /// Resolved ESlint config + pub(crate) data:PrettierConfiguration, } #[derive(Debug, Deserializable)] #[deserializable(unknown_fields = "allow")] pub(crate) struct PrettierConfiguration { - /// https://prettier.io/docs/en/options#print-width - print_width: u16, - /// https://prettier.io/docs/en/options#use-tabs - use_tabs: bool, - /// https://prettier.io/docs/en/options#trailing-commas - trailing_comma: PrettierTrailingComma, - /// https://prettier.io/docs/en/options#tab-width - tab_width: u8, - /// https://prettier.io/docs/en/options#semicolons - semi: bool, - /// https://prettier.io/docs/en/options#quotes - single_quote: bool, - /// https://prettier.io/docs/en/options#bracket-spcing - bracket_spacing: bool, - /// https://prettier.io/docs/en/options#bracket-line - bracket_line: bool, - /// https://prettier.io/docs/en/options#quote-props - quote_props: QuoteProps, - /// https://prettier.io/docs/en/options#jsx-quotes - jsx_single_quote: bool, - /// https://prettier.io/docs/en/options#arrow-function-parentheses - arrow_parens: ArrowParens, - /// https://prettier.io/docs/en/options#end-of-line - end_of_line: EndOfLine, - /// https://prettier.io/docs/en/configuration.html#configuration-overrides - overrides: Vec, + /// https://prettier.io/docs/en/options#print-width + print_width:u16, + /// https://prettier.io/docs/en/options#use-tabs + use_tabs:bool, + /// https://prettier.io/docs/en/options#trailing-commas + trailing_comma:PrettierTrailingComma, + /// https://prettier.io/docs/en/options#tab-width + tab_width:u8, + /// https://prettier.io/docs/en/options#semicolons + semi:bool, + /// https://prettier.io/docs/en/options#quotes + single_quote:bool, + /// https://prettier.io/docs/en/options#bracket-spcing + bracket_spacing:bool, + /// https://prettier.io/docs/en/options#bracket-line + bracket_line:bool, + /// https://prettier.io/docs/en/options#quote-props + quote_props:QuoteProps, + /// https://prettier.io/docs/en/options#jsx-quotes + jsx_single_quote:bool, + /// https://prettier.io/docs/en/options#arrow-function-parentheses + arrow_parens:ArrowParens, + /// https://prettier.io/docs/en/options#end-of-line + end_of_line:EndOfLine, + /// https://prettier.io/docs/en/configuration.html#configuration-overrides + overrides:Vec, } impl Default for PrettierConfiguration { - fn default() -> Self { - Self { - print_width: 80, - use_tabs: false, - trailing_comma: PrettierTrailingComma::default(), - tab_width: 2, - semi: false, - single_quote: true, - bracket_spacing: true, - bracket_line: false, - quote_props: QuoteProps::default(), - jsx_single_quote: false, - arrow_parens: ArrowParens::default(), - end_of_line: EndOfLine::default(), - overrides: vec![], - } - } + fn default() -> Self { + Self { + print_width:80, + use_tabs:false, + trailing_comma:PrettierTrailingComma::default(), + tab_width:2, + semi:false, + single_quote:true, + bracket_spacing:true, + bracket_line:false, + quote_props:QuoteProps::default(), + jsx_single_quote:false, + arrow_parens:ArrowParens::default(), + end_of_line:EndOfLine::default(), + overrides:vec![], + } + } } #[derive(Debug, Default, Deserializable)] pub(crate) struct Override { - files: ShorthandVec, - options: OverrideOptions, + files:ShorthandVec, + options:OverrideOptions, } #[derive(Clone, Debug, Default, Deserializable, Eq, PartialEq)] #[deserializable(unknown_fields = "allow")] pub(crate) struct OverrideOptions { - /// https://prettier.io/docs/en/options#print-width - print_width: Option, - /// https://prettier.io/docs/en/options#use-tabs - use_tabs: Option, - /// https://prettier.io/docs/en/options#trailing-commas - trailing_comma: Option, - /// https://prettier.io/docs/en/options#tab-width - tab_width: Option, - /// https://prettier.io/docs/en/options#semicolons - semi: Option, - /// https://prettier.io/docs/en/options#quotes - single_quote: Option, - /// https://prettier.io/docs/en/options#bracket-spcing - bracket_spacing: Option, - /// https://prettier.io/docs/en/options#bracket-line - bracket_line: Option, - /// https://prettier.io/docs/en/options#quote-props - quote_props: Option, - /// https://prettier.io/docs/en/options#jsx-quotes - jsx_single_quote: Option, - /// https://prettier.io/docs/en/options#arrow-function-parentheses - arrow_parens: Option, - /// https://prettier.io/docs/en/options#end-of-line - end_of_line: Option, + /// https://prettier.io/docs/en/options#print-width + print_width:Option, + /// https://prettier.io/docs/en/options#use-tabs + use_tabs:Option, + /// https://prettier.io/docs/en/options#trailing-commas + trailing_comma:Option, + /// https://prettier.io/docs/en/options#tab-width + tab_width:Option, + /// https://prettier.io/docs/en/options#semicolons + semi:Option, + /// https://prettier.io/docs/en/options#quotes + single_quote:Option, + /// https://prettier.io/docs/en/options#bracket-spcing + bracket_spacing:Option, + /// https://prettier.io/docs/en/options#bracket-line + bracket_line:Option, + /// https://prettier.io/docs/en/options#quote-props + quote_props:Option, + /// https://prettier.io/docs/en/options#jsx-quotes + jsx_single_quote:Option, + /// https://prettier.io/docs/en/options#arrow-function-parentheses + arrow_parens:Option, + /// https://prettier.io/docs/en/options#end-of-line + end_of_line:Option, } #[derive(Clone, Debug, Default, Deserializable, Eq, PartialEq)] enum EndOfLine { - #[default] - Lf, - Crlf, - Cr, - Auto, + #[default] + Lf, + Crlf, + Cr, + Auto, } #[derive(Clone, Debug, Default, Deserializable, Eq, PartialEq)] enum ArrowParens { - #[default] - Always, - Avoid, + #[default] + Always, + Avoid, } #[derive(Clone, Debug, Default, Deserializable, Eq, PartialEq)] enum PrettierTrailingComma { - #[default] - All, - None, - Es5, + #[default] + All, + None, + Es5, } #[derive(Clone, Debug, Default, Deserializable, Eq, PartialEq)] enum QuoteProps { - #[default] - #[deserializable(rename = "as-needed")] - AsNeeded, - Preserve, + #[default] + #[deserializable(rename = "as-needed")] + AsNeeded, + Preserve, } impl From for TrailingCommas { - fn from(value: PrettierTrailingComma) -> Self { - match value { - PrettierTrailingComma::All => Self::All, - PrettierTrailingComma::None => Self::None, - PrettierTrailingComma::Es5 => Self::Es5, - } - } + fn from(value:PrettierTrailingComma) -> Self { + match value { + PrettierTrailingComma::All => Self::All, + PrettierTrailingComma::None => Self::None, + PrettierTrailingComma::Es5 => Self::Es5, + } + } } impl From for ArrowParentheses { - fn from(value: ArrowParens) -> Self { - match value { - ArrowParens::Always => Self::Always, - ArrowParens::Avoid => Self::AsNeeded, - } - } + fn from(value:ArrowParens) -> Self { + match value { + ArrowParens::Always => Self::Always, + ArrowParens::Avoid => Self::AsNeeded, + } + } } impl From for LineEnding { - fn from(value: EndOfLine) -> Self { - match value { - EndOfLine::Lf => LineEnding::Lf, - EndOfLine::Crlf => LineEnding::Crlf, - EndOfLine::Cr => LineEnding::Cr, - EndOfLine::Auto => LineEnding::default(), - } - } + fn from(value:EndOfLine) -> Self { + match value { + EndOfLine::Lf => LineEnding::Lf, + EndOfLine::Crlf => LineEnding::Crlf, + EndOfLine::Cr => LineEnding::Cr, + EndOfLine::Auto => LineEnding::default(), + } + } } impl From for QuoteProperties { - fn from(value: QuoteProps) -> Self { - match value { - QuoteProps::AsNeeded => Self::AsNeeded, - QuoteProps::Preserve => Self::Preserve, - } - } + fn from(value:QuoteProps) -> Self { + match value { + QuoteProps::AsNeeded => Self::AsNeeded, + QuoteProps::Preserve => Self::Preserve, + } + } } impl TryFrom for biome_configuration::PartialConfiguration { - type Error = ParseFormatNumberError; - - fn try_from(value: PrettierConfiguration) -> Result { - let mut result = biome_configuration::PartialConfiguration::default(); - - let line_width = LineWidth::try_from(value.print_width)?; - - let indent_width = IndentWidth::try_from(value.tab_width)?; - - let indent_style = if value.use_tabs { - biome_formatter::IndentStyle::Tab - } else { - biome_formatter::IndentStyle::Space - }; - - let formatter = biome_configuration::PartialFormatterConfiguration { - indent_width: Some(indent_width), - line_width: Some(line_width), - indent_style: Some(indent_style), - line_ending: Some(value.end_of_line.into()), - attribute_position: Some(AttributePosition::default()), - format_with_errors: Some(false), - ignore: None, - include: None, - enabled: Some(true), - // editorconfig support is intentionally set to true, because prettier always reads the editorconfig file - // see: https://github.com/prettier/prettier/issues/15255 - use_editorconfig: Some(true), - // deprecated - indent_size: None, - bracket_spacing: Some(BracketSpacing::default()), - }; - - result.formatter = Some(formatter); - - let semicolons = if value.semi { - Semicolons::Always - } else { - Semicolons::AsNeeded - }; - - let quote_style = if value.single_quote { - QuoteStyle::Single - } else { - QuoteStyle::Double - }; - - let jsx_quote_style = if value.jsx_single_quote { - QuoteStyle::Single - } else { - QuoteStyle::Double - }; - - let js_formatter = biome_configuration::PartialJavascriptFormatter { - indent_width: None, - line_width: None, - indent_style: None, - line_ending: None, - enabled: None, - // deprecated - indent_size: None, - - // js ones - bracket_same_line: Some(value.bracket_line), - arrow_parentheses: Some(value.arrow_parens.into()), - semicolons: Some(semicolons), - trailing_commas: Some(value.trailing_comma.into()), - // deprecated - trailing_comma: None, - quote_style: Some(quote_style), - quote_properties: Some(value.quote_props.into()), - bracket_spacing: Some(value.bracket_spacing.into()), - jsx_quote_style: Some(jsx_quote_style), - attribute_position: Some(AttributePosition::default()), - }; - - let js_config = biome_configuration::PartialJavascriptConfiguration { - formatter: Some(js_formatter), - ..Default::default() - }; - - result.javascript = Some(js_config); - - if !value.overrides.is_empty() { - let mut overrides = biome_configuration::Overrides::default(); - - for override_elt in value.overrides { - overrides.0.push(override_elt.try_into()?); - } - - result.overrides = Some(overrides); - } - - Ok(result) - } + type Error = ParseFormatNumberError; + + fn try_from(value:PrettierConfiguration) -> Result { + let mut result = biome_configuration::PartialConfiguration::default(); + + let line_width = LineWidth::try_from(value.print_width)?; + + let indent_width = IndentWidth::try_from(value.tab_width)?; + + let indent_style = if value.use_tabs { + biome_formatter::IndentStyle::Tab + } else { + biome_formatter::IndentStyle::Space + }; + + let formatter = biome_configuration::PartialFormatterConfiguration { + indent_width:Some(indent_width), + line_width:Some(line_width), + indent_style:Some(indent_style), + line_ending:Some(value.end_of_line.into()), + attribute_position:Some(AttributePosition::default()), + format_with_errors:Some(false), + ignore:None, + include:None, + enabled:Some(true), + // editorconfig support is intentionally set to true, because prettier always reads the + // editorconfig file see: https://github.com/prettier/prettier/issues/15255 + use_editorconfig:Some(true), + // deprecated + indent_size:None, + bracket_spacing:Some(BracketSpacing::default()), + }; + + result.formatter = Some(formatter); + + let semicolons = if value.semi { Semicolons::Always } else { Semicolons::AsNeeded }; + + let quote_style = if value.single_quote { QuoteStyle::Single } else { QuoteStyle::Double }; + + let jsx_quote_style = if value.jsx_single_quote { QuoteStyle::Single } else { QuoteStyle::Double }; + + let js_formatter = biome_configuration::PartialJavascriptFormatter { + indent_width:None, + line_width:None, + indent_style:None, + line_ending:None, + enabled:None, + // deprecated + indent_size:None, + + // js ones + bracket_same_line:Some(value.bracket_line), + arrow_parentheses:Some(value.arrow_parens.into()), + semicolons:Some(semicolons), + trailing_commas:Some(value.trailing_comma.into()), + // deprecated + trailing_comma:None, + quote_style:Some(quote_style), + quote_properties:Some(value.quote_props.into()), + bracket_spacing:Some(value.bracket_spacing.into()), + jsx_quote_style:Some(jsx_quote_style), + attribute_position:Some(AttributePosition::default()), + }; + + let js_config = + biome_configuration::PartialJavascriptConfiguration { formatter:Some(js_formatter), ..Default::default() }; + + result.javascript = Some(js_config); + + if !value.overrides.is_empty() { + let mut overrides = biome_configuration::Overrides::default(); + + for override_elt in value.overrides { + overrides.0.push(override_elt.try_into()?); + } + + result.overrides = Some(overrides); + } + + Ok(result) + } } impl TryFrom for biome_configuration::OverridePattern { - type Error = ParseFormatNumberError; - - fn try_from(Override { files, options }: Override) -> Result { - let mut result = biome_configuration::OverridePattern { - include: Some(StringSet::new(files.into_iter().collect())), - ..Default::default() - }; - - if options.print_width.is_some() - || options.use_tabs.is_some() - || options.tab_width.is_some() - || options.end_of_line.is_some() - { - // are global options are set - let line_width = if let Some(print_width) = options.print_width { - Some(LineWidth::try_from(print_width)?) - } else { - None - }; - // are global options are set - let indent_width = if let Some(indent_width) = options.tab_width { - Some(IndentWidth::try_from(indent_width)?) - } else { - None - }; - - let indent_style = options.use_tabs.map(|use_tabs| { - if use_tabs { - biome_formatter::IndentStyle::Tab - } else { - biome_formatter::IndentStyle::Space - } - }); - - let formatter = biome_configuration::OverrideFormatterConfiguration { - indent_width, - line_width, - indent_style, - line_ending: options.end_of_line.map(|end_of_line| end_of_line.into()), - ..Default::default() - }; - - result.formatter = Some(formatter); - } - - if options.semi.is_none() - && options.single_quote.is_none() - && options.jsx_single_quote.is_none() - && options.bracket_line.is_none() - && options.arrow_parens.is_none() - && options.trailing_comma.is_none() - && options.quote_props.is_none() - && options.bracket_spacing.is_none() - { - // no js option are set - return Ok(result); - } - // js config - let semicolons = options.semi.map(|semi| { - if semi { - Semicolons::Always - } else { - Semicolons::AsNeeded - } - }); - - let quote_style = options.single_quote.map(|single_quote| { - if single_quote { - QuoteStyle::Single - } else { - QuoteStyle::Double - } - }); - - let jsx_quote_style = options.jsx_single_quote.map(|jsx_single_quote| { - if jsx_single_quote { - QuoteStyle::Single - } else { - QuoteStyle::Double - } - }); - - let js_formatter = biome_configuration::PartialJavascriptFormatter { - bracket_same_line: options.bracket_line, - arrow_parentheses: options.arrow_parens.map(|arrow_parens| arrow_parens.into()), - semicolons, - trailing_commas: options - .trailing_comma - .map(|trailing_comma| trailing_comma.into()), - quote_style, - quote_properties: options.quote_props.map(|quote_props| quote_props.into()), - jsx_quote_style, - ..Default::default() - }; - - let js_config = biome_configuration::PartialJavascriptConfiguration { - formatter: Some(js_formatter), - ..Default::default() - }; - - result.javascript = Some(js_config); - - Ok(result) - } + type Error = ParseFormatNumberError; + + fn try_from(Override { files, options }:Override) -> Result { + let mut result = biome_configuration::OverridePattern { + include:Some(StringSet::new(files.into_iter().collect())), + ..Default::default() + }; + + if options.print_width.is_some() + || options.use_tabs.is_some() + || options.tab_width.is_some() + || options.end_of_line.is_some() + { + // are global options are set + let line_width = if let Some(print_width) = options.print_width { + Some(LineWidth::try_from(print_width)?) + } else { + None + }; + // are global options are set + let indent_width = if let Some(indent_width) = options.tab_width { + Some(IndentWidth::try_from(indent_width)?) + } else { + None + }; + + let indent_style = options.use_tabs.map(|use_tabs| { + if use_tabs { + biome_formatter::IndentStyle::Tab + } else { + biome_formatter::IndentStyle::Space + } + }); + + let formatter = biome_configuration::OverrideFormatterConfiguration { + indent_width, + line_width, + indent_style, + line_ending:options.end_of_line.map(|end_of_line| end_of_line.into()), + ..Default::default() + }; + + result.formatter = Some(formatter); + } + + if options.semi.is_none() + && options.single_quote.is_none() + && options.jsx_single_quote.is_none() + && options.bracket_line.is_none() + && options.arrow_parens.is_none() + && options.trailing_comma.is_none() + && options.quote_props.is_none() + && options.bracket_spacing.is_none() + { + // no js option are set + return Ok(result); + } + // js config + let semicolons = options + .semi + .map(|semi| if semi { Semicolons::Always } else { Semicolons::AsNeeded }); + + let quote_style = options.single_quote.map( + |single_quote| { + if single_quote { QuoteStyle::Single } else { QuoteStyle::Double } + }, + ); + + let jsx_quote_style = + options.jsx_single_quote.map( + |jsx_single_quote| { + if jsx_single_quote { QuoteStyle::Single } else { QuoteStyle::Double } + }, + ); + + let js_formatter = biome_configuration::PartialJavascriptFormatter { + bracket_same_line:options.bracket_line, + arrow_parentheses:options.arrow_parens.map(|arrow_parens| arrow_parens.into()), + semicolons, + trailing_commas:options.trailing_comma.map(|trailing_comma| trailing_comma.into()), + quote_style, + quote_properties:options.quote_props.map(|quote_props| quote_props.into()), + jsx_quote_style, + ..Default::default() + }; + + let js_config = + biome_configuration::PartialJavascriptConfiguration { formatter:Some(js_formatter), ..Default::default() }; + + result.javascript = Some(js_config); + + Ok(result) + } } /// A Prettier config can be embedded in `package.json` -const PACKAGE_JSON: &str = "package.json"; +const PACKAGE_JSON:&str = "package.json"; /// Prettie config files ordered by precedence -const CONFIG_FILES: [&str; 8] = [ - ".prettierrc", - ".prettierrc.json", - // Prefixed with `./` to ensure that it is loadable via Node.js's `import()` - "./.prettierrc.js", - "./prettier.config.js", - "./.prettierrc.mjs", - "./prettier.config.mjs", - "./.prettierrc.cjs", - "./prettier.config.cjs", +const CONFIG_FILES:[&str; 8] = [ + ".prettierrc", + ".prettierrc.json", + // Prefixed with `./` to ensure that it is loadable via Node.js's `import()` + "./.prettierrc.js", + "./prettier.config.js", + "./.prettierrc.mjs", + "./prettier.config.mjs", + "./.prettierrc.cjs", + "./prettier.config.cjs", ]; /// Prettier Ignore file. Use the same syntax as gitignore. -pub(crate) const IGNORE_FILE: &str = ".prettierignore"; +pub(crate) const IGNORE_FILE:&str = ".prettierignore"; -/// This function is in charge of reading prettier files, deserialize its contents +/// This function is in charge of reading prettier files, deserialize its +/// contents pub(crate) fn read_config_file( - fs: &DynRef<'_, dyn FileSystem>, - console: &mut dyn Console, + fs:&DynRef<'_, dyn FileSystem>, + console:&mut dyn Console, ) -> Result { - // We don't report an error if Prettier config is not embedded in `PACKAGE_JSON`. - if let Ok(data) = load_config(fs, Path::new(PACKAGE_JSON), console) { - return Ok(Config { - path: PACKAGE_JSON, - data, - }); - } - - for config_name in CONFIG_FILES { - let path = Path::new(config_name); - - if fs.path_exists(path) { - return Ok(Config { - path: config_name, - data: load_config(fs, path, console)?, - }); - } - } - - Err(CliDiagnostic::MigrateError(MigrationDiagnostic { - reason: "Biome couldn't find a Prettier configuration file.".to_string(), - })) + // We don't report an error if Prettier config is not embedded in + // `PACKAGE_JSON`. + if let Ok(data) = load_config(fs, Path::new(PACKAGE_JSON), console) { + return Ok(Config { path:PACKAGE_JSON, data }); + } + + for config_name in CONFIG_FILES { + let path = Path::new(config_name); + + if fs.path_exists(path) { + return Ok(Config { path:config_name, data:load_config(fs, path, console)? }); + } + } + + Err(CliDiagnostic::MigrateError(MigrationDiagnostic { + reason:"Biome couldn't find a Prettier configuration file.".to_string(), + })) } fn load_config( - fs: &DynRef<'_, dyn FileSystem>, - path: &Path, - console: &mut dyn Console, + fs:&DynRef<'_, dyn FileSystem>, + path:&Path, + console:&mut dyn Console, ) -> Result { - let (deserialized, diagnostics) = match path.extension().and_then(OsStr::to_str) { - None | Some("json") => { - let mut file = fs.open_with_options(path, OpenOptions::default().read(true))?; - - let mut content = String::new(); - - file.read_to_string(&mut content)?; - - if path.file_name().is_some_and(|name| name == PACKAGE_JSON) { - let (deserialized, _) = deserialize_from_json_str::( - &content, - JsonParserOptions::default() - .with_allow_trailing_commas() - .with_allow_comments(), - "", - ) - .consume(); - ( - deserialized.and_then(|packagejson| packagejson.prettier), - vec![], - ) - } else { - deserialize_from_json_str::( - &content, - JsonParserOptions::default() - .with_allow_trailing_commas() - .with_allow_comments(), - "", - ) - .consume() - } - } - - Some("js" | "mjs" | "cjs") => { - let node::Resolution { content, .. } = node::load_config(&path.to_string_lossy())?; - - deserialize_from_json_str::( - &content, - JsonParserOptions::default(), - "", - ) - .consume() - } - - Some(ext) => { - return Err(CliDiagnostic::MigrateError(MigrationDiagnostic { - reason: format!( - "Prettier configuration ending with the extension `{ext}` are not supported." - ), - })) - } - }; - - let path_str = path.to_string_lossy(); - // Heuristic: the Prettier config file is considered a YAML file if: - // - desrialization failed - // - there are at least 3 diagnostics - // - the configuration file has no extension. - // In this case we skip emitting the diagnostics - if !(deserialized.is_none() && diagnostics.len() > 2 || path.extension().is_none()) { - for diagnostic in diagnostics.into_iter().filter(|diag| { - matches!( - diag.severity(), - biome_diagnostics::Severity::Fatal - | biome_diagnostics::Severity::Error - | biome_diagnostics::Severity::Warning - ) - }) { - let diagnostic = diagnostic.with_file_path(path_str.to_string()); - - console.error(markup! {{PrintDiagnostic::simple(&diagnostic)}}); - } - } - - if let Some(result) = deserialized { - if result.end_of_line == EndOfLine::Auto { - console.log(markup! { + let (deserialized, diagnostics) = match path.extension().and_then(OsStr::to_str) { + None | Some("json") => { + let mut file = fs.open_with_options(path, OpenOptions::default().read(true))?; + + let mut content = String::new(); + + file.read_to_string(&mut content)?; + + if path.file_name().is_some_and(|name| name == PACKAGE_JSON) { + let (deserialized, _) = deserialize_from_json_str::( + &content, + JsonParserOptions::default().with_allow_trailing_commas().with_allow_comments(), + "", + ) + .consume(); + (deserialized.and_then(|packagejson| packagejson.prettier), vec![]) + } else { + deserialize_from_json_str::( + &content, + JsonParserOptions::default().with_allow_trailing_commas().with_allow_comments(), + "", + ) + .consume() + } + }, + + Some("js" | "mjs" | "cjs") => { + let node::Resolution { content, .. } = node::load_config(&path.to_string_lossy())?; + + deserialize_from_json_str::(&content, JsonParserOptions::default(), "").consume() + }, + + Some(ext) => { + return Err(CliDiagnostic::MigrateError(MigrationDiagnostic { + reason:format!("Prettier configuration ending with the extension `{ext}` are not supported."), + })); + }, + }; + + let path_str = path.to_string_lossy(); + // Heuristic: the Prettier config file is considered a YAML file if: + // - desrialization failed + // - there are at least 3 diagnostics + // - the configuration file has no extension. + // In this case we skip emitting the diagnostics + if !(deserialized.is_none() && diagnostics.len() > 2 || path.extension().is_none()) { + for diagnostic in diagnostics.into_iter().filter(|diag| { + matches!( + diag.severity(), + biome_diagnostics::Severity::Fatal + | biome_diagnostics::Severity::Error + | biome_diagnostics::Severity::Warning + ) + }) { + let diagnostic = diagnostic.with_file_path(path_str.to_string()); + + console.error(markup! {{PrintDiagnostic::simple(&diagnostic)}}); + } + } + + if let Some(result) = deserialized { + if result.end_of_line == EndOfLine::Auto { + console.log(markup! { "Prettier's `\"endOfLine\": \"auto\"` option is not supported in Biome. The default `\"lf\"` option is used instead." }); - } - - Ok(result) - } else if path.extension().is_none() { - // The Prettier config file may be a YAML file. - Err(CliDiagnostic::MigrateError(MigrationDiagnostic { - reason: "Could not deserialize the Prettier configuration file.\nOnly JSON configurations are supported.".to_string(), - })) - } else { - Err(CliDiagnostic::MigrateError(MigrationDiagnostic { - reason: "Could not deserialize the Prettier configuration file".to_string(), - })) - } + } + + Ok(result) + } else if path.extension().is_none() { + // The Prettier config file may be a YAML file. + Err(CliDiagnostic::MigrateError(MigrationDiagnostic { + reason:"Could not deserialize the Prettier configuration file.\nOnly JSON configurations are supported." + .to_string(), + })) + } else { + Err(CliDiagnostic::MigrateError(MigrationDiagnostic { + reason:"Could not deserialize the Prettier configuration file".to_string(), + })) + } } #[cfg(test)] mod tests { - use crate::execute::migrate::prettier::{PrettierConfiguration, PrettierTrailingComma}; - - use biome_deserialize::json::deserialize_from_json_str; - - use biome_json_parser::JsonParserOptions; - - #[test] - fn ok() { - let configuration = deserialize_from_json_str::( - r#"{ "useTabs": true }"#, - JsonParserOptions::default(), - "", - ) - .into_deserialized() - .unwrap(); - - assert!(matches!( - configuration, - PrettierConfiguration { use_tabs: true, .. } - )) - } - - #[test] - fn some_properties() { - let configuration = deserialize_from_json_str::( - r#" + use biome_deserialize::json::deserialize_from_json_str; + use biome_json_parser::JsonParserOptions; + + use crate::execute::migrate::prettier::{PrettierConfiguration, PrettierTrailingComma}; + + #[test] + fn ok() { + let configuration = deserialize_from_json_str::( + r#"{ "useTabs": true }"#, + JsonParserOptions::default(), + "", + ) + .into_deserialized() + .unwrap(); + + assert!(matches!(configuration, PrettierConfiguration { use_tabs:true, .. })) + } + + #[test] + fn some_properties() { + let configuration = deserialize_from_json_str::( + r#" { "printWidth": 100, "semi": true, @@ -577,24 +536,24 @@ mod tests { "jsxSingleQuote": true } "#, - JsonParserOptions::default(), - "", - ) - .into_deserialized() - .unwrap(); - - assert!(matches!( - configuration, - PrettierConfiguration { - use_tabs: true, - print_width: 100, - semi: true, - single_quote: true, - tab_width: 2, - trailing_comma: PrettierTrailingComma::Es5, - jsx_single_quote: true, - .. - } - )) - } + JsonParserOptions::default(), + "", + ) + .into_deserialized() + .unwrap(); + + assert!(matches!( + configuration, + PrettierConfiguration { + use_tabs:true, + print_width:100, + semi:true, + single_quote:true, + tab_width:2, + trailing_comma:PrettierTrailingComma::Es5, + jsx_single_quote:true, + .. + } + )) + } } diff --git a/crates/biome_cli/Source/execute/mod.rs b/crates/biome_cli/Source/execute/mod.rs index 2d17190febad..ac5c048426c6 100644 --- a/crates/biome_cli/Source/execute/mod.rs +++ b/crates/biome_cli/Source/execute/mod.rs @@ -4,623 +4,592 @@ mod process_file; mod std_in; pub(crate) mod traverse; -use crate::cli_options::{CliOptions, CliReporter}; -use crate::commands::MigrateSubCommand; -use crate::diagnostics::ReportDiagnostic; -use crate::execute::migrate::MigratePayload; -use crate::execute::traverse::{traverse, TraverseResult}; -use crate::reporter::github::{GithubReporter, GithubReporterVisitor}; -use crate::reporter::gitlab::{GitLabReporter, GitLabReporterVisitor}; -use crate::reporter::json::{JsonReporter, JsonReporterVisitor}; -use crate::reporter::junit::{JunitReporter, JunitReporterVisitor}; -use crate::reporter::summary::{SummaryReporter, SummaryReporterVisitor}; -use crate::reporter::terminal::{ConsoleReporter, ConsoleReporterVisitor}; -use crate::{CliDiagnostic, CliSession, DiagnosticsPayload, Reporter}; +use std::{ + borrow::Borrow, + ffi::OsString, + fmt::{Display, Formatter}, + path::{Path, PathBuf}, +}; + use biome_configuration::analyzer::RuleSelector; -use biome_console::{markup, ConsoleExt}; -use biome_diagnostics::adapters::SerdeJsonError; -use biome_diagnostics::{category, Category}; +use biome_console::{ConsoleExt, markup}; +use biome_diagnostics::{Category, adapters::SerdeJsonError, category}; use biome_fs::BiomePath; use biome_service::workspace::{ - FeatureName, FeaturesBuilder, FixFileMode, FormatFileParams, OpenFileParams, PatternId, + FeatureName, + FeaturesBuilder, + FixFileMode, + FormatFileParams, + OpenFileParams, + PatternId, }; -use std::borrow::Borrow; -use std::ffi::OsString; -use std::fmt::{Display, Formatter}; -use std::path::{Path, PathBuf}; use tracing::info; +use crate::{ + CliDiagnostic, + CliSession, + DiagnosticsPayload, + Reporter, + cli_options::{CliOptions, CliReporter}, + commands::MigrateSubCommand, + diagnostics::ReportDiagnostic, + execute::{ + migrate::MigratePayload, + traverse::{TraverseResult, traverse}, + }, + reporter::{ + github::{GithubReporter, GithubReporterVisitor}, + gitlab::{GitLabReporter, GitLabReporterVisitor}, + json::{JsonReporter, JsonReporterVisitor}, + junit::{JunitReporter, JunitReporterVisitor}, + summary::{SummaryReporter, SummaryReporterVisitor}, + terminal::{ConsoleReporter, ConsoleReporterVisitor}, + }, +}; + /// Useful information during the traversal of files and virtual content #[derive(Debug, Clone)] pub struct Execution { - /// How the information should be collected and reported - report_mode: ReportMode, + /// How the information should be collected and reported + report_mode:ReportMode, - /// The modality of execution of the traversal - traversal_mode: TraversalMode, + /// The modality of execution of the traversal + traversal_mode:TraversalMode, - /// The maximum number of diagnostics that can be printed in console - max_diagnostics: u32, + /// The maximum number of diagnostics that can be printed in console + max_diagnostics:u32, } impl Execution { - pub fn new_format(vcs_targeted: VcsTargeted) -> Self { - Self { - traversal_mode: TraversalMode::Format { - ignore_errors: false, - write: false, - stdin: None, - vcs_targeted, - }, - report_mode: ReportMode::default(), - max_diagnostics: 0, - } - } - - pub fn report_mode(&self) -> &ReportMode { - &self.report_mode - } + pub fn new_format(vcs_targeted:VcsTargeted) -> Self { + Self { + traversal_mode:TraversalMode::Format { ignore_errors:false, write:false, stdin:None, vcs_targeted }, + report_mode:ReportMode::default(), + max_diagnostics:0, + } + } + + pub fn report_mode(&self) -> &ReportMode { &self.report_mode } } impl Execution { - pub(crate) fn to_feature(&self) -> FeatureName { - match self.traversal_mode { - TraversalMode::Format { .. } => FeaturesBuilder::new().with_formatter().build(), - TraversalMode::Lint { .. } => FeaturesBuilder::new().with_linter().build(), - TraversalMode::Check { .. } | TraversalMode::CI { .. } => FeaturesBuilder::new() - .with_organize_imports() - .with_formatter() - .with_linter() - .with_assists() - .build(), - TraversalMode::Migrate { .. } => FeatureName::empty(), - TraversalMode::Search { .. } => FeaturesBuilder::new().with_search().build(), - } - } + pub(crate) fn to_feature(&self) -> FeatureName { + match self.traversal_mode { + TraversalMode::Format { .. } => FeaturesBuilder::new().with_formatter().build(), + TraversalMode::Lint { .. } => FeaturesBuilder::new().with_linter().build(), + TraversalMode::Check { .. } | TraversalMode::CI { .. } => { + FeaturesBuilder::new() + .with_organize_imports() + .with_formatter() + .with_linter() + .with_assists() + .build() + }, + TraversalMode::Migrate { .. } => FeatureName::empty(), + TraversalMode::Search { .. } => FeaturesBuilder::new().with_search().build(), + } + } } #[derive(Debug, Clone, Copy)] pub enum ExecutionEnvironment { - GitHub, + GitHub, } /// A type that holds the information to execute the CLI via `stdin #[derive(Debug, Clone)] pub struct Stdin( - /// The virtual path to the file - PathBuf, - /// The content of the file - String, + /// The virtual path to the file + PathBuf, + /// The content of the file + String, ); impl Stdin { - fn as_path(&self) -> &Path { - self.0.as_path() - } + fn as_path(&self) -> &Path { self.0.as_path() } - fn as_content(&self) -> &str { - self.1.as_str() - } + fn as_content(&self) -> &str { self.1.as_str() } } impl From<(PathBuf, String)> for Stdin { - fn from((path, content): (PathBuf, String)) -> Self { - Self(path, content) - } + fn from((path, content):(PathBuf, String)) -> Self { Self(path, content) } } #[derive(Debug, Clone)] pub struct VcsTargeted { - pub staged: bool, - pub changed: bool, + pub staged:bool, + pub changed:bool, } impl From<(bool, bool)> for VcsTargeted { - fn from((staged, changed): (bool, bool)) -> Self { - Self { staged, changed } - } + fn from((staged, changed):(bool, bool)) -> Self { Self { staged, changed } } } #[derive(Debug, Clone)] pub enum TraversalMode { - /// This mode is enabled when running the command `biome check` - Check { - /// The type of fixes that should be applied when analyzing a file. - /// - /// It's [None] if the `check` command is called without `--apply` or `--apply-suggested` - /// arguments. - fix_file_mode: Option, - /// An optional tuple. - /// 1. The virtual path to the file - /// 2. The content of the file - stdin: Option, - /// A flag to know vcs integrated options such as `--staged` or `--changed` are enabled - vcs_targeted: VcsTargeted, - }, - /// This mode is enabled when running the command `biome lint` - Lint { - /// The type of fixes that should be applied when analyzing a file. - /// - /// It's [None] if the `check` command is called without `--apply` or `--apply-suggested` - /// arguments. - fix_file_mode: Option, - /// An optional tuple. - /// 1. The virtual path to the file - /// 2. The content of the file - stdin: Option, - /// Run only the given rule or group of rules. - /// If the severity level of a rule is `off`, - /// then the severity level of the rule is set to `error` if it is a recommended rule or `warn` otherwise. - only: Vec, - /// Skip the given rule or group of rules by setting the severity level of the rules to `off`. - /// This option takes precedence over `--only`. - skip: Vec, - /// A flag to know vcs integrated options such as `--staged` or `--changed` are enabled - vcs_targeted: VcsTargeted, - /// Supress existing diagnostics with a `// biome-ignore` comment - suppress: bool, - /// Explanation for suppressing diagnostics with `--suppress` and `--reason` - suppression_reason: Option, - }, - /// This mode is enabled when running the command `biome ci` - CI { - /// Whether the CI is running in a specific environment, e.g. GitHub, GitLab, etc. - environment: Option, - /// A flag to know vcs integrated options such as `--staged` or `--changed` are enabled - vcs_targeted: VcsTargeted, - }, - /// This mode is enabled when running the command `biome format` - Format { - /// It ignores parse errors - ignore_errors: bool, - /// It writes the new content on file - write: bool, - /// An optional tuple. - /// 1. The virtual path to the file - /// 2. The content of the file - stdin: Option, - /// A flag to know vcs integrated options such as `--staged` or `--changed` are enabled - vcs_targeted: VcsTargeted, - }, - /// This mode is enabled when running the command `biome migrate` - Migrate { - /// Write result to disk - write: bool, - /// The path to `biome.json` - configuration_file_path: PathBuf, - /// The path directory where `biome.json` is placed - configuration_directory_path: PathBuf, - sub_command: Option, - }, - /// This mode is enabled when running the command `biome search` - Search { - /// The GritQL pattern to search for. - /// - /// Note that the search command does not support rewrites. - pattern: PatternId, - - /// An optional tuple. - /// 1. The virtual path to the file - /// 2. The content of the file - stdin: Option, - }, + /// This mode is enabled when running the command `biome check` + Check { + /// The type of fixes that should be applied when analyzing a file. + /// + /// It's [None] if the `check` command is called without `--apply` or + /// `--apply-suggested` arguments. + fix_file_mode:Option, + /// An optional tuple. + /// 1. The virtual path to the file + /// 2. The content of the file + stdin:Option, + /// A flag to know vcs integrated options such as `--staged` or + /// `--changed` are enabled + vcs_targeted:VcsTargeted, + }, + /// This mode is enabled when running the command `biome lint` + Lint { + /// The type of fixes that should be applied when analyzing a file. + /// + /// It's [None] if the `check` command is called without `--apply` or + /// `--apply-suggested` arguments. + fix_file_mode:Option, + /// An optional tuple. + /// 1. The virtual path to the file + /// 2. The content of the file + stdin:Option, + /// Run only the given rule or group of rules. + /// If the severity level of a rule is `off`, + /// then the severity level of the rule is set to `error` if it is a + /// recommended rule or `warn` otherwise. + only:Vec, + /// Skip the given rule or group of rules by setting the severity level + /// of the rules to `off`. This option takes precedence over `--only`. + skip:Vec, + /// A flag to know vcs integrated options such as `--staged` or + /// `--changed` are enabled + vcs_targeted:VcsTargeted, + /// Supress existing diagnostics with a `// biome-ignore` comment + suppress:bool, + /// Explanation for suppressing diagnostics with `--suppress` and + /// `--reason` + suppression_reason:Option, + }, + /// This mode is enabled when running the command `biome ci` + CI { + /// Whether the CI is running in a specific environment, e.g. GitHub, + /// GitLab, etc. + environment:Option, + /// A flag to know vcs integrated options such as `--staged` or + /// `--changed` are enabled + vcs_targeted:VcsTargeted, + }, + /// This mode is enabled when running the command `biome format` + Format { + /// It ignores parse errors + ignore_errors:bool, + /// It writes the new content on file + write:bool, + /// An optional tuple. + /// 1. The virtual path to the file + /// 2. The content of the file + stdin:Option, + /// A flag to know vcs integrated options such as `--staged` or + /// `--changed` are enabled + vcs_targeted:VcsTargeted, + }, + /// This mode is enabled when running the command `biome migrate` + Migrate { + /// Write result to disk + write:bool, + /// The path to `biome.json` + configuration_file_path:PathBuf, + /// The path directory where `biome.json` is placed + configuration_directory_path:PathBuf, + sub_command:Option, + }, + /// This mode is enabled when running the command `biome search` + Search { + /// The GritQL pattern to search for. + /// + /// Note that the search command does not support rewrites. + pattern:PatternId, + + /// An optional tuple. + /// 1. The virtual path to the file + /// 2. The content of the file + stdin:Option, + }, } impl Display for TraversalMode { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - TraversalMode::Check { .. } => write!(f, "check"), - TraversalMode::CI { .. } => write!(f, "ci"), - TraversalMode::Format { .. } => write!(f, "format"), - TraversalMode::Migrate { .. } => write!(f, "migrate"), - TraversalMode::Lint { .. } => write!(f, "lint"), - TraversalMode::Search { .. } => write!(f, "search"), - } - } + fn fmt(&self, f:&mut Formatter<'_>) -> std::fmt::Result { + match self { + TraversalMode::Check { .. } => write!(f, "check"), + TraversalMode::CI { .. } => write!(f, "ci"), + TraversalMode::Format { .. } => write!(f, "format"), + TraversalMode::Migrate { .. } => write!(f, "migrate"), + TraversalMode::Lint { .. } => write!(f, "lint"), + TraversalMode::Search { .. } => write!(f, "search"), + } + } } -/// Tells to the execution of the traversal how the information should be reported +/// Tells to the execution of the traversal how the information should be +/// reported #[derive(Copy, Clone, Debug)] pub enum ReportMode { - /// Reports information straight to the console, it's the default mode - Terminal { with_summary: bool }, - /// Reports information in JSON format - Json { pretty: bool }, - /// Reports information for GitHub - GitHub, - /// JUnit output - /// Ref: https://github.com/testmoapp/junitxml?tab=readme-ov-file#basic-junit-xml-structure - Junit, - /// Reports information in the [GitLab Code Quality](https://docs.gitlab.com/ee/ci/testing/code_quality.html#implement-a-custom-tool) format. - GitLab, + /// Reports information straight to the console, it's the default mode + Terminal { with_summary:bool }, + /// Reports information in JSON format + Json { pretty:bool }, + /// Reports information for GitHub + GitHub, + /// JUnit output + /// Ref: https://github.com/testmoapp/junitxml?tab=readme-ov-file#basic-junit-xml-structure + Junit, + /// Reports information in the [GitLab Code Quality](https://docs.gitlab.com/ee/ci/testing/code_quality.html#implement-a-custom-tool) format. + GitLab, } impl Default for ReportMode { - fn default() -> Self { - Self::Terminal { - with_summary: false, - } - } + fn default() -> Self { Self::Terminal { with_summary:false } } } impl From for ReportMode { - fn from(value: CliReporter) -> Self { - match value { - CliReporter::Default => Self::Terminal { - with_summary: false, - }, - CliReporter::Summary => Self::Terminal { with_summary: true }, - CliReporter::Json => Self::Json { pretty: false }, - CliReporter::JsonPretty => Self::Json { pretty: true }, - CliReporter::GitHub => Self::GitHub, - CliReporter::Junit => Self::Junit, - CliReporter::GitLab => Self::GitLab {}, - } - } + fn from(value:CliReporter) -> Self { + match value { + CliReporter::Default => Self::Terminal { with_summary:false }, + CliReporter::Summary => Self::Terminal { with_summary:true }, + CliReporter::Json => Self::Json { pretty:false }, + CliReporter::JsonPretty => Self::Json { pretty:true }, + CliReporter::GitHub => Self::GitHub, + CliReporter::Junit => Self::Junit, + CliReporter::GitLab => Self::GitLab {}, + } + } } impl Execution { - pub(crate) fn new(mode: TraversalMode) -> Self { - Self { - report_mode: ReportMode::default(), - traversal_mode: mode, - max_diagnostics: 20, - } - } - - pub(crate) fn new_ci(vcs_targeted: VcsTargeted) -> Self { - // Ref: https://docs.github.com/actions/learn-github-actions/variables#default-environment-variables - let is_github = std::env::var("GITHUB_ACTIONS") - .ok() - .map_or(false, |value| value == "true"); - - Self { - report_mode: ReportMode::default(), - traversal_mode: TraversalMode::CI { - environment: if is_github { - Some(ExecutionEnvironment::GitHub) - } else { - None - }, - vcs_targeted, - }, - max_diagnostics: 20, - } - } - - /// It sets the reporting mode by reading the [CliOptions] - pub(crate) fn set_report(mut self, cli_options: &CliOptions) -> Self { - self.report_mode = cli_options.reporter.clone().into(); - - self - } - - pub(crate) fn traversal_mode(&self) -> &TraversalMode { - &self.traversal_mode - } - - pub(crate) fn get_max_diagnostics(&self) -> u32 { - self.max_diagnostics - } - - /// `true` only when running the traversal in [TraversalMode::Check] and `should_fix` is `true` - pub(crate) fn as_fix_file_mode(&self) -> Option<&FixFileMode> { - match &self.traversal_mode { - TraversalMode::Check { fix_file_mode, .. } - | TraversalMode::Lint { fix_file_mode, .. } => fix_file_mode.as_ref(), - TraversalMode::Format { .. } - | TraversalMode::CI { .. } - | TraversalMode::Migrate { .. } - | TraversalMode::Search { .. } => None, - } - } - - pub(crate) fn as_diagnostic_category(&self) -> &'static Category { - match self.traversal_mode { - TraversalMode::Check { .. } => category!("check"), - TraversalMode::Lint { .. } => category!("lint"), - TraversalMode::CI { .. } => category!("ci"), - TraversalMode::Format { .. } => category!("format"), - TraversalMode::Migrate { .. } => category!("migrate"), - TraversalMode::Search { .. } => category!("search"), - } - } - - pub(crate) const fn is_ci(&self) -> bool { - matches!(self.traversal_mode, TraversalMode::CI { .. }) - } - - pub(crate) const fn is_search(&self) -> bool { - matches!(self.traversal_mode, TraversalMode::Search { .. }) - } - - pub(crate) const fn is_check(&self) -> bool { - matches!(self.traversal_mode, TraversalMode::Check { .. }) - } - - pub(crate) const fn is_lint(&self) -> bool { - matches!(self.traversal_mode, TraversalMode::Lint { .. }) - } - - pub(crate) const fn is_check_apply(&self) -> bool { - matches!( - self.traversal_mode, - TraversalMode::Check { - fix_file_mode: Some(FixFileMode::SafeFixes), - .. - } - ) - } - - pub(crate) const fn is_check_apply_unsafe(&self) -> bool { - matches!( - self.traversal_mode, - TraversalMode::Check { - fix_file_mode: Some(FixFileMode::SafeAndUnsafeFixes), - .. - } - ) - } - - pub(crate) const fn is_format(&self) -> bool { - matches!(self.traversal_mode, TraversalMode::Format { .. }) - } - - pub(crate) const fn is_format_write(&self) -> bool { - if let TraversalMode::Format { write, .. } = self.traversal_mode { - write - } else { - false - } - } - - /// Whether the traversal mode requires write access to files - pub(crate) const fn requires_write_access(&self) -> bool { - match self.traversal_mode { - TraversalMode::Check { fix_file_mode, .. } - | TraversalMode::Lint { fix_file_mode, .. } => fix_file_mode.is_some(), - TraversalMode::CI { .. } | TraversalMode::Search { .. } => false, - TraversalMode::Format { write, .. } | TraversalMode::Migrate { write, .. } => write, - } - } - - pub(crate) fn as_stdin_file(&self) -> Option<&Stdin> { - match &self.traversal_mode { - TraversalMode::Format { stdin, .. } - | TraversalMode::Lint { stdin, .. } - | TraversalMode::Check { stdin, .. } - | TraversalMode::Search { stdin, .. } => stdin.as_ref(), - TraversalMode::CI { .. } | TraversalMode::Migrate { .. } => None, - } - } - - pub(crate) fn is_vcs_targeted(&self) -> bool { - match &self.traversal_mode { - TraversalMode::Check { vcs_targeted, .. } - | TraversalMode::Lint { vcs_targeted, .. } - | TraversalMode::Format { vcs_targeted, .. } - | TraversalMode::CI { vcs_targeted, .. } => vcs_targeted.staged || vcs_targeted.changed, - TraversalMode::Migrate { .. } | TraversalMode::Search { .. } => false, - } - } - - /// Returns [true] if the user used the `--write`/`--fix` option - pub(crate) fn is_write(&self) -> bool { - match self.traversal_mode { - TraversalMode::Check { fix_file_mode, .. } => fix_file_mode.is_some(), - TraversalMode::Lint { fix_file_mode, .. } => fix_file_mode.is_some(), - TraversalMode::CI { .. } => false, - TraversalMode::Format { write, .. } => write, - TraversalMode::Migrate { write, .. } => write, - TraversalMode::Search { .. } => false, - } - } + pub(crate) fn new(mode:TraversalMode) -> Self { + Self { report_mode:ReportMode::default(), traversal_mode:mode, max_diagnostics:20 } + } + + pub(crate) fn new_ci(vcs_targeted:VcsTargeted) -> Self { + // Ref: https://docs.github.com/actions/learn-github-actions/variables#default-environment-variables + let is_github = std::env::var("GITHUB_ACTIONS").ok().map_or(false, |value| value == "true"); + + Self { + report_mode:ReportMode::default(), + traversal_mode:TraversalMode::CI { + environment:if is_github { Some(ExecutionEnvironment::GitHub) } else { None }, + vcs_targeted, + }, + max_diagnostics:20, + } + } + + /// It sets the reporting mode by reading the [CliOptions] + pub(crate) fn set_report(mut self, cli_options:&CliOptions) -> Self { + self.report_mode = cli_options.reporter.clone().into(); + + self + } + + pub(crate) fn traversal_mode(&self) -> &TraversalMode { &self.traversal_mode } + + pub(crate) fn get_max_diagnostics(&self) -> u32 { self.max_diagnostics } + + /// `true` only when running the traversal in [TraversalMode::Check] and + /// `should_fix` is `true` + pub(crate) fn as_fix_file_mode(&self) -> Option<&FixFileMode> { + match &self.traversal_mode { + TraversalMode::Check { fix_file_mode, .. } | TraversalMode::Lint { fix_file_mode, .. } => { + fix_file_mode.as_ref() + }, + TraversalMode::Format { .. } + | TraversalMode::CI { .. } + | TraversalMode::Migrate { .. } + | TraversalMode::Search { .. } => None, + } + } + + pub(crate) fn as_diagnostic_category(&self) -> &'static Category { + match self.traversal_mode { + TraversalMode::Check { .. } => category!("check"), + TraversalMode::Lint { .. } => category!("lint"), + TraversalMode::CI { .. } => category!("ci"), + TraversalMode::Format { .. } => category!("format"), + TraversalMode::Migrate { .. } => category!("migrate"), + TraversalMode::Search { .. } => category!("search"), + } + } + + pub(crate) const fn is_ci(&self) -> bool { matches!(self.traversal_mode, TraversalMode::CI { .. }) } + + pub(crate) const fn is_search(&self) -> bool { matches!(self.traversal_mode, TraversalMode::Search { .. }) } + + pub(crate) const fn is_check(&self) -> bool { matches!(self.traversal_mode, TraversalMode::Check { .. }) } + + pub(crate) const fn is_lint(&self) -> bool { matches!(self.traversal_mode, TraversalMode::Lint { .. }) } + + pub(crate) const fn is_check_apply(&self) -> bool { + matches!( + self.traversal_mode, + TraversalMode::Check { fix_file_mode:Some(FixFileMode::SafeFixes), .. } + ) + } + + pub(crate) const fn is_check_apply_unsafe(&self) -> bool { + matches!( + self.traversal_mode, + TraversalMode::Check { fix_file_mode:Some(FixFileMode::SafeAndUnsafeFixes), .. } + ) + } + + pub(crate) const fn is_format(&self) -> bool { matches!(self.traversal_mode, TraversalMode::Format { .. }) } + + pub(crate) const fn is_format_write(&self) -> bool { + if let TraversalMode::Format { write, .. } = self.traversal_mode { + write + } else { + false + } + } + + /// Whether the traversal mode requires write access to files + pub(crate) const fn requires_write_access(&self) -> bool { + match self.traversal_mode { + TraversalMode::Check { fix_file_mode, .. } | TraversalMode::Lint { fix_file_mode, .. } => { + fix_file_mode.is_some() + }, + TraversalMode::CI { .. } | TraversalMode::Search { .. } => false, + TraversalMode::Format { write, .. } | TraversalMode::Migrate { write, .. } => write, + } + } + + pub(crate) fn as_stdin_file(&self) -> Option<&Stdin> { + match &self.traversal_mode { + TraversalMode::Format { stdin, .. } + | TraversalMode::Lint { stdin, .. } + | TraversalMode::Check { stdin, .. } + | TraversalMode::Search { stdin, .. } => stdin.as_ref(), + TraversalMode::CI { .. } | TraversalMode::Migrate { .. } => None, + } + } + + pub(crate) fn is_vcs_targeted(&self) -> bool { + match &self.traversal_mode { + TraversalMode::Check { vcs_targeted, .. } + | TraversalMode::Lint { vcs_targeted, .. } + | TraversalMode::Format { vcs_targeted, .. } + | TraversalMode::CI { vcs_targeted, .. } => vcs_targeted.staged || vcs_targeted.changed, + TraversalMode::Migrate { .. } | TraversalMode::Search { .. } => false, + } + } + + /// Returns [true] if the user used the `--write`/`--fix` option + pub(crate) fn is_write(&self) -> bool { + match self.traversal_mode { + TraversalMode::Check { fix_file_mode, .. } => fix_file_mode.is_some(), + TraversalMode::Lint { fix_file_mode, .. } => fix_file_mode.is_some(), + TraversalMode::CI { .. } => false, + TraversalMode::Format { write, .. } => write, + TraversalMode::Migrate { write, .. } => write, + TraversalMode::Search { .. } => false, + } + } } -/// Based on the [mode](TraversalMode), the function might launch a traversal of the file system -/// or handles the stdin file. +/// Based on the [mode](TraversalMode), the function might launch a traversal of +/// the file system or handles the stdin file. pub fn execute_mode( - mut execution: Execution, - mut session: CliSession, - cli_options: &CliOptions, - paths: Vec, + mut execution:Execution, + mut session:CliSession, + cli_options:&CliOptions, + paths:Vec, ) -> Result<(), CliDiagnostic> { - // If a custom reporter was provided, let's lift the limit so users can see all of them - execution.max_diagnostics = if cli_options.reporter.is_default() { - cli_options.max_diagnostics.into() - } else { - info!("Removing the limit of --max-diagnostics, because of a reporter different from the default one: {}", cli_options.reporter); - - u32::MAX - }; - - // don't do any traversal if there's some content coming from stdin - if let Some(stdin) = execution.as_stdin_file() { - let biome_path = BiomePath::new(stdin.as_path()); - - std_in::run( - session, - &execution, - biome_path, - stdin.as_content(), - cli_options.verbose, - ) - } else if let TraversalMode::Migrate { - write, - configuration_file_path, - configuration_directory_path, - sub_command, - } = execution.traversal_mode - { - let payload = MigratePayload { - session, - write, - configuration_file_path, - configuration_directory_path, - verbose: cli_options.verbose, - sub_command, - }; - - migrate::run(payload) - } else { - let TraverseResult { - summary, - evaluated_paths, - diagnostics, - } = traverse(&execution, &mut session, cli_options, paths)?; - - let console = session.app.console; - - let errors = summary.errors; - - let skipped = summary.skipped; - - let processed = summary.changed + summary.unchanged; - - let should_exit_on_warnings = summary.warnings > 0 && cli_options.error_on_warnings; - - match execution.report_mode { - ReportMode::Terminal { with_summary } => { - if with_summary { - let reporter = SummaryReporter { - summary, - diagnostics_payload: DiagnosticsPayload { - verbose: cli_options.verbose, - diagnostic_level: cli_options.diagnostic_level, - diagnostics, - }, - execution: execution.clone(), - }; - - reporter.write(&mut SummaryReporterVisitor(console))?; - } else { - let reporter = ConsoleReporter { - summary, - diagnostics_payload: DiagnosticsPayload { - verbose: cli_options.verbose, - diagnostic_level: cli_options.diagnostic_level, - diagnostics, - }, - execution: execution.clone(), - evaluated_paths, - }; - - reporter.write(&mut ConsoleReporterVisitor(console))?; - } - } - - ReportMode::Json { pretty } => { - console.error(markup!{ + // If a custom reporter was provided, let's lift the limit so users can see all + // of them + execution.max_diagnostics = if cli_options.reporter.is_default() { + cli_options.max_diagnostics.into() + } else { + info!( + "Removing the limit of --max-diagnostics, because of a reporter different from the default one: {}", + cli_options.reporter + ); + + u32::MAX + }; + + // don't do any traversal if there's some content coming from stdin + if let Some(stdin) = execution.as_stdin_file() { + let biome_path = BiomePath::new(stdin.as_path()); + + std_in::run(session, &execution, biome_path, stdin.as_content(), cli_options.verbose) + } else if let TraversalMode::Migrate { write, configuration_file_path, configuration_directory_path, sub_command } = + execution.traversal_mode + { + let payload = MigratePayload { + session, + write, + configuration_file_path, + configuration_directory_path, + verbose:cli_options.verbose, + sub_command, + }; + + migrate::run(payload) + } else { + let TraverseResult { summary, evaluated_paths, diagnostics } = + traverse(&execution, &mut session, cli_options, paths)?; + + let console = session.app.console; + + let errors = summary.errors; + + let skipped = summary.skipped; + + let processed = summary.changed + summary.unchanged; + + let should_exit_on_warnings = summary.warnings > 0 && cli_options.error_on_warnings; + + match execution.report_mode { + ReportMode::Terminal { with_summary } => { + if with_summary { + let reporter = SummaryReporter { + summary, + diagnostics_payload:DiagnosticsPayload { + verbose:cli_options.verbose, + diagnostic_level:cli_options.diagnostic_level, + diagnostics, + }, + execution:execution.clone(), + }; + + reporter.write(&mut SummaryReporterVisitor(console))?; + } else { + let reporter = ConsoleReporter { + summary, + diagnostics_payload:DiagnosticsPayload { + verbose:cli_options.verbose, + diagnostic_level:cli_options.diagnostic_level, + diagnostics, + }, + execution:execution.clone(), + evaluated_paths, + }; + + reporter.write(&mut ConsoleReporterVisitor(console))?; + } + }, + + ReportMode::Json { pretty } => { + console.error(markup!{ "The ""--json"" option is ""unstable/experimental"" and its output might change between patches/minor releases." }); - let reporter = JsonReporter { - summary, - diagnostics: DiagnosticsPayload { - verbose: cli_options.verbose, - diagnostic_level: cli_options.diagnostic_level, - diagnostics, - }, - execution: execution.clone(), - }; - - let mut buffer = JsonReporterVisitor::new(summary); - - reporter.write(&mut buffer)?; - - if pretty { - let content = serde_json::to_string(&buffer).map_err(|error| { - CliDiagnostic::Report(ReportDiagnostic::Serialization( - SerdeJsonError::from(error), - )) - })?; - - let report_file = BiomePath::new("_report_output.json"); - - session.app.workspace.open_file(OpenFileParams { - content, - path: report_file.clone(), - version: 0, - document_file_source: None, - })?; - - let code = session.app.workspace.format_file(FormatFileParams { - path: report_file.clone(), - })?; - - console.log(markup! { - {code.as_code()} - }); - } else { - console.log(markup! { - {buffer} - }); - } - } - - ReportMode::GitHub => { - let reporter = GithubReporter { - diagnostics_payload: DiagnosticsPayload { - verbose: cli_options.verbose, - diagnostic_level: cli_options.diagnostic_level, - diagnostics, - }, - execution: execution.clone(), - }; - - reporter.write(&mut GithubReporterVisitor(console))?; - } - - ReportMode::GitLab => { - let reporter = GitLabReporter { - diagnostics: DiagnosticsPayload { - verbose: cli_options.verbose, - diagnostic_level: cli_options.diagnostic_level, - diagnostics, - }, - execution: execution.clone(), - }; - - reporter.write(&mut GitLabReporterVisitor::new( - console, - session.app.fs.borrow().working_directory(), - ))?; - } - - ReportMode::Junit => { - let reporter = JunitReporter { - summary, - diagnostics_payload: DiagnosticsPayload { - verbose: cli_options.verbose, - diagnostic_level: cli_options.diagnostic_level, - diagnostics, - }, - execution: execution.clone(), - }; - - reporter.write(&mut JunitReporterVisitor::new(console))?; - } - } - - // Processing emitted error diagnostics, exit with a non-zero code - if processed.saturating_sub(skipped) == 0 && !cli_options.no_errors_on_unmatched { - Err(CliDiagnostic::no_files_processed()) - } else if errors > 0 || should_exit_on_warnings { - let category = execution.as_diagnostic_category(); - - if should_exit_on_warnings { - if execution.is_check_apply() { - Err(CliDiagnostic::apply_warnings(category)) - } else { - Err(CliDiagnostic::check_warnings(category)) - } - } else if execution.is_check_apply() { - Err(CliDiagnostic::apply_error(category)) - } else { - Err(CliDiagnostic::check_error(category)) - } - } else { - Ok(()) - } - } + let reporter = JsonReporter { + summary, + diagnostics:DiagnosticsPayload { + verbose:cli_options.verbose, + diagnostic_level:cli_options.diagnostic_level, + diagnostics, + }, + execution:execution.clone(), + }; + + let mut buffer = JsonReporterVisitor::new(summary); + + reporter.write(&mut buffer)?; + + if pretty { + let content = serde_json::to_string(&buffer).map_err(|error| { + CliDiagnostic::Report(ReportDiagnostic::Serialization(SerdeJsonError::from(error))) + })?; + + let report_file = BiomePath::new("_report_output.json"); + + session.app.workspace.open_file(OpenFileParams { + content, + path:report_file.clone(), + version:0, + document_file_source:None, + })?; + + let code = session + .app + .workspace + .format_file(FormatFileParams { path:report_file.clone() })?; + + console.log(markup! { + {code.as_code()} + }); + } else { + console.log(markup! { + {buffer} + }); + } + }, + + ReportMode::GitHub => { + let reporter = GithubReporter { + diagnostics_payload:DiagnosticsPayload { + verbose:cli_options.verbose, + diagnostic_level:cli_options.diagnostic_level, + diagnostics, + }, + execution:execution.clone(), + }; + + reporter.write(&mut GithubReporterVisitor(console))?; + }, + + ReportMode::GitLab => { + let reporter = GitLabReporter { + diagnostics:DiagnosticsPayload { + verbose:cli_options.verbose, + diagnostic_level:cli_options.diagnostic_level, + diagnostics, + }, + execution:execution.clone(), + }; + + reporter.write(&mut GitLabReporterVisitor::new( + console, + session.app.fs.borrow().working_directory(), + ))?; + }, + + ReportMode::Junit => { + let reporter = JunitReporter { + summary, + diagnostics_payload:DiagnosticsPayload { + verbose:cli_options.verbose, + diagnostic_level:cli_options.diagnostic_level, + diagnostics, + }, + execution:execution.clone(), + }; + + reporter.write(&mut JunitReporterVisitor::new(console))?; + }, + } + + // Processing emitted error diagnostics, exit with a non-zero code + if processed.saturating_sub(skipped) == 0 && !cli_options.no_errors_on_unmatched { + Err(CliDiagnostic::no_files_processed()) + } else if errors > 0 || should_exit_on_warnings { + let category = execution.as_diagnostic_category(); + + if should_exit_on_warnings { + if execution.is_check_apply() { + Err(CliDiagnostic::apply_warnings(category)) + } else { + Err(CliDiagnostic::check_warnings(category)) + } + } else if execution.is_check_apply() { + Err(CliDiagnostic::apply_error(category)) + } else { + Err(CliDiagnostic::check_error(category)) + } + } else { + Ok(()) + } + } } diff --git a/crates/biome_cli/Source/execute/process_file.rs b/crates/biome_cli/Source/execute/process_file.rs index 3ddd62e81006..623f15267dec 100644 --- a/crates/biome_cli/Source/execute/process_file.rs +++ b/crates/biome_cli/Source/execute/process_file.rs @@ -6,90 +6,87 @@ mod organize_imports; mod search; pub(crate) mod workspace_file; -use crate::execute::diagnostics::{ResultExt, UnhandledDiagnostic}; -use crate::execute::traverse::TraversalOptions; -use crate::execute::TraversalMode; -use biome_diagnostics::{category, DiagnosticExt, DiagnosticTags, Error}; +use std::{marker::PhantomData, ops::Deref}; + +use biome_diagnostics::{DiagnosticExt, DiagnosticTags, Error, category}; use biome_fs::BiomePath; use biome_service::workspace::{FeatureKind, SupportKind, SupportsFeatureParams}; use check::check_file; use format::format; use lint::lint; use search::search; -use std::marker::PhantomData; -use std::ops::Deref; + +use crate::execute::{ + TraversalMode, + diagnostics::{ResultExt, UnhandledDiagnostic}, + traverse::TraversalOptions, +}; #[derive(Debug)] pub(crate) enum FileStatus { - /// File changed and it was a success - Changed, - /// File unchanged, and it was a success - Unchanged, - /// While handling the file, something happened - Message(Message), - /// A match was found while searching a file - SearchResult(usize, Message), - /// File ignored, it should not be count as "handled" - Ignored, - /// Files that belong to other tools and shouldn't be touched - Protected(String), + /// File changed and it was a success + Changed, + /// File unchanged, and it was a success + Unchanged, + /// While handling the file, something happened + Message(Message), + /// A match was found while searching a file + SearchResult(usize, Message), + /// File ignored, it should not be count as "handled" + Ignored, + /// Files that belong to other tools and shouldn't be touched + Protected(String), } impl FileStatus { - pub const fn is_changed(&self) -> bool { - matches!(self, Self::Changed) - } + pub const fn is_changed(&self) -> bool { matches!(self, Self::Changed) } } /// Wrapper type for messages that can be printed during the traversal process #[derive(Debug)] pub(crate) enum Message { - SkippedFixes { - /// Suggested fixes skipped during the lint traversal - skipped_suggested_fixes: u32, - }, - Failure, - Error(Error), - Diagnostics { - name: String, - content: String, - diagnostics: Vec, - skipped_diagnostics: u32, - }, - Diff { - file_name: String, - old: String, - new: String, - diff_kind: DiffKind, - }, + SkippedFixes { + /// Suggested fixes skipped during the lint traversal + skipped_suggested_fixes:u32, + }, + Failure, + Error(Error), + Diagnostics { + name:String, + content:String, + diagnostics:Vec, + skipped_diagnostics:u32, + }, + Diff { + file_name:String, + old:String, + new:String, + diff_kind:DiffKind, + }, } impl Message { - pub(crate) const fn is_failure(&self) -> bool { - matches!(self, Message::Failure) - } + pub(crate) const fn is_failure(&self) -> bool { matches!(self, Message::Failure) } } #[derive(Debug)] pub(crate) enum DiffKind { - Format, - OrganizeImports, - Assists, + Format, + OrganizeImports, + Assists, } impl From for Message where - Error: From, - D: std::fmt::Debug, + Error: From, + D: std::fmt::Debug, { - fn from(err: D) -> Self { - Self::Error(Error::from(err)) - } + fn from(err:D) -> Self { Self::Error(Error::from(err)) } } /// The return type for [process_file], with the following semantics: -/// - `Ok(Success)` means the operation was successful (the file is added to -/// the `processed` counter) +/// - `Ok(Success)` means the operation was successful (the file is added to the +/// `processed` counter) /// - `Ok(Message(_))` means the operation was successful but a message still /// needs to be printed (eg. the diff when not in CI or write mode) /// - `Ok(Ignored)` means the file was ignored (the file is not added to the @@ -98,28 +95,22 @@ where /// `skipped` counter pub(crate) type FileResult = Result; -/// Data structure that allows to pass [TraversalOptions] to multiple consumers, bypassing the -/// compiler constraints set by the lifetimes of the [TraversalOptions] +/// Data structure that allows to pass [TraversalOptions] to multiple consumers, +/// bypassing the compiler constraints set by the lifetimes of the +/// [TraversalOptions] pub(crate) struct SharedTraversalOptions<'ctx, 'app> { - inner: &'app TraversalOptions<'ctx, 'app>, - _p: PhantomData<&'app ()>, + inner:&'app TraversalOptions<'ctx, 'app>, + _p:PhantomData<&'app ()>, } impl<'ctx, 'app> SharedTraversalOptions<'ctx, 'app> { - fn new(t: &'app TraversalOptions<'ctx, 'app>) -> Self { - Self { - _p: PhantomData, - inner: t, - } - } + fn new(t:&'app TraversalOptions<'ctx, 'app>) -> Self { Self { _p:PhantomData, inner:t } } } impl<'ctx, 'app> Deref for SharedTraversalOptions<'ctx, 'app> { - type Target = TraversalOptions<'ctx, 'app>; + type Target = TraversalOptions<'ctx, 'app>; - fn deref(&self) -> &Self::Target { - self.inner - } + fn deref(&self) -> &Self::Target { self.inner } } /// This function performs the actual processing: it reads the file from disk @@ -127,122 +118,101 @@ impl<'ctx, 'app> Deref for SharedTraversalOptions<'ctx, 'app> { /// diagnostics were emitted, or compare the formatted code with the original /// content of the file and emit a diff or write the new content to the disk if /// write mode is enabled -pub(crate) fn process_file(ctx: &TraversalOptions, biome_path: &BiomePath) -> FileResult { - tracing::trace_span!("process_file", path = ?biome_path).in_scope(move || { - let file_features = ctx - .workspace - .file_features(SupportsFeatureParams { - path: biome_path.clone(), - features: ctx.execution.to_feature(), - }) - .with_file_path_and_code_and_tags( - biome_path.display().to_string(), - category!("files/missingHandler"), - DiagnosticTags::VERBOSE, - )?; - - // first we stop if there are some files that don't have ALL features enabled, e.g. images, fonts, etc. - if file_features.is_ignored() || file_features.is_not_enabled() { - return Ok(FileStatus::Ignored); - } else if file_features.is_not_supported() { - return Err(Message::from( - UnhandledDiagnostic.with_file_path(biome_path.display().to_string()), - )); - } - - // then we pick the specific features for this file - let unsupported_reason = match ctx.execution.traversal_mode() { - TraversalMode::Check { .. } | TraversalMode::CI { .. } => file_features - .support_kind_for(&FeatureKind::Lint) - .and_then(|support_kind| { - if support_kind.is_not_enabled() { - Some(support_kind) - } else { - None - } - }) - .and( - file_features - .support_kind_for(&FeatureKind::Format) - .and_then(|support_kind| { - if support_kind.is_not_enabled() { - Some(support_kind) - } else { - None - } - }), - ) - .and( - file_features - .support_kind_for(&FeatureKind::OrganizeImports) - .and_then(|support_kind| { - if support_kind.is_not_enabled() { - Some(support_kind) - } else { - None - } - }), - ), - TraversalMode::Format { .. } => file_features.support_kind_for(&FeatureKind::Format), - TraversalMode::Lint { .. } => file_features.support_kind_for(&FeatureKind::Lint), - TraversalMode::Migrate { .. } => None, - TraversalMode::Search { .. } => file_features.support_kind_for(&FeatureKind::Search), - }; - - if let Some(reason) = unsupported_reason { - match reason { - SupportKind::FileNotSupported => { - return Err(Message::from( - UnhandledDiagnostic.with_file_path(biome_path.display().to_string()), - )); - } - - SupportKind::FeatureNotEnabled | SupportKind::Ignored => { - return Ok(FileStatus::Ignored); - } - - SupportKind::Protected => { - return Ok(FileStatus::Protected(biome_path.display().to_string())); - } - - SupportKind::Supported => {} - }; - } - - let shared_context = &SharedTraversalOptions::new(ctx); - - match ctx.execution.traversal_mode { - TraversalMode::Lint { - ref suppression_reason, - suppress, - .. - } => { - // the unsupported case should be handled already at this point - lint( - shared_context, - biome_path, - suppress, - suppression_reason.as_deref(), - ) - } - - TraversalMode::Format { .. } => { - // the unsupported case should be handled already at this point - format(shared_context, biome_path) - } - - TraversalMode::Check { .. } | TraversalMode::CI { .. } => { - check_file(shared_context, biome_path, &file_features) - } - - TraversalMode::Migrate { .. } => { - unreachable!("The migration should not be called for this file") - } - - TraversalMode::Search { ref pattern, .. } => { - // the unsupported case should be handled already at this point - search(shared_context, biome_path, pattern) - } - } - }) +pub(crate) fn process_file(ctx:&TraversalOptions, biome_path:&BiomePath) -> FileResult { + tracing::trace_span!("process_file", path = ?biome_path).in_scope(move || { + let file_features = ctx + .workspace + .file_features(SupportsFeatureParams { path:biome_path.clone(), features:ctx.execution.to_feature() }) + .with_file_path_and_code_and_tags( + biome_path.display().to_string(), + category!("files/missingHandler"), + DiagnosticTags::VERBOSE, + )?; + + // first we stop if there are some files that don't have ALL features enabled, + // e.g. images, fonts, etc. + if file_features.is_ignored() || file_features.is_not_enabled() { + return Ok(FileStatus::Ignored); + } else if file_features.is_not_supported() { + return Err(Message::from( + UnhandledDiagnostic.with_file_path(biome_path.display().to_string()), + )); + } + + // then we pick the specific features for this file + let unsupported_reason = match ctx.execution.traversal_mode() { + TraversalMode::Check { .. } | TraversalMode::CI { .. } => { + file_features + .support_kind_for(&FeatureKind::Lint) + .and_then( + |support_kind| { + if support_kind.is_not_enabled() { Some(support_kind) } else { None } + }, + ) + .and(file_features.support_kind_for(&FeatureKind::Format).and_then(|support_kind| { + if support_kind.is_not_enabled() { Some(support_kind) } else { None } + })) + .and( + file_features + .support_kind_for(&FeatureKind::OrganizeImports) + .and_then( + |support_kind| { + if support_kind.is_not_enabled() { Some(support_kind) } else { None } + }, + ), + ) + }, + TraversalMode::Format { .. } => file_features.support_kind_for(&FeatureKind::Format), + TraversalMode::Lint { .. } => file_features.support_kind_for(&FeatureKind::Lint), + TraversalMode::Migrate { .. } => None, + TraversalMode::Search { .. } => file_features.support_kind_for(&FeatureKind::Search), + }; + + if let Some(reason) = unsupported_reason { + match reason { + SupportKind::FileNotSupported => { + return Err(Message::from( + UnhandledDiagnostic.with_file_path(biome_path.display().to_string()), + )); + }, + + SupportKind::FeatureNotEnabled | SupportKind::Ignored => { + return Ok(FileStatus::Ignored); + }, + + SupportKind::Protected => { + return Ok(FileStatus::Protected(biome_path.display().to_string())); + }, + + SupportKind::Supported => {}, + }; + } + + let shared_context = &SharedTraversalOptions::new(ctx); + + match ctx.execution.traversal_mode { + TraversalMode::Lint { ref suppression_reason, suppress, .. } => { + // the unsupported case should be handled already at this point + lint(shared_context, biome_path, suppress, suppression_reason.as_deref()) + }, + + TraversalMode::Format { .. } => { + // the unsupported case should be handled already at this point + format(shared_context, biome_path) + }, + + TraversalMode::Check { .. } | TraversalMode::CI { .. } => { + check_file(shared_context, biome_path, &file_features) + }, + + TraversalMode::Migrate { .. } => { + unreachable!("The migration should not be called for this file") + }, + + TraversalMode::Search { ref pattern, .. } => { + // the unsupported case should be handled already at this point + search(shared_context, biome_path, pattern) + }, + } + }) } diff --git a/crates/biome_cli/Source/execute/process_file/assists.rs b/crates/biome_cli/Source/execute/process_file/assists.rs index ed6f6c0256af..0d7085d07413 100644 --- a/crates/biome_cli/Source/execute/process_file/assists.rs +++ b/crates/biome_cli/Source/execute/process_file/assists.rs @@ -1,83 +1,78 @@ use std::ffi::OsStr; -use crate::execute::diagnostics::ResultExt; -use crate::execute::process_file::workspace_file::WorkspaceFile; -use crate::execute::process_file::{ - DiffKind, FileResult, FileStatus, Message, SharedTraversalOptions, -}; use biome_analyze::RuleCategoriesBuilder; use biome_diagnostics::category; -use biome_service::file_handlers::{AstroFileHandler, SvelteFileHandler, VueFileHandler}; -use biome_service::workspace::FixFileMode; +use biome_service::{ + file_handlers::{AstroFileHandler, SvelteFileHandler, VueFileHandler}, + workspace::FixFileMode, +}; + +use crate::execute::{ + diagnostics::ResultExt, + process_file::{DiffKind, FileResult, FileStatus, Message, SharedTraversalOptions, workspace_file::WorkspaceFile}, +}; /// Lints a single file and returns a [FileResult] pub(crate) fn assists_with_guard<'ctx>( - ctx: &'ctx SharedTraversalOptions<'ctx, '_>, - workspace_file: &mut WorkspaceFile, + ctx:&'ctx SharedTraversalOptions<'ctx, '_>, + workspace_file:&mut WorkspaceFile, ) -> FileResult { - tracing::info_span!("Processes assists", path =? workspace_file.path.display()).in_scope( - move || { - let input = workspace_file.input()?; + tracing::info_span!("Processes assists", path =? workspace_file.path.display()).in_scope(move || { + let input = workspace_file.input()?; - let only = Vec::new(); + let only = Vec::new(); - let skip = Vec::new(); + let skip = Vec::new(); - let fix_result = workspace_file - .guard() - .fix_file( - FixFileMode::SafeFixes, - false, - RuleCategoriesBuilder::default().with_action().build(), - only.clone(), - skip.clone(), - None, - ) - .with_file_path_and_code( - workspace_file.path.display().to_string(), - category!("assists"), - )?; + let fix_result = workspace_file + .guard() + .fix_file( + FixFileMode::SafeFixes, + false, + RuleCategoriesBuilder::default().with_action().build(), + only.clone(), + skip.clone(), + None, + ) + .with_file_path_and_code(workspace_file.path.display().to_string(), category!("assists"))?; - ctx.push_message(Message::SkippedFixes { - skipped_suggested_fixes: fix_result.skipped_suggested_fixes, - }); + ctx.push_message(Message::SkippedFixes { skipped_suggested_fixes:fix_result.skipped_suggested_fixes }); - let mut output = fix_result.code; + let mut output = fix_result.code; - match workspace_file.as_extension().map(OsStr::as_encoded_bytes) { - Some(b"astro") => { - output = AstroFileHandler::output(input.as_str(), output.as_str()); - } + match workspace_file.as_extension().map(OsStr::as_encoded_bytes) { + Some(b"astro") => { + output = AstroFileHandler::output(input.as_str(), output.as_str()); + }, - Some(b"vue") => { - output = VueFileHandler::output(input.as_str(), output.as_str()); - } + Some(b"vue") => { + output = VueFileHandler::output(input.as_str(), output.as_str()); + }, - Some(b"svelte") => { - output = SvelteFileHandler::output(input.as_str(), output.as_str()); - } + Some(b"svelte") => { + output = SvelteFileHandler::output(input.as_str(), output.as_str()); + }, - _ => {} - } + _ => {}, + } - if input != output { - if ctx.execution.as_fix_file_mode().is_none() { - return Ok(FileStatus::Message(Message::Diff { - file_name: workspace_file.path.display().to_string(), - old: input, - new: output, - diff_kind: DiffKind::Assists, - })); - } else { - if output != input && ctx.execution.as_fix_file_mode().is_some() { - workspace_file.update_file(output)?; - } + if input != output { + if ctx.execution.as_fix_file_mode().is_none() { + return Ok(FileStatus::Message(Message::Diff { + file_name:workspace_file.path.display().to_string(), + old:input, + new:output, + diff_kind:DiffKind::Assists, + })); + } else { + if output != input && ctx.execution.as_fix_file_mode().is_some() { + workspace_file.update_file(output)?; + } - Ok(FileStatus::Changed) - } - } else { - Ok(FileStatus::Unchanged) - } - }, - ) + Ok(FileStatus::Changed) + } + } else { + Ok(FileStatus::Unchanged) + } + }) } diff --git a/crates/biome_cli/Source/execute/process_file/check.rs b/crates/biome_cli/Source/execute/process_file/check.rs index 6409667650b2..f625497a4854 100644 --- a/crates/biome_cli/Source/execute/process_file/check.rs +++ b/crates/biome_cli/Source/execute/process_file/check.rs @@ -1,136 +1,141 @@ -use crate::execute::process_file::assists::assists_with_guard; -use crate::execute::process_file::format::format_with_guard; -use crate::execute::process_file::lint::lint_with_guard; -use crate::execute::process_file::organize_imports::organize_imports_with_guard; -use crate::execute::process_file::workspace_file::WorkspaceFile; -use crate::execute::process_file::{FileResult, FileStatus, Message, SharedTraversalOptions}; -use biome_service::workspace::FileFeaturesResult; use std::path::Path; +use biome_service::workspace::FileFeaturesResult; + +use crate::execute::process_file::{ + FileResult, + FileStatus, + Message, + SharedTraversalOptions, + assists::assists_with_guard, + format::format_with_guard, + lint::lint_with_guard, + organize_imports::organize_imports_with_guard, + workspace_file::WorkspaceFile, +}; + pub(crate) fn check_file<'ctx>( - ctx: &'ctx SharedTraversalOptions<'ctx, '_>, - path: &Path, - file_features: &'ctx FileFeaturesResult, + ctx:&'ctx SharedTraversalOptions<'ctx, '_>, + path:&Path, + file_features:&'ctx FileFeaturesResult, ) -> FileResult { - let mut has_failures = false; - - let mut workspace_file = WorkspaceFile::new(ctx, path)?; - - let mut changed = false; - - tracing::info_span!("Process check", path =? workspace_file.path.display()).in_scope( - move || { - if file_features.supports_lint() { - let lint_result = lint_with_guard(ctx, &mut workspace_file, false, None); - - match lint_result { - Ok(status) => { - if status.is_changed() { - changed = true - } - - if let FileStatus::Message(msg) = status { - if msg.is_failure() { - has_failures = true; - } - - ctx.push_message(msg); - } - } - - Err(err) => { - ctx.push_message(err); - - has_failures = true; - } - } - } - - if file_features.supports_organize_imports() { - let organize_imports_result = organize_imports_with_guard(ctx, &mut workspace_file); - - match organize_imports_result { - Ok(status) => { - if status.is_changed() { - changed = true - } - - if let FileStatus::Message(msg) = status { - if msg.is_failure() { - has_failures = true; - } - - ctx.push_message(msg); - } - } - - Err(err) => { - ctx.push_message(err); - - has_failures = true; - } - } - } - - if file_features.supports_assists() { - let assists_result = assists_with_guard(ctx, &mut workspace_file); - - match assists_result { - Ok(status) => { - if status.is_changed() { - changed = true - } - - if let FileStatus::Message(msg) = status { - if msg.is_failure() { - has_failures = true; - } - - ctx.push_message(msg); - } - } - - Err(err) => { - ctx.push_message(err); - - has_failures = true; - } - } - } - - if file_features.supports_format() { - let format_result = format_with_guard(ctx, &mut workspace_file); - - match format_result { - Ok(status) => { - if status.is_changed() { - changed = true - } - - if let FileStatus::Message(msg) = status { - if msg.is_failure() { - has_failures = true; - } - - ctx.push_message(msg); - } - } - - Err(err) => { - ctx.push_message(err); - - has_failures = true; - } - } - } - - if has_failures { - Ok(FileStatus::Message(Message::Failure)) - } else if changed { - Ok(FileStatus::Changed) - } else { - Ok(FileStatus::Unchanged) - } - }, - ) + let mut has_failures = false; + + let mut workspace_file = WorkspaceFile::new(ctx, path)?; + + let mut changed = false; + + tracing::info_span!("Process check", path =? workspace_file.path.display()).in_scope(move || { + if file_features.supports_lint() { + let lint_result = lint_with_guard(ctx, &mut workspace_file, false, None); + + match lint_result { + Ok(status) => { + if status.is_changed() { + changed = true + } + + if let FileStatus::Message(msg) = status { + if msg.is_failure() { + has_failures = true; + } + + ctx.push_message(msg); + } + }, + + Err(err) => { + ctx.push_message(err); + + has_failures = true; + }, + } + } + + if file_features.supports_organize_imports() { + let organize_imports_result = organize_imports_with_guard(ctx, &mut workspace_file); + + match organize_imports_result { + Ok(status) => { + if status.is_changed() { + changed = true + } + + if let FileStatus::Message(msg) = status { + if msg.is_failure() { + has_failures = true; + } + + ctx.push_message(msg); + } + }, + + Err(err) => { + ctx.push_message(err); + + has_failures = true; + }, + } + } + + if file_features.supports_assists() { + let assists_result = assists_with_guard(ctx, &mut workspace_file); + + match assists_result { + Ok(status) => { + if status.is_changed() { + changed = true + } + + if let FileStatus::Message(msg) = status { + if msg.is_failure() { + has_failures = true; + } + + ctx.push_message(msg); + } + }, + + Err(err) => { + ctx.push_message(err); + + has_failures = true; + }, + } + } + + if file_features.supports_format() { + let format_result = format_with_guard(ctx, &mut workspace_file); + + match format_result { + Ok(status) => { + if status.is_changed() { + changed = true + } + + if let FileStatus::Message(msg) = status { + if msg.is_failure() { + has_failures = true; + } + + ctx.push_message(msg); + } + }, + + Err(err) => { + ctx.push_message(err); + + has_failures = true; + }, + } + } + + if has_failures { + Ok(FileStatus::Message(Message::Failure)) + } else if changed { + Ok(FileStatus::Changed) + } else { + Ok(FileStatus::Unchanged) + } + }) } diff --git a/crates/biome_cli/Source/execute/process_file/format.rs b/crates/biome_cli/Source/execute/process_file/format.rs index 52b3a2d5d3fb..ba2b0155bc9d 100644 --- a/crates/biome_cli/Source/execute/process_file/format.rs +++ b/crates/biome_cli/Source/execute/process_file/format.rs @@ -1,146 +1,130 @@ -use crate::execute::diagnostics::{ResultExt, SkippedDiagnostic}; -use crate::execute::process_file::workspace_file::WorkspaceFile; -use crate::execute::process_file::{ - DiffKind, FileResult, FileStatus, Message, SharedTraversalOptions, -}; -use crate::execute::TraversalMode; +use std::{ffi::OsStr, path::Path, sync::atomic::Ordering}; + use biome_analyze::RuleCategoriesBuilder; -use biome_diagnostics::{category, Diagnostic, DiagnosticExt, Error, Severity}; +use biome_diagnostics::{Diagnostic, DiagnosticExt, Error, Severity, category}; use biome_service::file_handlers::{AstroFileHandler, SvelteFileHandler, VueFileHandler}; -use std::ffi::OsStr; -use std::path::Path; -use std::sync::atomic::Ordering; use tracing::debug; -pub(crate) fn format<'ctx>(ctx: &'ctx SharedTraversalOptions<'ctx, '_>, path: &Path) -> FileResult { - let mut workspace_file = WorkspaceFile::new(ctx, path)?; +use crate::execute::{ + TraversalMode, + diagnostics::{ResultExt, SkippedDiagnostic}, + process_file::{DiffKind, FileResult, FileStatus, Message, SharedTraversalOptions, workspace_file::WorkspaceFile}, +}; + +pub(crate) fn format<'ctx>(ctx:&'ctx SharedTraversalOptions<'ctx, '_>, path:&Path) -> FileResult { + let mut workspace_file = WorkspaceFile::new(ctx, path)?; - format_with_guard(ctx, &mut workspace_file) + format_with_guard(ctx, &mut workspace_file) } pub(crate) fn format_with_guard<'ctx>( - ctx: &'ctx SharedTraversalOptions<'ctx, '_>, - workspace_file: &mut WorkspaceFile, + ctx:&'ctx SharedTraversalOptions<'ctx, '_>, + workspace_file:&mut WorkspaceFile, ) -> FileResult { - tracing::info_span!("Processes formatting", path =? workspace_file.path.display()).in_scope( - move || { - let max_diagnostics = ctx.remaining_diagnostics.load(Ordering::Relaxed); - - debug!("Pulling diagnostics from parsed file"); - - let diagnostics_result = workspace_file - .guard() - .pull_diagnostics( - RuleCategoriesBuilder::default().with_syntax().build(), - max_diagnostics, - Vec::new(), - Vec::new(), - ) - .with_file_path_and_code( - workspace_file.path.display().to_string(), - category!("format"), - )?; - - let input = workspace_file.input()?; - - let (should_write, ignore_errors) = match ctx.execution.traversal_mode { - TraversalMode::Format { - write, - ignore_errors, - .. - } => (write, ignore_errors), - - _ => ( - ctx.execution.is_check_apply() || ctx.execution.is_check_apply_unsafe(), - false, - ), - }; - - debug!("Should write the file to disk? {}", should_write); - - debug!("Should ignore errors? {}", ignore_errors); - - if diagnostics_result.errors > 0 && ignore_errors { - return Err(Message::from( - SkippedDiagnostic.with_file_path(workspace_file.path.display().to_string()), - )); - } - - ctx.push_message(Message::Diagnostics { - name: workspace_file.path.display().to_string(), - content: input.clone(), - diagnostics: diagnostics_result - .diagnostics - .into_iter() - .filter_map(|diag| { - if diag.severity() >= Severity::Error && ignore_errors { - None - } else { - Some(Error::from(diag)) - } - }) - .collect(), - skipped_diagnostics: diagnostics_result.skipped_diagnostics as u32, - }); - - let printed = workspace_file - .guard() - .format_file() - .with_file_path_and_code( - workspace_file.path.display().to_string(), - category!("format"), - )?; - - let mut output = printed.into_code(); - - if ignore_errors { - return Ok(FileStatus::Ignored); - } - - match workspace_file.as_extension().map(OsStr::as_encoded_bytes) { - Some(b"astro") => { - if output.is_empty() { - return Ok(FileStatus::Unchanged); - } - - output = AstroFileHandler::output(input.as_str(), output.as_str()); - } - - Some(b"vue") => { - if output.is_empty() { - return Ok(FileStatus::Unchanged); - } - - output = VueFileHandler::output(input.as_str(), output.as_str()); - } - - Some(b"svelte") => { - if output.is_empty() { - return Ok(FileStatus::Unchanged); - } - - output = SvelteFileHandler::output(input.as_str(), output.as_str()); - } - - _ => {} - } - - if output != input { - if should_write { - workspace_file.update_file(output)?; - - Ok(FileStatus::Changed) - } else { - Ok(FileStatus::Message(Message::Diff { - file_name: workspace_file.path.display().to_string(), - old: input, - new: output, - diff_kind: DiffKind::Format, - })) - } - } else { - Ok(FileStatus::Unchanged) - } - }, - ) + tracing::info_span!("Processes formatting", path =? workspace_file.path.display()).in_scope(move || { + let max_diagnostics = ctx.remaining_diagnostics.load(Ordering::Relaxed); + + debug!("Pulling diagnostics from parsed file"); + + let diagnostics_result = workspace_file + .guard() + .pull_diagnostics( + RuleCategoriesBuilder::default().with_syntax().build(), + max_diagnostics, + Vec::new(), + Vec::new(), + ) + .with_file_path_and_code(workspace_file.path.display().to_string(), category!("format"))?; + + let input = workspace_file.input()?; + + let (should_write, ignore_errors) = match ctx.execution.traversal_mode { + TraversalMode::Format { write, ignore_errors, .. } => (write, ignore_errors), + + _ => (ctx.execution.is_check_apply() || ctx.execution.is_check_apply_unsafe(), false), + }; + + debug!("Should write the file to disk? {}", should_write); + + debug!("Should ignore errors? {}", ignore_errors); + + if diagnostics_result.errors > 0 && ignore_errors { + return Err(Message::from( + SkippedDiagnostic.with_file_path(workspace_file.path.display().to_string()), + )); + } + + ctx.push_message(Message::Diagnostics { + name:workspace_file.path.display().to_string(), + content:input.clone(), + diagnostics:diagnostics_result + .diagnostics + .into_iter() + .filter_map(|diag| { + if diag.severity() >= Severity::Error && ignore_errors { + None + } else { + Some(Error::from(diag)) + } + }) + .collect(), + skipped_diagnostics:diagnostics_result.skipped_diagnostics as u32, + }); + + let printed = workspace_file + .guard() + .format_file() + .with_file_path_and_code(workspace_file.path.display().to_string(), category!("format"))?; + + let mut output = printed.into_code(); + + if ignore_errors { + return Ok(FileStatus::Ignored); + } + + match workspace_file.as_extension().map(OsStr::as_encoded_bytes) { + Some(b"astro") => { + if output.is_empty() { + return Ok(FileStatus::Unchanged); + } + + output = AstroFileHandler::output(input.as_str(), output.as_str()); + }, + + Some(b"vue") => { + if output.is_empty() { + return Ok(FileStatus::Unchanged); + } + + output = VueFileHandler::output(input.as_str(), output.as_str()); + }, + + Some(b"svelte") => { + if output.is_empty() { + return Ok(FileStatus::Unchanged); + } + + output = SvelteFileHandler::output(input.as_str(), output.as_str()); + }, + + _ => {}, + } + + if output != input { + if should_write { + workspace_file.update_file(output)?; + + Ok(FileStatus::Changed) + } else { + Ok(FileStatus::Message(Message::Diff { + file_name:workspace_file.path.display().to_string(), + old:input, + new:output, + diff_kind:DiffKind::Format, + })) + } + } else { + Ok(FileStatus::Unchanged) + } + }) } diff --git a/crates/biome_cli/Source/execute/process_file/lint.rs b/crates/biome_cli/Source/execute/process_file/lint.rs index 2d609f486f72..80478da46476 100644 --- a/crates/biome_cli/Source/execute/process_file/lint.rs +++ b/crates/biome_cli/Source/execute/process_file/lint.rs @@ -1,155 +1,137 @@ -use crate::execute::diagnostics::ResultExt; -use crate::execute::process_file::workspace_file::WorkspaceFile; -use crate::execute::process_file::{FileResult, FileStatus, Message, SharedTraversalOptions}; -use crate::TraversalMode; +use std::{ffi::OsStr, path::Path, sync::atomic::Ordering}; + use biome_analyze::RuleCategoriesBuilder; -use biome_diagnostics::{category, Error}; +use biome_diagnostics::{Error, category}; use biome_rowan::TextSize; use biome_service::file_handlers::{AstroFileHandler, SvelteFileHandler, VueFileHandler}; -use std::ffi::OsStr; -use std::path::Path; -use std::sync::atomic::Ordering; + +use crate::{ + TraversalMode, + execute::{ + diagnostics::ResultExt, + process_file::{FileResult, FileStatus, Message, SharedTraversalOptions, workspace_file::WorkspaceFile}, + }, +}; /// Lints a single file and returns a [FileResult] pub(crate) fn lint<'ctx>( - ctx: &'ctx SharedTraversalOptions<'ctx, '_>, - path: &Path, - suppress: bool, - suppression_reason: Option<&str>, + ctx:&'ctx SharedTraversalOptions<'ctx, '_>, + path:&Path, + suppress:bool, + suppression_reason:Option<&str>, ) -> FileResult { - let mut workspace_file = WorkspaceFile::new(ctx, path)?; + let mut workspace_file = WorkspaceFile::new(ctx, path)?; - lint_with_guard(ctx, &mut workspace_file, suppress, suppression_reason) + lint_with_guard(ctx, &mut workspace_file, suppress, suppression_reason) } pub(crate) fn lint_with_guard<'ctx>( - ctx: &'ctx SharedTraversalOptions<'ctx, '_>, - workspace_file: &mut WorkspaceFile, - suppress: bool, - suppression_reason: Option<&str>, + ctx:&'ctx SharedTraversalOptions<'ctx, '_>, + workspace_file:&mut WorkspaceFile, + suppress:bool, + suppression_reason:Option<&str>, ) -> FileResult { - tracing::info_span!("Processes linting", path =? workspace_file.path.display()).in_scope( - move || { - let mut input = workspace_file.input()?; - - let mut changed = false; - - let (only, skip) = - if let TraversalMode::Lint { only, skip, .. } = ctx.execution.traversal_mode() { - (only.clone(), skip.clone()) - } else { - (Vec::new(), Vec::new()) - }; - - if let Some(fix_mode) = ctx.execution.as_fix_file_mode() { - let suppression_explanation = if suppress && suppression_reason.is_none() { - "ignored using `--suppress`" - } else { - suppression_reason.unwrap_or("") - }; - - let fix_result = workspace_file - .guard() - .fix_file( - *fix_mode, - false, - RuleCategoriesBuilder::default() - .with_syntax() - .with_lint() - .build(), - only.clone(), - skip.clone(), - Some(suppression_explanation.to_string()), - ) - .with_file_path_and_code( - workspace_file.path.display().to_string(), - category!("lint"), - )?; - - ctx.push_message(Message::SkippedFixes { - skipped_suggested_fixes: fix_result.skipped_suggested_fixes, - }); - - let mut output = fix_result.code; - - match workspace_file.as_extension().map(OsStr::as_encoded_bytes) { - Some(b"astro") => { - output = AstroFileHandler::output(input.as_str(), output.as_str()); - } - - Some(b"vue") => { - output = VueFileHandler::output(input.as_str(), output.as_str()); - } - - Some(b"svelte") => { - output = SvelteFileHandler::output(input.as_str(), output.as_str()); - } - - _ => {} - } - - if output != input { - changed = true; - - workspace_file.update_file(output)?; - - input = workspace_file.input()?; - } - } - - let max_diagnostics = ctx.remaining_diagnostics.load(Ordering::Relaxed); - - let pull_diagnostics_result = workspace_file - .guard() - .pull_diagnostics( - RuleCategoriesBuilder::default() - .with_syntax() - .with_lint() - .build(), - max_diagnostics, - only, - skip, - ) - .with_file_path_and_code( - workspace_file.path.display().to_string(), - category!("lint"), - )?; - - let no_diagnostics = pull_diagnostics_result.diagnostics.is_empty() - && pull_diagnostics_result.skipped_diagnostics == 0; - - if !no_diagnostics { - let offset = match workspace_file.as_extension().map(OsStr::as_encoded_bytes) { - Some(b"vue") => VueFileHandler::start(input.as_str()), - Some(b"astro") => AstroFileHandler::start(input.as_str()), - Some(b"svelte") => SvelteFileHandler::start(input.as_str()), - _ => None, - }; - - ctx.push_message(Message::Diagnostics { - name: workspace_file.path.display().to_string(), - content: input, - diagnostics: pull_diagnostics_result - .diagnostics - .into_iter() - .map(|d| { - if let Some(offset) = offset { - d.with_offset(TextSize::from(offset)) - } else { - d - } - }) - .map(Error::from) - .collect(), - skipped_diagnostics: pull_diagnostics_result.skipped_diagnostics as u32, - }); - } - - if changed { - Ok(FileStatus::Changed) - } else { - Ok(FileStatus::Unchanged) - } - }, - ) + tracing::info_span!("Processes linting", path =? workspace_file.path.display()).in_scope(move || { + let mut input = workspace_file.input()?; + + let mut changed = false; + + let (only, skip) = if let TraversalMode::Lint { only, skip, .. } = ctx.execution.traversal_mode() { + (only.clone(), skip.clone()) + } else { + (Vec::new(), Vec::new()) + }; + + if let Some(fix_mode) = ctx.execution.as_fix_file_mode() { + let suppression_explanation = if suppress && suppression_reason.is_none() { + "ignored using `--suppress`" + } else { + suppression_reason.unwrap_or("") + }; + + let fix_result = workspace_file + .guard() + .fix_file( + *fix_mode, + false, + RuleCategoriesBuilder::default().with_syntax().with_lint().build(), + only.clone(), + skip.clone(), + Some(suppression_explanation.to_string()), + ) + .with_file_path_and_code(workspace_file.path.display().to_string(), category!("lint"))?; + + ctx.push_message(Message::SkippedFixes { skipped_suggested_fixes:fix_result.skipped_suggested_fixes }); + + let mut output = fix_result.code; + + match workspace_file.as_extension().map(OsStr::as_encoded_bytes) { + Some(b"astro") => { + output = AstroFileHandler::output(input.as_str(), output.as_str()); + }, + + Some(b"vue") => { + output = VueFileHandler::output(input.as_str(), output.as_str()); + }, + + Some(b"svelte") => { + output = SvelteFileHandler::output(input.as_str(), output.as_str()); + }, + + _ => {}, + } + + if output != input { + changed = true; + + workspace_file.update_file(output)?; + + input = workspace_file.input()?; + } + } + + let max_diagnostics = ctx.remaining_diagnostics.load(Ordering::Relaxed); + + let pull_diagnostics_result = workspace_file + .guard() + .pull_diagnostics( + RuleCategoriesBuilder::default().with_syntax().with_lint().build(), + max_diagnostics, + only, + skip, + ) + .with_file_path_and_code(workspace_file.path.display().to_string(), category!("lint"))?; + + let no_diagnostics = + pull_diagnostics_result.diagnostics.is_empty() && pull_diagnostics_result.skipped_diagnostics == 0; + + if !no_diagnostics { + let offset = match workspace_file.as_extension().map(OsStr::as_encoded_bytes) { + Some(b"vue") => VueFileHandler::start(input.as_str()), + Some(b"astro") => AstroFileHandler::start(input.as_str()), + Some(b"svelte") => SvelteFileHandler::start(input.as_str()), + _ => None, + }; + + ctx.push_message(Message::Diagnostics { + name:workspace_file.path.display().to_string(), + content:input, + diagnostics:pull_diagnostics_result + .diagnostics + .into_iter() + .map(|d| { + if let Some(offset) = offset { + d.with_offset(TextSize::from(offset)) + } else { + d + } + }) + .map(Error::from) + .collect(), + skipped_diagnostics:pull_diagnostics_result.skipped_diagnostics as u32, + }); + } + + if changed { Ok(FileStatus::Changed) } else { Ok(FileStatus::Unchanged) } + }) } diff --git a/crates/biome_cli/Source/execute/process_file/organize_imports.rs b/crates/biome_cli/Source/execute/process_file/organize_imports.rs index 29f291820007..7c64b98ea4c1 100644 --- a/crates/biome_cli/Source/execute/process_file/organize_imports.rs +++ b/crates/biome_cli/Source/execute/process_file/organize_imports.rs @@ -1,76 +1,71 @@ use std::ffi::OsStr; -use crate::execute::diagnostics::ResultExt; -use crate::execute::process_file::workspace_file::WorkspaceFile; -use crate::execute::process_file::{ - DiffKind, FileResult, FileStatus, Message, SharedTraversalOptions, -}; use biome_diagnostics::category; use biome_service::file_handlers::{AstroFileHandler, SvelteFileHandler, VueFileHandler}; +use crate::execute::{ + diagnostics::ResultExt, + process_file::{DiffKind, FileResult, FileStatus, Message, SharedTraversalOptions, workspace_file::WorkspaceFile}, +}; + /// Lints a single file and returns a [FileResult] pub(crate) fn organize_imports_with_guard<'ctx>( - ctx: &'ctx SharedTraversalOptions<'ctx, '_>, - workspace_file: &mut WorkspaceFile, + ctx:&'ctx SharedTraversalOptions<'ctx, '_>, + workspace_file:&mut WorkspaceFile, ) -> FileResult { - tracing::info_span!("Processes import sorting", path =? workspace_file.path.display()).in_scope( - move || { - let sorted = workspace_file - .guard() - .organize_imports() - .with_file_path_and_code( - workspace_file.path.display().to_string(), - category!("organizeImports"), - )?; + tracing::info_span!("Processes import sorting", path =? workspace_file.path.display()).in_scope(move || { + let sorted = workspace_file + .guard() + .organize_imports() + .with_file_path_and_code(workspace_file.path.display().to_string(), category!("organizeImports"))?; - let input = workspace_file.input()?; + let input = workspace_file.input()?; - let mut output = sorted.code; + let mut output = sorted.code; - match workspace_file.as_extension().map(OsStr::as_encoded_bytes) { - Some(b"astro") => { - if output.is_empty() { - return Ok(FileStatus::Unchanged); - } + match workspace_file.as_extension().map(OsStr::as_encoded_bytes) { + Some(b"astro") => { + if output.is_empty() { + return Ok(FileStatus::Unchanged); + } - output = AstroFileHandler::output(input.as_str(), output.as_str()); - } + output = AstroFileHandler::output(input.as_str(), output.as_str()); + }, - Some(b"vue") => { - if output.is_empty() { - return Ok(FileStatus::Unchanged); - } + Some(b"vue") => { + if output.is_empty() { + return Ok(FileStatus::Unchanged); + } - output = VueFileHandler::output(input.as_str(), output.as_str()); - } + output = VueFileHandler::output(input.as_str(), output.as_str()); + }, - Some(b"svelte") => { - if output.is_empty() { - return Ok(FileStatus::Unchanged); - } + Some(b"svelte") => { + if output.is_empty() { + return Ok(FileStatus::Unchanged); + } - output = SvelteFileHandler::output(input.as_str(), output.as_str()); - } + output = SvelteFileHandler::output(input.as_str(), output.as_str()); + }, - _ => {} - } + _ => {}, + } - if output != input { - if ctx.execution.is_check_apply() || ctx.execution.is_check_apply_unsafe() { - workspace_file.update_file(output)?; - } else { - return Ok(FileStatus::Message(Message::Diff { - file_name: workspace_file.path.display().to_string(), - old: input, - new: output, - diff_kind: DiffKind::OrganizeImports, - })); - } + if output != input { + if ctx.execution.is_check_apply() || ctx.execution.is_check_apply_unsafe() { + workspace_file.update_file(output)?; + } else { + return Ok(FileStatus::Message(Message::Diff { + file_name:workspace_file.path.display().to_string(), + old:input, + new:output, + diff_kind:DiffKind::OrganizeImports, + })); + } - Ok(FileStatus::Changed) - } else { - Ok(FileStatus::Unchanged) - } - }, - ) + Ok(FileStatus::Changed) + } else { + Ok(FileStatus::Unchanged) + } + }) } diff --git a/crates/biome_cli/Source/execute/process_file/search.rs b/crates/biome_cli/Source/execute/process_file/search.rs index 6ae88bf64a12..d6330bcb67f0 100644 --- a/crates/biome_cli/Source/execute/process_file/search.rs +++ b/crates/biome_cli/Source/execute/process_file/search.rs @@ -1,53 +1,47 @@ -use crate::execute::diagnostics::{ResultExt, SearchDiagnostic}; -use crate::execute::process_file::workspace_file::WorkspaceFile; -use crate::execute::process_file::{FileResult, FileStatus, Message, SharedTraversalOptions}; -use biome_diagnostics::{category, DiagnosticExt}; -use biome_service::workspace::PatternId; use std::path::Path; -pub(crate) fn search<'ctx>( - ctx: &'ctx SharedTraversalOptions<'ctx, '_>, - path: &Path, - pattern: &PatternId, -) -> FileResult { - let mut workspace_file = WorkspaceFile::new(ctx, path)?; +use biome_diagnostics::{DiagnosticExt, category}; +use biome_service::workspace::PatternId; + +use crate::execute::{ + diagnostics::{ResultExt, SearchDiagnostic}, + process_file::{FileResult, FileStatus, Message, SharedTraversalOptions, workspace_file::WorkspaceFile}, +}; + +pub(crate) fn search<'ctx>(ctx:&'ctx SharedTraversalOptions<'ctx, '_>, path:&Path, pattern:&PatternId) -> FileResult { + let mut workspace_file = WorkspaceFile::new(ctx, path)?; - search_with_guard(ctx, &mut workspace_file, pattern) + search_with_guard(ctx, &mut workspace_file, pattern) } pub(crate) fn search_with_guard<'ctx>( - _ctx: &'ctx SharedTraversalOptions<'ctx, '_>, - workspace_file: &mut WorkspaceFile, - pattern: &PatternId, + _ctx:&'ctx SharedTraversalOptions<'ctx, '_>, + workspace_file:&mut WorkspaceFile, + pattern:&PatternId, ) -> FileResult { - tracing::info_span!("Processes searching", path =? workspace_file.path.display()).in_scope( - move || { - let result = workspace_file - .guard() - .search_pattern(pattern) - .with_file_path_and_code( - workspace_file.path.display().to_string(), - category!("search"), - )?; - - let input = workspace_file.input()?; - - let file_name = workspace_file.path.display().to_string(); - - let matches_len = result.matches.len(); - - let search_results = Message::Diagnostics { - name: file_name, - content: input, - diagnostics: result - .matches - .into_iter() - .map(|mat| SearchDiagnostic.with_file_span(mat)) - .collect(), - skipped_diagnostics: 0, - }; - - Ok(FileStatus::SearchResult(matches_len, search_results)) - }, - ) + tracing::info_span!("Processes searching", path =? workspace_file.path.display()).in_scope(move || { + let result = workspace_file + .guard() + .search_pattern(pattern) + .with_file_path_and_code(workspace_file.path.display().to_string(), category!("search"))?; + + let input = workspace_file.input()?; + + let file_name = workspace_file.path.display().to_string(); + + let matches_len = result.matches.len(); + + let search_results = Message::Diagnostics { + name:file_name, + content:input, + diagnostics:result + .matches + .into_iter() + .map(|mat| SearchDiagnostic.with_file_span(mat)) + .collect(), + skipped_diagnostics:0, + }; + + Ok(FileStatus::SearchResult(matches_len, search_results)) + }) } diff --git a/crates/biome_cli/Source/execute/process_file/workspace_file.rs b/crates/biome_cli/Source/execute/process_file/workspace_file.rs index 781f4e224721..e5a2460f3fda 100644 --- a/crates/biome_cli/Source/execute/process_file/workspace_file.rs +++ b/crates/biome_cli/Source/execute/process_file/workspace_file.rs @@ -1,83 +1,71 @@ -use crate::execute::diagnostics::{ResultExt, ResultIoExt}; -use crate::execute::process_file::SharedTraversalOptions; -use biome_diagnostics::{category, Error}; +use std::{ + ffi::OsStr, + path::{Path, PathBuf}, +}; + +use biome_diagnostics::{Error, category}; use biome_fs::{BiomePath, File, OpenOptions}; -use biome_service::workspace::{FileGuard, OpenFileParams}; -use biome_service::{Workspace, WorkspaceError}; -use std::ffi::OsStr; -use std::path::{Path, PathBuf}; +use biome_service::{ + Workspace, + WorkspaceError, + workspace::{FileGuard, OpenFileParams}, +}; + +use crate::execute::{ + diagnostics::{ResultExt, ResultIoExt}, + process_file::SharedTraversalOptions, +}; -/// Small wrapper that holds information and operations around the current processed file +/// Small wrapper that holds information and operations around the current +/// processed file pub(crate) struct WorkspaceFile<'ctx, 'app> { - guard: FileGuard<'app, dyn Workspace + 'ctx>, - file: Box, - pub(crate) path: PathBuf, + guard:FileGuard<'app, dyn Workspace + 'ctx>, + file:Box, + pub(crate) path:PathBuf, } impl<'ctx, 'app> WorkspaceFile<'ctx, 'app> { - /// It attempts to read the file from disk, creating a [FileGuard] and - /// saving these information internally - pub(crate) fn new( - ctx: &SharedTraversalOptions<'ctx, 'app>, - path: &Path, - ) -> Result { - let biome_path = BiomePath::new(path); - - let open_options = OpenOptions::default() - .read(true) - .write(ctx.execution.requires_write_access()); - - let mut file = ctx - .fs - .open_with_options(path, open_options) - .with_file_path(path.display().to_string())?; - - let mut input = String::new(); - - file.read_to_string(&mut input) - .with_file_path(path.display().to_string())?; - - let guard = FileGuard::open( - ctx.workspace, - OpenFileParams { - document_file_source: None, - path: biome_path, - version: 0, - content: input.clone(), - }, - ) - .with_file_path_and_code(path.display().to_string(), category!("internalError/fs"))?; - - Ok(Self { - file, - guard, - path: PathBuf::from(path), - }) - } - - pub(crate) fn guard(&self) -> &FileGuard<'app, dyn Workspace + 'ctx> { - &self.guard - } - - pub(crate) fn input(&self) -> Result { - self.guard().get_file_content() - } - - pub(crate) fn as_extension(&self) -> Option<&OsStr> { - self.path.extension() - } - - /// It updates the workspace file with `new_content` - pub(crate) fn update_file(&mut self, new_content: impl Into) -> Result<(), Error> { - let new_content = new_content.into(); - - self.file - .set_content(new_content.as_bytes()) - .with_file_path(self.path.display().to_string())?; - - self.guard - .change_file(self.file.file_version(), new_content)?; - - Ok(()) - } + /// It attempts to read the file from disk, creating a [FileGuard] and + /// saving these information internally + pub(crate) fn new(ctx:&SharedTraversalOptions<'ctx, 'app>, path:&Path) -> Result { + let biome_path = BiomePath::new(path); + + let open_options = OpenOptions::default().read(true).write(ctx.execution.requires_write_access()); + + let mut file = ctx + .fs + .open_with_options(path, open_options) + .with_file_path(path.display().to_string())?; + + let mut input = String::new(); + + file.read_to_string(&mut input).with_file_path(path.display().to_string())?; + + let guard = FileGuard::open( + ctx.workspace, + OpenFileParams { document_file_source:None, path:biome_path, version:0, content:input.clone() }, + ) + .with_file_path_and_code(path.display().to_string(), category!("internalError/fs"))?; + + Ok(Self { file, guard, path:PathBuf::from(path) }) + } + + pub(crate) fn guard(&self) -> &FileGuard<'app, dyn Workspace + 'ctx> { &self.guard } + + pub(crate) fn input(&self) -> Result { self.guard().get_file_content() } + + pub(crate) fn as_extension(&self) -> Option<&OsStr> { self.path.extension() } + + /// It updates the workspace file with `new_content` + pub(crate) fn update_file(&mut self, new_content:impl Into) -> Result<(), Error> { + let new_content = new_content.into(); + + self.file + .set_content(new_content.as_bytes()) + .with_file_path(self.path.display().to_string())?; + + self.guard.change_file(self.file.file_version(), new_content)?; + + Ok(()) + } } diff --git a/crates/biome_cli/Source/execute/std_in.rs b/crates/biome_cli/Source/execute/std_in.rs index ee1eb99b2262..4ab001635218 100644 --- a/crates/biome_cli/Source/execute/std_in.rs +++ b/crates/biome_cli/Source/execute/std_in.rs @@ -1,244 +1,241 @@ //! In here, there are the operations that run via standard input -//! -use crate::execute::Execution; -use crate::{CliDiagnostic, CliSession, TraversalMode}; +use std::borrow::Cow; + use biome_analyze::RuleCategoriesBuilder; -use biome_console::{markup, ConsoleExt}; -use biome_diagnostics::Diagnostic; -use biome_diagnostics::PrintDiagnostic; +use biome_console::{ConsoleExt, markup}; +use biome_diagnostics::{Diagnostic, PrintDiagnostic}; use biome_fs::BiomePath; -use biome_service::file_handlers::{AstroFileHandler, SvelteFileHandler, VueFileHandler}; -use biome_service::workspace::{ - ChangeFileParams, DropPatternParams, FeaturesBuilder, FixFileParams, FormatFileParams, - OpenFileParams, OrganizeImportsParams, SupportsFeatureParams, +use biome_service::{ + WorkspaceError, + file_handlers::{AstroFileHandler, SvelteFileHandler, VueFileHandler}, + workspace::{ + ChangeFileParams, + DropPatternParams, + FeaturesBuilder, + FixFileParams, + FormatFileParams, + OpenFileParams, + OrganizeImportsParams, + SupportsFeatureParams, + }, }; -use biome_service::WorkspaceError; -use std::borrow::Cow; + +use crate::{CliDiagnostic, CliSession, TraversalMode, execute::Execution}; pub(crate) fn run<'a>( - session: CliSession, - mode: &'a Execution, - biome_path: BiomePath, - content: &'a str, - verbose: bool, + session:CliSession, + mode:&'a Execution, + biome_path:BiomePath, + content:&'a str, + verbose:bool, ) -> Result<(), CliDiagnostic> { - let workspace = &*session.app.workspace; - - let console = &mut *session.app.console; - - let mut version = 0; - - if mode.is_format() { - let file_features = workspace.file_features(SupportsFeatureParams { - path: biome_path.clone(), - features: FeaturesBuilder::new().with_formatter().build(), - })?; - - if file_features.is_protected() { - let protected_diagnostic = - WorkspaceError::protected_file(biome_path.display().to_string()); - - if protected_diagnostic.tags().is_verbose() { - if verbose { - console.error(markup! {{PrintDiagnostic::verbose(&protected_diagnostic)}}) - } - } else { - console.error(markup! {{PrintDiagnostic::simple(&protected_diagnostic)}}) - } - - console.append(markup! {{content}}); - - return Ok(()); - }; - - if file_features.supports_format() { - workspace.open_file(OpenFileParams { - path: biome_path.clone(), - version: 0, - content: content.into(), - document_file_source: None, - })?; - - let printed = workspace.format_file(FormatFileParams { - path: biome_path.clone(), - })?; - - let code = printed.into_code(); - - let output = match biome_path.extension().map(|ext| ext.as_encoded_bytes()) { - Some(b"astro") => AstroFileHandler::output(content, code.as_str()), - Some(b"vue") => VueFileHandler::output(content, code.as_str()), - Some(b"svelte") => SvelteFileHandler::output(content, code.as_str()), - _ => code, - }; - - console.append(markup! { - {output} - }); - } else { - console.append(markup! { - {content} - }); - - console.error(markup! { - "The content was not formatted because the formatter is currently disabled." - }); - - return Err(CliDiagnostic::stdin()); - } - } else if mode.is_check() || mode.is_lint() { - let mut new_content = Cow::Borrowed(content); - - workspace.open_file(OpenFileParams { - path: biome_path.clone(), - version: 0, - content: content.into(), - document_file_source: None, - })?; - // apply fix file of the linter - let file_features = workspace.file_features(SupportsFeatureParams { - path: biome_path.clone(), - features: FeaturesBuilder::new() - .with_linter() - .with_organize_imports() - .with_formatter() - .build(), - })?; - - if file_features.is_protected() { - let protected_diagnostic = - WorkspaceError::protected_file(biome_path.display().to_string()); - - if protected_diagnostic.tags().is_verbose() { - if verbose { - console.error(markup! {{PrintDiagnostic::verbose(&protected_diagnostic)}}) - } - } else { - console.error(markup! {{PrintDiagnostic::simple(&protected_diagnostic)}}) - } - - console.append(markup! {{content}}); - - return Ok(()); - }; - - let (only, skip) = if let TraversalMode::Lint { only, skip, .. } = mode.traversal_mode() { - (only.clone(), skip.clone()) - } else { - (Vec::new(), Vec::new()) - }; - - if let Some(fix_file_mode) = mode.as_fix_file_mode() { - if file_features.supports_lint() { - let fix_file_result = workspace.fix_file(FixFileParams { - fix_file_mode: *fix_file_mode, - path: biome_path.clone(), - should_format: mode.is_check() && file_features.supports_format(), - only: only.clone(), - skip: skip.clone(), - suppression_reason: None, - rule_categories: RuleCategoriesBuilder::default() - .with_syntax() - .with_lint() - .build(), - })?; - - let code = fix_file_result.code; - - let output = match biome_path.extension().map(|ext| ext.as_encoded_bytes()) { - Some(b"astro") => AstroFileHandler::output(&new_content, code.as_str()), - Some(b"vue") => VueFileHandler::output(&new_content, code.as_str()), - Some(b"svelte") => SvelteFileHandler::output(&new_content, code.as_str()), - _ => code, - }; - - if output != new_content { - version += 1; - - workspace.change_file(ChangeFileParams { - content: output.clone(), - path: biome_path.clone(), - version, - })?; - - new_content = Cow::Owned(output); - } - } - - if file_features.supports_organize_imports() && mode.is_check() { - let result = workspace.organize_imports(OrganizeImportsParams { - path: biome_path.clone(), - })?; - - let code = result.code; - - let output = match biome_path.extension().map(|ext| ext.as_encoded_bytes()) { - Some(b"astro") => AstroFileHandler::output(&new_content, code.as_str()), - Some(b"vue") => VueFileHandler::output(&new_content, code.as_str()), - Some(b"svelte") => SvelteFileHandler::output(&new_content, code.as_str()), - _ => code, - }; - - if output != new_content { - version += 1; - - workspace.change_file(ChangeFileParams { - content: output.clone(), - path: biome_path.clone(), - version, - })?; - - new_content = Cow::Owned(output); - } - } - } - - if file_features.supports_format() && mode.is_check() { - let printed = workspace.format_file(FormatFileParams { - path: biome_path.clone(), - })?; - - let code = printed.into_code(); - - let output = match biome_path.extension().map(|ext| ext.as_encoded_bytes()) { - Some(b"astro") => AstroFileHandler::output(&new_content, code.as_str()), - Some(b"vue") => VueFileHandler::output(&new_content, code.as_str()), - Some(b"svelte") => SvelteFileHandler::output(&new_content, code.as_str()), - _ => code, - }; - - if (mode.is_check_apply() || mode.is_check_apply_unsafe()) && output != new_content { - new_content = Cow::Owned(output); - } - } - - match new_content { - Cow::Borrowed(original_content) => { - console.append(markup! { - {original_content} - }); - - if !mode.is_write() { - return Err(CliDiagnostic::stdin()); - } - } - - Cow::Owned(ref new_content) => { - console.append(markup! { - {new_content} - }); - } - } - } else if let TraversalMode::Search { pattern, .. } = mode.traversal_mode() { - // Make sure patterns are always cleaned up at the end of execution. - let _ = session.app.workspace.drop_pattern(DropPatternParams { - pattern: pattern.clone(), - }); - - console.append(markup! {{content}}); - } else { - console.append(markup! {{content}}); - } - - Ok(()) + let workspace = &*session.app.workspace; + + let console = &mut *session.app.console; + + let mut version = 0; + + if mode.is_format() { + let file_features = workspace.file_features(SupportsFeatureParams { + path:biome_path.clone(), + features:FeaturesBuilder::new().with_formatter().build(), + })?; + + if file_features.is_protected() { + let protected_diagnostic = WorkspaceError::protected_file(biome_path.display().to_string()); + + if protected_diagnostic.tags().is_verbose() { + if verbose { + console.error(markup! {{PrintDiagnostic::verbose(&protected_diagnostic)}}) + } + } else { + console.error(markup! {{PrintDiagnostic::simple(&protected_diagnostic)}}) + } + + console.append(markup! {{content}}); + + return Ok(()); + }; + + if file_features.supports_format() { + workspace.open_file(OpenFileParams { + path:biome_path.clone(), + version:0, + content:content.into(), + document_file_source:None, + })?; + + let printed = workspace.format_file(FormatFileParams { path:biome_path.clone() })?; + + let code = printed.into_code(); + + let output = match biome_path.extension().map(|ext| ext.as_encoded_bytes()) { + Some(b"astro") => AstroFileHandler::output(content, code.as_str()), + Some(b"vue") => VueFileHandler::output(content, code.as_str()), + Some(b"svelte") => SvelteFileHandler::output(content, code.as_str()), + _ => code, + }; + + console.append(markup! { + {output} + }); + } else { + console.append(markup! { + {content} + }); + + console.error(markup! { + "The content was not formatted because the formatter is currently disabled." + }); + + return Err(CliDiagnostic::stdin()); + } + } else if mode.is_check() || mode.is_lint() { + let mut new_content = Cow::Borrowed(content); + + workspace.open_file(OpenFileParams { + path:biome_path.clone(), + version:0, + content:content.into(), + document_file_source:None, + })?; + // apply fix file of the linter + let file_features = workspace.file_features(SupportsFeatureParams { + path:biome_path.clone(), + features:FeaturesBuilder::new() + .with_linter() + .with_organize_imports() + .with_formatter() + .build(), + })?; + + if file_features.is_protected() { + let protected_diagnostic = WorkspaceError::protected_file(biome_path.display().to_string()); + + if protected_diagnostic.tags().is_verbose() { + if verbose { + console.error(markup! {{PrintDiagnostic::verbose(&protected_diagnostic)}}) + } + } else { + console.error(markup! {{PrintDiagnostic::simple(&protected_diagnostic)}}) + } + + console.append(markup! {{content}}); + + return Ok(()); + }; + + let (only, skip) = if let TraversalMode::Lint { only, skip, .. } = mode.traversal_mode() { + (only.clone(), skip.clone()) + } else { + (Vec::new(), Vec::new()) + }; + + if let Some(fix_file_mode) = mode.as_fix_file_mode() { + if file_features.supports_lint() { + let fix_file_result = workspace.fix_file(FixFileParams { + fix_file_mode:*fix_file_mode, + path:biome_path.clone(), + should_format:mode.is_check() && file_features.supports_format(), + only:only.clone(), + skip:skip.clone(), + suppression_reason:None, + rule_categories:RuleCategoriesBuilder::default().with_syntax().with_lint().build(), + })?; + + let code = fix_file_result.code; + + let output = match biome_path.extension().map(|ext| ext.as_encoded_bytes()) { + Some(b"astro") => AstroFileHandler::output(&new_content, code.as_str()), + Some(b"vue") => VueFileHandler::output(&new_content, code.as_str()), + Some(b"svelte") => SvelteFileHandler::output(&new_content, code.as_str()), + _ => code, + }; + + if output != new_content { + version += 1; + + workspace.change_file(ChangeFileParams { + content:output.clone(), + path:biome_path.clone(), + version, + })?; + + new_content = Cow::Owned(output); + } + } + + if file_features.supports_organize_imports() && mode.is_check() { + let result = workspace.organize_imports(OrganizeImportsParams { path:biome_path.clone() })?; + + let code = result.code; + + let output = match biome_path.extension().map(|ext| ext.as_encoded_bytes()) { + Some(b"astro") => AstroFileHandler::output(&new_content, code.as_str()), + Some(b"vue") => VueFileHandler::output(&new_content, code.as_str()), + Some(b"svelte") => SvelteFileHandler::output(&new_content, code.as_str()), + _ => code, + }; + + if output != new_content { + version += 1; + + workspace.change_file(ChangeFileParams { + content:output.clone(), + path:biome_path.clone(), + version, + })?; + + new_content = Cow::Owned(output); + } + } + } + + if file_features.supports_format() && mode.is_check() { + let printed = workspace.format_file(FormatFileParams { path:biome_path.clone() })?; + + let code = printed.into_code(); + + let output = match biome_path.extension().map(|ext| ext.as_encoded_bytes()) { + Some(b"astro") => AstroFileHandler::output(&new_content, code.as_str()), + Some(b"vue") => VueFileHandler::output(&new_content, code.as_str()), + Some(b"svelte") => SvelteFileHandler::output(&new_content, code.as_str()), + _ => code, + }; + + if (mode.is_check_apply() || mode.is_check_apply_unsafe()) && output != new_content { + new_content = Cow::Owned(output); + } + } + + match new_content { + Cow::Borrowed(original_content) => { + console.append(markup! { + {original_content} + }); + + if !mode.is_write() { + return Err(CliDiagnostic::stdin()); + } + }, + + Cow::Owned(ref new_content) => { + console.append(markup! { + {new_content} + }); + }, + } + } else if let TraversalMode::Search { pattern, .. } = mode.traversal_mode() { + // Make sure patterns are always cleaned up at the end of execution. + let _ = session + .app + .workspace + .drop_pattern(DropPatternParams { pattern:pattern.clone() }); + + console.append(markup! {{content}}); + } else { + console.append(markup! {{content}}); + } + + Ok(()) } diff --git a/crates/biome_cli/Source/execute/traverse.rs b/crates/biome_cli/Source/execute/traverse.rs index 17e124a45b8d..a6ff87785951 100644 --- a/crates/biome_cli/Source/execute/traverse.rs +++ b/crates/biome_cli/Source/execute/traverse.rs @@ -1,814 +1,760 @@ -use super::process_file::{process_file, DiffKind, FileStatus, Message}; -use super::{Execution, TraversalMode}; -use crate::cli_options::CliOptions; -use crate::execute::diagnostics::{ - AssistsDiffDiagnostic, CIAssistsDiffDiagnostic, CIFormatDiffDiagnostic, - CIOrganizeImportsDiffDiagnostic, ContentDiffAdvice, FormatDiffDiagnostic, - OrganizeImportsDiffDiagnostic, PanicDiagnostic, +use std::{ + collections::BTreeSet, + env::current_dir, + ffi::OsString, + panic::catch_unwind, + path::PathBuf, + sync::{ + Once, + RwLock, + atomic::{AtomicU32, AtomicUsize, Ordering}, + }, + thread, + time::{Duration, Instant}, +}; + +use biome_diagnostics::{DiagnosticExt, DiagnosticTags, Error, Resource, Severity, category}; +use biome_fs::{BiomePath, FileSystem, PathInterner, TraversalContext, TraversalScope}; +use biome_service::{ + Workspace, + WorkspaceError, + dome::Dome, + extension_error, + workspace::{DropPatternParams, IsPathIgnoredParams, SupportsFeatureParams}, }; -use crate::reporter::TraversalSummary; -use crate::{CliDiagnostic, CliSession}; -use biome_diagnostics::DiagnosticTags; -use biome_diagnostics::{category, DiagnosticExt, Error, Resource, Severity}; -use biome_fs::{BiomePath, FileSystem, PathInterner}; -use biome_fs::{TraversalContext, TraversalScope}; -use biome_service::dome::Dome; -use biome_service::workspace::{DropPatternParams, IsPathIgnoredParams}; -use biome_service::{extension_error, workspace::SupportsFeatureParams, Workspace, WorkspaceError}; -use crossbeam::channel::{unbounded, Receiver, Sender}; +use crossbeam::channel::{Receiver, Sender, unbounded}; use rustc_hash::FxHashSet; -use std::collections::BTreeSet; -use std::sync::atomic::AtomicU32; -use std::sync::RwLock; -use std::{ - env::current_dir, - ffi::OsString, - panic::catch_unwind, - path::PathBuf, - sync::{ - atomic::{AtomicUsize, Ordering}, - Once, - }, - thread, - time::{Duration, Instant}, + +use super::{ + Execution, + TraversalMode, + process_file::{DiffKind, FileStatus, Message, process_file}, +}; +use crate::{ + CliDiagnostic, + CliSession, + cli_options::CliOptions, + execute::diagnostics::{ + AssistsDiffDiagnostic, + CIAssistsDiffDiagnostic, + CIFormatDiffDiagnostic, + CIOrganizeImportsDiffDiagnostic, + ContentDiffAdvice, + FormatDiffDiagnostic, + OrganizeImportsDiffDiagnostic, + PanicDiagnostic, + }, + reporter::TraversalSummary, }; pub(crate) struct TraverseResult { - pub(crate) summary: TraversalSummary, - pub(crate) evaluated_paths: BTreeSet, - pub(crate) diagnostics: Vec, + pub(crate) summary:TraversalSummary, + pub(crate) evaluated_paths:BTreeSet, + pub(crate) diagnostics:Vec, } pub(crate) fn traverse( - execution: &Execution, - session: &mut CliSession, - cli_options: &CliOptions, - mut inputs: Vec, + execution:&Execution, + session:&mut CliSession, + cli_options:&CliOptions, + mut inputs:Vec, ) -> Result { - init_thread_pool(); - - if inputs.is_empty() { - match &execution.traversal_mode { - TraversalMode::Check { .. } - | TraversalMode::Lint { .. } - | TraversalMode::Format { .. } - | TraversalMode::CI { .. } - | TraversalMode::Search { .. } => { - // If `--staged` or `--changed` is specified, it's acceptable for them to be empty, so ignore it. - if !execution.is_vcs_targeted() { - match current_dir() { - Ok(current_dir) => inputs.push(current_dir.into_os_string()), - Err(err) => return Err(CliDiagnostic::io_error(err)), - } - } - } - - _ => { - if execution.as_stdin_file().is_none() && !cli_options.no_errors_on_unmatched { - return Err(CliDiagnostic::missing_argument( - "", - format!("{}", execution.traversal_mode), - )); - } - } - } - } - - let (interner, recv_files) = PathInterner::new(); - - let (sender, receiver) = unbounded(); - - let changed = AtomicUsize::new(0); - - let unchanged = AtomicUsize::new(0); - - let matches = AtomicUsize::new(0); - - let skipped = AtomicUsize::new(0); - - let fs = &*session.app.fs; - - let workspace = &*session.app.workspace; - - let max_diagnostics = execution.get_max_diagnostics(); - - let remaining_diagnostics = AtomicU32::new(max_diagnostics); - - let printer = DiagnosticsPrinter::new(execution) - .with_verbose(cli_options.verbose) - .with_diagnostic_level(cli_options.diagnostic_level) - .with_max_diagnostics(max_diagnostics); - - let (duration, evaluated_paths, diagnostics) = thread::scope(|s| { - let handler = thread::Builder::new() - .name(String::from("biome::console")) - .spawn_scoped(s, || printer.run(receiver, recv_files)) - .expect("failed to spawn console thread"); - - // The traversal context is scoped to ensure all the channels it - // contains are properly closed once the traversal finishes - let (elapsed, evaluated_paths) = traverse_inputs( - fs, - inputs, - &TraversalOptions { - fs, - workspace, - execution, - interner, - matches: &matches, - changed: &changed, - unchanged: &unchanged, - skipped: &skipped, - messages: sender, - remaining_diagnostics: &remaining_diagnostics, - evaluated_paths: RwLock::default(), - }, - ); - // wait for the main thread to finish - let diagnostics = handler.join().unwrap(); - - (elapsed, evaluated_paths, diagnostics) - }); - - // Make sure patterns are always cleaned up at the end of traversal. - if let TraversalMode::Search { pattern, .. } = execution.traversal_mode() { - let _ = session.app.workspace.drop_pattern(DropPatternParams { - pattern: pattern.clone(), - }); - } - - let errors = printer.errors(); - - let warnings = printer.warnings(); - - let changed = changed.load(Ordering::Relaxed); - - let unchanged = unchanged.load(Ordering::Relaxed); - - let matches = matches.load(Ordering::Relaxed); - - let skipped = skipped.load(Ordering::Relaxed); - - let suggested_fixes_skipped = printer.skipped_fixes(); - - let diagnostics_not_printed = printer.not_printed_diagnostics(); - - Ok(TraverseResult { - summary: TraversalSummary { - changed, - unchanged, - duration, - errors, - matches, - warnings, - skipped, - suggested_fixes_skipped, - diagnostics_not_printed, - }, - evaluated_paths, - diagnostics, - }) + init_thread_pool(); + + if inputs.is_empty() { + match &execution.traversal_mode { + TraversalMode::Check { .. } + | TraversalMode::Lint { .. } + | TraversalMode::Format { .. } + | TraversalMode::CI { .. } + | TraversalMode::Search { .. } => { + // If `--staged` or `--changed` is specified, it's acceptable for them to be + // empty, so ignore it. + if !execution.is_vcs_targeted() { + match current_dir() { + Ok(current_dir) => inputs.push(current_dir.into_os_string()), + Err(err) => return Err(CliDiagnostic::io_error(err)), + } + } + }, + + _ => { + if execution.as_stdin_file().is_none() && !cli_options.no_errors_on_unmatched { + return Err(CliDiagnostic::missing_argument( + "", + format!("{}", execution.traversal_mode), + )); + } + }, + } + } + + let (interner, recv_files) = PathInterner::new(); + + let (sender, receiver) = unbounded(); + + let changed = AtomicUsize::new(0); + + let unchanged = AtomicUsize::new(0); + + let matches = AtomicUsize::new(0); + + let skipped = AtomicUsize::new(0); + + let fs = &*session.app.fs; + + let workspace = &*session.app.workspace; + + let max_diagnostics = execution.get_max_diagnostics(); + + let remaining_diagnostics = AtomicU32::new(max_diagnostics); + + let printer = DiagnosticsPrinter::new(execution) + .with_verbose(cli_options.verbose) + .with_diagnostic_level(cli_options.diagnostic_level) + .with_max_diagnostics(max_diagnostics); + + let (duration, evaluated_paths, diagnostics) = thread::scope(|s| { + let handler = thread::Builder::new() + .name(String::from("biome::console")) + .spawn_scoped(s, || printer.run(receiver, recv_files)) + .expect("failed to spawn console thread"); + + // The traversal context is scoped to ensure all the channels it + // contains are properly closed once the traversal finishes + let (elapsed, evaluated_paths) = traverse_inputs( + fs, + inputs, + &TraversalOptions { + fs, + workspace, + execution, + interner, + matches:&matches, + changed:&changed, + unchanged:&unchanged, + skipped:&skipped, + messages:sender, + remaining_diagnostics:&remaining_diagnostics, + evaluated_paths:RwLock::default(), + }, + ); + // wait for the main thread to finish + let diagnostics = handler.join().unwrap(); + + (elapsed, evaluated_paths, diagnostics) + }); + + // Make sure patterns are always cleaned up at the end of traversal. + if let TraversalMode::Search { pattern, .. } = execution.traversal_mode() { + let _ = session + .app + .workspace + .drop_pattern(DropPatternParams { pattern:pattern.clone() }); + } + + let errors = printer.errors(); + + let warnings = printer.warnings(); + + let changed = changed.load(Ordering::Relaxed); + + let unchanged = unchanged.load(Ordering::Relaxed); + + let matches = matches.load(Ordering::Relaxed); + + let skipped = skipped.load(Ordering::Relaxed); + + let suggested_fixes_skipped = printer.skipped_fixes(); + + let diagnostics_not_printed = printer.not_printed_diagnostics(); + + Ok(TraverseResult { + summary:TraversalSummary { + changed, + unchanged, + duration, + errors, + matches, + warnings, + skipped, + suggested_fixes_skipped, + diagnostics_not_printed, + }, + evaluated_paths, + diagnostics, + }) } -/// This function will setup the global Rayon thread pool the first time it's called +/// This function will setup the global Rayon thread pool the first time it's +/// called /// -/// This is currently only used to assign friendly debug names to the threads of the pool +/// This is currently only used to assign friendly debug names to the threads of +/// the pool fn init_thread_pool() { - static INIT_ONCE: Once = Once::new(); - - INIT_ONCE.call_once(|| { - rayon::ThreadPoolBuilder::new() - .thread_name(|index| format!("biome::worker_{index}")) - .build_global() - .expect("failed to initialize the global thread pool"); - }); + static INIT_ONCE:Once = Once::new(); + + INIT_ONCE.call_once(|| { + rayon::ThreadPoolBuilder::new() + .thread_name(|index| format!("biome::worker_{index}")) + .build_global() + .expect("failed to initialize the global thread pool"); + }); } /// Initiate the filesystem traversal tasks with the provided input paths and -/// run it to completion, returning the duration of the process and the evaluated paths -fn traverse_inputs( - fs: &dyn FileSystem, - inputs: Vec, - ctx: &TraversalOptions, -) -> (Duration, BTreeSet) { - let start = Instant::now(); +/// run it to completion, returning the duration of the process and the +/// evaluated paths +fn traverse_inputs(fs:&dyn FileSystem, inputs:Vec, ctx:&TraversalOptions) -> (Duration, BTreeSet) { + let start = Instant::now(); - fs.traversal(Box::new(move |scope: &dyn TraversalScope| { - for input in inputs { - scope.evaluate(ctx, PathBuf::from(input)); - } - })); + fs.traversal(Box::new(move |scope:&dyn TraversalScope| { + for input in inputs { + scope.evaluate(ctx, PathBuf::from(input)); + } + })); - let paths = ctx.evaluated_paths(); + let paths = ctx.evaluated_paths(); - let dome = Dome::new(paths); + let dome = Dome::new(paths); - let mut iter = dome.iter(); + let mut iter = dome.iter(); - fs.traversal(Box::new(|scope: &dyn TraversalScope| { - while let Some(path) = iter.next_config() { - scope.handle(ctx, path.to_path_buf()); - } + fs.traversal(Box::new(|scope:&dyn TraversalScope| { + while let Some(path) = iter.next_config() { + scope.handle(ctx, path.to_path_buf()); + } - while let Some(path) = iter.next_manifest() { - scope.handle(ctx, path.to_path_buf()); - } + while let Some(path) = iter.next_manifest() { + scope.handle(ctx, path.to_path_buf()); + } - for path in iter { - scope.handle(ctx, path.to_path_buf()); - } - })); + for path in iter { + scope.handle(ctx, path.to_path_buf()); + } + })); - (start.elapsed(), ctx.evaluated_paths()) + (start.elapsed(), ctx.evaluated_paths()) } // struct DiagnosticsReporter<'ctx> {} struct DiagnosticsPrinter<'ctx> { - /// Execution of the traversal - execution: &'ctx Execution, - /// The maximum number of diagnostics the console thread is allowed to print - max_diagnostics: u32, - /// The approximate number of diagnostics the console will print before - /// folding the rest into the "skipped diagnostics" counter - remaining_diagnostics: AtomicU32, - /// Mutable reference to a boolean flag tracking whether the console thread - /// printed any error-level message - errors: AtomicU32, - /// Mutable reference to a boolean flag tracking whether the console thread - /// printed any warnings-level message - warnings: AtomicU32, - /// Whether the console thread should print diagnostics in verbose mode - verbose: bool, - /// The diagnostic level the console thread should print - diagnostic_level: Severity, - - not_printed_diagnostics: AtomicU32, - printed_diagnostics: AtomicU32, - total_skipped_suggested_fixes: AtomicU32, + /// Execution of the traversal + execution:&'ctx Execution, + /// The maximum number of diagnostics the console thread is allowed to print + max_diagnostics:u32, + /// The approximate number of diagnostics the console will print before + /// folding the rest into the "skipped diagnostics" counter + remaining_diagnostics:AtomicU32, + /// Mutable reference to a boolean flag tracking whether the console thread + /// printed any error-level message + errors:AtomicU32, + /// Mutable reference to a boolean flag tracking whether the console thread + /// printed any warnings-level message + warnings:AtomicU32, + /// Whether the console thread should print diagnostics in verbose mode + verbose:bool, + /// The diagnostic level the console thread should print + diagnostic_level:Severity, + + not_printed_diagnostics:AtomicU32, + printed_diagnostics:AtomicU32, + total_skipped_suggested_fixes:AtomicU32, } impl<'ctx> DiagnosticsPrinter<'ctx> { - fn new(execution: &'ctx Execution) -> Self { - Self { - errors: AtomicU32::new(0), - warnings: AtomicU32::new(0), - remaining_diagnostics: AtomicU32::new(0), - execution, - diagnostic_level: Severity::Hint, - verbose: false, - max_diagnostics: 20, - not_printed_diagnostics: AtomicU32::new(0), - printed_diagnostics: AtomicU32::new(0), - total_skipped_suggested_fixes: AtomicU32::new(0), - } - } - - fn with_verbose(mut self, verbose: bool) -> Self { - self.verbose = verbose; - - self - } - - fn with_max_diagnostics(mut self, value: u32) -> Self { - self.max_diagnostics = value; - - self - } - - fn with_diagnostic_level(mut self, value: Severity) -> Self { - self.diagnostic_level = value; - - self - } - - fn errors(&self) -> u32 { - self.errors.load(Ordering::Relaxed) - } - - fn warnings(&self) -> u32 { - self.warnings.load(Ordering::Relaxed) - } - - fn not_printed_diagnostics(&self) -> u32 { - self.not_printed_diagnostics.load(Ordering::Relaxed) - } - - fn skipped_fixes(&self) -> u32 { - self.total_skipped_suggested_fixes.load(Ordering::Relaxed) - } - - /// Checks if the diagnostic we received from the thread should be considered or not. Logic: - /// - it should not be considered if its severity level is lower than the one provided via CLI; - /// - it should not be considered if it's a verbose diagnostic and the CLI **didn't** request a `--verbose` option. - fn should_skip_diagnostic(&self, severity: Severity, diagnostic_tags: DiagnosticTags) -> bool { - if severity < self.diagnostic_level { - return true; - } - - if diagnostic_tags.is_verbose() && !self.verbose { - return true; - } - - false - } - - /// Count the diagnostic, and then returns a boolean that tells if it should be printed - fn should_print(&self) -> bool { - let printed_diagnostics = self.printed_diagnostics.load(Ordering::Relaxed); - - let should_print = printed_diagnostics < self.max_diagnostics; - - if should_print { - self.printed_diagnostics.fetch_add(1, Ordering::Relaxed); - - self.remaining_diagnostics.store( - self.max_diagnostics.saturating_sub(printed_diagnostics), - Ordering::Relaxed, - ); - } else { - self.not_printed_diagnostics.fetch_add(1, Ordering::Relaxed); - } - - should_print - } - - fn run(&self, receiver: Receiver, interner: Receiver) -> Vec { - let mut paths: FxHashSet = FxHashSet::default(); - - let mut diagnostics_to_print = vec![]; - - while let Ok(msg) = receiver.recv() { - match msg { - Message::SkippedFixes { - skipped_suggested_fixes, - } => { - self.total_skipped_suggested_fixes - .fetch_add(skipped_suggested_fixes, Ordering::Relaxed); - } - - Message::Failure => { - self.errors.fetch_add(1, Ordering::Relaxed); - } - - Message::Error(mut err) => { - let location = err.location(); - - if self.should_skip_diagnostic(err.severity(), err.tags()) { - continue; - } - - if err.severity() == Severity::Warning { - // *warnings += 1; - - self.warnings.fetch_add(1, Ordering::Relaxed); - // self.warnings.set(self.warnings.get() + 1) - } - - if let Some(Resource::File(file_path)) = location.resource.as_ref() { - // Retrieves the file name from the file ID cache, if it's a miss - // flush entries from the interner channel until it's found - let file_name = match paths.get(*file_path) { - Some(path) => Some(path), - None => loop { - match interner.recv() { - Ok(path) => { - paths.insert(path.display().to_string()); - - if path.display().to_string() == *file_path { - break paths.get(&path.display().to_string()); - } - } - // In case the channel disconnected without sending - // the path we need, print the error without a file - // name (normally this should never happen) - Err(_) => break None, - } - }, - }; - - if let Some(path) = file_name { - err = err.with_file_path(path.as_str()); - } - } - - let should_print = self.should_print(); - - if should_print { - diagnostics_to_print.push(err); - } - } - - Message::Diagnostics { - name, - content, - diagnostics, - skipped_diagnostics, - } => { - self.not_printed_diagnostics - .fetch_add(skipped_diagnostics, Ordering::Relaxed); - - // is CI mode we want to print all the diagnostics - if self.execution.is_ci() { - for diag in diagnostics { - let severity = diag.severity(); - - if self.should_skip_diagnostic(severity, diag.tags()) { - continue; - } - - if severity == Severity::Error { - self.errors.fetch_add(1, Ordering::Relaxed); - } - - if severity == Severity::Warning { - self.warnings.fetch_add(1, Ordering::Relaxed); - } - - let diag = diag.with_file_path(&name).with_file_source_code(&content); - - diagnostics_to_print.push(diag); - } - } else { - for diag in diagnostics { - let severity = diag.severity(); - - if self.should_skip_diagnostic(severity, diag.tags()) { - continue; - } - - if severity == Severity::Error { - self.errors.fetch_add(1, Ordering::Relaxed); - } - - if severity == Severity::Warning { - self.warnings.fetch_add(1, Ordering::Relaxed); - } - - let should_print = self.should_print(); - - if should_print { - let diag = - diag.with_file_path(&name).with_file_source_code(&content); - - diagnostics_to_print.push(diag) - } - } - } - } - - Message::Diff { - file_name, - old, - new, - diff_kind, - } => { - // A diff is an error in CI mode and in format check mode - let is_error = self.execution.is_ci() || !self.execution.is_format_write(); - - if is_error { - self.errors.fetch_add(1, Ordering::Relaxed); - } - - let severity: Severity = if is_error { - Severity::Error - } else { - // we set lowest - Severity::Hint - }; - - if self.should_skip_diagnostic(severity, DiagnosticTags::empty()) { - continue; - } - - let should_print = self.should_print(); - - if should_print { - if self.execution.is_ci() { - match diff_kind { - DiffKind::Format => { - let diag = CIFormatDiffDiagnostic { - file_name: file_name.clone(), - diff: ContentDiffAdvice { - old: old.clone(), - new: new.clone(), - }, - }; - - diagnostics_to_print.push( - diag.with_severity(severity) - .with_file_source_code(old.clone()), - ); - } - - DiffKind::OrganizeImports => { - let diag = CIOrganizeImportsDiffDiagnostic { - file_name: file_name.clone(), - diff: ContentDiffAdvice { - old: old.clone(), - new: new.clone(), - }, - }; - - diagnostics_to_print.push( - diag.with_severity(severity) - .with_file_source_code(old.clone()), - ); - } - - DiffKind::Assists => { - let diag = CIAssistsDiffDiagnostic { - file_name: file_name.clone(), - diff: ContentDiffAdvice { - old: old.clone(), - new: new.clone(), - }, - }; - - diagnostics_to_print.push( - diag.with_severity(severity) - .with_file_source_code(old.clone()), - ) - } - }; - } else { - match diff_kind { - DiffKind::Format => { - let diag = FormatDiffDiagnostic { - file_name: file_name.clone(), - diff: ContentDiffAdvice { - old: old.clone(), - new: new.clone(), - }, - }; - - diagnostics_to_print.push( - diag.with_severity(severity) - .with_file_source_code(old.clone()), - ) - } - - DiffKind::OrganizeImports => { - let diag = OrganizeImportsDiffDiagnostic { - file_name: file_name.clone(), - diff: ContentDiffAdvice { - old: old.clone(), - new: new.clone(), - }, - }; - - diagnostics_to_print.push( - diag.with_severity(severity) - .with_file_source_code(old.clone()), - ) - } - - DiffKind::Assists => { - let diag = AssistsDiffDiagnostic { - file_name: file_name.clone(), - diff: ContentDiffAdvice { - old: old.clone(), - new: new.clone(), - }, - }; - - diagnostics_to_print.push( - diag.with_severity(severity) - .with_file_source_code(old.clone()), - ) - } - }; - } - } - } - } - } - - diagnostics_to_print - } + fn new(execution:&'ctx Execution) -> Self { + Self { + errors:AtomicU32::new(0), + warnings:AtomicU32::new(0), + remaining_diagnostics:AtomicU32::new(0), + execution, + diagnostic_level:Severity::Hint, + verbose:false, + max_diagnostics:20, + not_printed_diagnostics:AtomicU32::new(0), + printed_diagnostics:AtomicU32::new(0), + total_skipped_suggested_fixes:AtomicU32::new(0), + } + } + + fn with_verbose(mut self, verbose:bool) -> Self { + self.verbose = verbose; + + self + } + + fn with_max_diagnostics(mut self, value:u32) -> Self { + self.max_diagnostics = value; + + self + } + + fn with_diagnostic_level(mut self, value:Severity) -> Self { + self.diagnostic_level = value; + + self + } + + fn errors(&self) -> u32 { self.errors.load(Ordering::Relaxed) } + + fn warnings(&self) -> u32 { self.warnings.load(Ordering::Relaxed) } + + fn not_printed_diagnostics(&self) -> u32 { self.not_printed_diagnostics.load(Ordering::Relaxed) } + + fn skipped_fixes(&self) -> u32 { self.total_skipped_suggested_fixes.load(Ordering::Relaxed) } + + /// Checks if the diagnostic we received from the thread should be + /// considered or not. Logic: + /// - it should not be considered if its severity level is lower than the + /// one provided via CLI; + /// - it should not be considered if it's a verbose diagnostic and the CLI + /// **didn't** request a `--verbose` option. + fn should_skip_diagnostic(&self, severity:Severity, diagnostic_tags:DiagnosticTags) -> bool { + if severity < self.diagnostic_level { + return true; + } + + if diagnostic_tags.is_verbose() && !self.verbose { + return true; + } + + false + } + + /// Count the diagnostic, and then returns a boolean that tells if it should + /// be printed + fn should_print(&self) -> bool { + let printed_diagnostics = self.printed_diagnostics.load(Ordering::Relaxed); + + let should_print = printed_diagnostics < self.max_diagnostics; + + if should_print { + self.printed_diagnostics.fetch_add(1, Ordering::Relaxed); + + self.remaining_diagnostics + .store(self.max_diagnostics.saturating_sub(printed_diagnostics), Ordering::Relaxed); + } else { + self.not_printed_diagnostics.fetch_add(1, Ordering::Relaxed); + } + + should_print + } + + fn run(&self, receiver:Receiver, interner:Receiver) -> Vec { + let mut paths:FxHashSet = FxHashSet::default(); + + let mut diagnostics_to_print = vec![]; + + while let Ok(msg) = receiver.recv() { + match msg { + Message::SkippedFixes { skipped_suggested_fixes } => { + self.total_skipped_suggested_fixes + .fetch_add(skipped_suggested_fixes, Ordering::Relaxed); + }, + + Message::Failure => { + self.errors.fetch_add(1, Ordering::Relaxed); + }, + + Message::Error(mut err) => { + let location = err.location(); + + if self.should_skip_diagnostic(err.severity(), err.tags()) { + continue; + } + + if err.severity() == Severity::Warning { + // *warnings += 1; + + self.warnings.fetch_add(1, Ordering::Relaxed); + // self.warnings.set(self.warnings.get() + 1) + } + + if let Some(Resource::File(file_path)) = location.resource.as_ref() { + // Retrieves the file name from the file ID cache, if it's a miss + // flush entries from the interner channel until it's found + let file_name = match paths.get(*file_path) { + Some(path) => Some(path), + None => { + loop { + match interner.recv() { + Ok(path) => { + paths.insert(path.display().to_string()); + + if path.display().to_string() == *file_path { + break paths.get(&path.display().to_string()); + } + }, + // In case the channel disconnected without sending + // the path we need, print the error without a file + // name (normally this should never happen) + Err(_) => break None, + } + } + }, + }; + + if let Some(path) = file_name { + err = err.with_file_path(path.as_str()); + } + } + + let should_print = self.should_print(); + + if should_print { + diagnostics_to_print.push(err); + } + }, + + Message::Diagnostics { name, content, diagnostics, skipped_diagnostics } => { + self.not_printed_diagnostics.fetch_add(skipped_diagnostics, Ordering::Relaxed); + + // is CI mode we want to print all the diagnostics + if self.execution.is_ci() { + for diag in diagnostics { + let severity = diag.severity(); + + if self.should_skip_diagnostic(severity, diag.tags()) { + continue; + } + + if severity == Severity::Error { + self.errors.fetch_add(1, Ordering::Relaxed); + } + + if severity == Severity::Warning { + self.warnings.fetch_add(1, Ordering::Relaxed); + } + + let diag = diag.with_file_path(&name).with_file_source_code(&content); + + diagnostics_to_print.push(diag); + } + } else { + for diag in diagnostics { + let severity = diag.severity(); + + if self.should_skip_diagnostic(severity, diag.tags()) { + continue; + } + + if severity == Severity::Error { + self.errors.fetch_add(1, Ordering::Relaxed); + } + + if severity == Severity::Warning { + self.warnings.fetch_add(1, Ordering::Relaxed); + } + + let should_print = self.should_print(); + + if should_print { + let diag = diag.with_file_path(&name).with_file_source_code(&content); + + diagnostics_to_print.push(diag) + } + } + } + }, + + Message::Diff { file_name, old, new, diff_kind } => { + // A diff is an error in CI mode and in format check mode + let is_error = self.execution.is_ci() || !self.execution.is_format_write(); + + if is_error { + self.errors.fetch_add(1, Ordering::Relaxed); + } + + let severity:Severity = if is_error { + Severity::Error + } else { + // we set lowest + Severity::Hint + }; + + if self.should_skip_diagnostic(severity, DiagnosticTags::empty()) { + continue; + } + + let should_print = self.should_print(); + + if should_print { + if self.execution.is_ci() { + match diff_kind { + DiffKind::Format => { + let diag = CIFormatDiffDiagnostic { + file_name:file_name.clone(), + diff:ContentDiffAdvice { old:old.clone(), new:new.clone() }, + }; + + diagnostics_to_print + .push(diag.with_severity(severity).with_file_source_code(old.clone())); + }, + + DiffKind::OrganizeImports => { + let diag = CIOrganizeImportsDiffDiagnostic { + file_name:file_name.clone(), + diff:ContentDiffAdvice { old:old.clone(), new:new.clone() }, + }; + + diagnostics_to_print + .push(diag.with_severity(severity).with_file_source_code(old.clone())); + }, + + DiffKind::Assists => { + let diag = CIAssistsDiffDiagnostic { + file_name:file_name.clone(), + diff:ContentDiffAdvice { old:old.clone(), new:new.clone() }, + }; + + diagnostics_to_print + .push(diag.with_severity(severity).with_file_source_code(old.clone())) + }, + }; + } else { + match diff_kind { + DiffKind::Format => { + let diag = FormatDiffDiagnostic { + file_name:file_name.clone(), + diff:ContentDiffAdvice { old:old.clone(), new:new.clone() }, + }; + + diagnostics_to_print + .push(diag.with_severity(severity).with_file_source_code(old.clone())) + }, + + DiffKind::OrganizeImports => { + let diag = OrganizeImportsDiffDiagnostic { + file_name:file_name.clone(), + diff:ContentDiffAdvice { old:old.clone(), new:new.clone() }, + }; + + diagnostics_to_print + .push(diag.with_severity(severity).with_file_source_code(old.clone())) + }, + + DiffKind::Assists => { + let diag = AssistsDiffDiagnostic { + file_name:file_name.clone(), + diff:ContentDiffAdvice { old:old.clone(), new:new.clone() }, + }; + + diagnostics_to_print + .push(diag.with_severity(severity).with_file_source_code(old.clone())) + }, + }; + } + } + }, + } + } + + diagnostics_to_print + } } /// Context object shared between directory traversal tasks pub(crate) struct TraversalOptions<'ctx, 'app> { - /// Shared instance of [FileSystem] - pub(crate) fs: &'app dyn FileSystem, - /// Instance of [Workspace] used by this instance of the CLI - pub(crate) workspace: &'ctx dyn Workspace, - /// Determines how the files should be processed - pub(crate) execution: &'ctx Execution, - /// File paths interner cache used by the filesystem traversal - interner: PathInterner, - /// Shared atomic counter storing the number of changed files - changed: &'ctx AtomicUsize, - /// Shared atomic counter storing the number of unchanged files - unchanged: &'ctx AtomicUsize, - /// Shared atomic counter storing the number of unchanged files - matches: &'ctx AtomicUsize, - /// Shared atomic counter storing the number of skipped files - skipped: &'ctx AtomicUsize, - /// Channel sending messages to the display thread - pub(crate) messages: Sender, - /// The approximate number of diagnostics the console will print before - /// folding the rest into the "skipped diagnostics" counter - pub(crate) remaining_diagnostics: &'ctx AtomicU32, - - /// List of paths that should be processed - pub(crate) evaluated_paths: RwLock>, + /// Shared instance of [FileSystem] + pub(crate) fs:&'app dyn FileSystem, + /// Instance of [Workspace] used by this instance of the CLI + pub(crate) workspace:&'ctx dyn Workspace, + /// Determines how the files should be processed + pub(crate) execution:&'ctx Execution, + /// File paths interner cache used by the filesystem traversal + interner:PathInterner, + /// Shared atomic counter storing the number of changed files + changed:&'ctx AtomicUsize, + /// Shared atomic counter storing the number of unchanged files + unchanged:&'ctx AtomicUsize, + /// Shared atomic counter storing the number of unchanged files + matches:&'ctx AtomicUsize, + /// Shared atomic counter storing the number of skipped files + skipped:&'ctx AtomicUsize, + /// Channel sending messages to the display thread + pub(crate) messages:Sender, + /// The approximate number of diagnostics the console will print before + /// folding the rest into the "skipped diagnostics" counter + pub(crate) remaining_diagnostics:&'ctx AtomicU32, + + /// List of paths that should be processed + pub(crate) evaluated_paths:RwLock>, } impl<'ctx, 'app> TraversalOptions<'ctx, 'app> { - pub(crate) fn increment_changed(&self, path: &BiomePath) { - self.changed.fetch_add(1, Ordering::Relaxed); - - self.evaluated_paths - .write() - .unwrap() - .replace(path.to_written()); - } - - pub(crate) fn increment_unchanged(&self) { - self.unchanged.fetch_add(1, Ordering::Relaxed); - } - - pub(crate) fn increment_matches(&self, num_matches: usize) { - self.matches.fetch_add(num_matches, Ordering::Relaxed); - } - - /// Send a message to the display thread - pub(crate) fn push_message(&self, msg: impl Into) { - self.messages.send(msg.into()).ok(); - } - - pub(crate) fn miss_handler_err(&self, err: WorkspaceError, biome_path: &BiomePath) { - self.push_diagnostic( - err.with_category(category!("files/missingHandler")) - .with_file_path(biome_path.display().to_string()) - .with_tags(DiagnosticTags::VERBOSE), - ); - } - - pub(crate) fn protected_file(&self, biome_path: &BiomePath) { - self.push_diagnostic( - WorkspaceError::protected_file(biome_path.display().to_string()).into(), - ) - } + pub(crate) fn increment_changed(&self, path:&BiomePath) { + self.changed.fetch_add(1, Ordering::Relaxed); + + self.evaluated_paths.write().unwrap().replace(path.to_written()); + } + + pub(crate) fn increment_unchanged(&self) { self.unchanged.fetch_add(1, Ordering::Relaxed); } + + pub(crate) fn increment_matches(&self, num_matches:usize) { + self.matches.fetch_add(num_matches, Ordering::Relaxed); + } + + /// Send a message to the display thread + pub(crate) fn push_message(&self, msg:impl Into) { self.messages.send(msg.into()).ok(); } + + pub(crate) fn miss_handler_err(&self, err:WorkspaceError, biome_path:&BiomePath) { + self.push_diagnostic( + err.with_category(category!("files/missingHandler")) + .with_file_path(biome_path.display().to_string()) + .with_tags(DiagnosticTags::VERBOSE), + ); + } + + pub(crate) fn protected_file(&self, biome_path:&BiomePath) { + self.push_diagnostic(WorkspaceError::protected_file(biome_path.display().to_string()).into()) + } } impl<'ctx, 'app> TraversalContext for TraversalOptions<'ctx, 'app> { - fn interner(&self) -> &PathInterner { - &self.interner - } - - fn evaluated_paths(&self) -> BTreeSet { - self.evaluated_paths.read().unwrap().clone() - } - - fn push_diagnostic(&self, error: Error) { - self.push_message(error); - } - - fn can_handle(&self, biome_path: &BiomePath) -> bool { - let path = biome_path.as_path(); - - if self.fs.path_is_dir(path) || self.fs.path_is_symlink(path) { - // handle: - // - directories - // - symlinks - // - unresolved symlinks - // e.g `symlink/subdir` where symlink points to a directory that includes `subdir`. - // Note that `symlink/subdir` is not an existing file. - let can_handle = !self - .workspace - .is_path_ignored(IsPathIgnoredParams { - biome_path: biome_path.clone(), - features: self.execution.to_feature(), - }) - .unwrap_or_else(|err| { - self.push_diagnostic(err.into()); - - false - }); - - return can_handle; - } - - // bail on fifo and socket files - if !self.fs.path_is_file(path) { - return false; - } - - let file_features = self.workspace.file_features(SupportsFeatureParams { - path: biome_path.clone(), - features: self.execution.to_feature(), - }); - - let file_features = match file_features { - Ok(file_features) => { - if file_features.is_protected() { - self.protected_file(biome_path); - - return false; - } - - if file_features.is_not_supported() && !file_features.is_ignored() { - // we should throw a diagnostic if we can't handle a file that isn't ignored - self.miss_handler_err(extension_error(biome_path), biome_path); - - return false; - } - - file_features - } - - Err(err) => { - self.miss_handler_err(err, biome_path); - - return false; - } - }; - - match self.execution.traversal_mode() { - TraversalMode::Check { .. } | TraversalMode::CI { .. } => { - file_features.supports_lint() - || file_features.supports_format() - || file_features.supports_organize_imports() - } - - TraversalMode::Format { .. } => file_features.supports_format(), - TraversalMode::Lint { .. } => file_features.supports_lint(), - // Imagine if Biome can't handle its own configuration file... - TraversalMode::Migrate { .. } => true, - TraversalMode::Search { .. } => file_features.supports_search(), - } - } - - fn handle_path(&self, path: BiomePath) { - handle_file(self, &path) - } - - fn store_path(&self, path: BiomePath) { - self.evaluated_paths - .write() - .unwrap() - .insert(BiomePath::new(path.as_path())); - } + fn interner(&self) -> &PathInterner { &self.interner } + + fn evaluated_paths(&self) -> BTreeSet { self.evaluated_paths.read().unwrap().clone() } + + fn push_diagnostic(&self, error:Error) { self.push_message(error); } + + fn can_handle(&self, biome_path:&BiomePath) -> bool { + let path = biome_path.as_path(); + + if self.fs.path_is_dir(path) || self.fs.path_is_symlink(path) { + // handle: + // - directories + // - symlinks + // - unresolved symlinks e.g `symlink/subdir` where symlink points to a + // directory that includes `subdir`. Note that `symlink/subdir` is not an + // existing file. + let can_handle = !self + .workspace + .is_path_ignored(IsPathIgnoredParams { + biome_path:biome_path.clone(), + features:self.execution.to_feature(), + }) + .unwrap_or_else(|err| { + self.push_diagnostic(err.into()); + + false + }); + + return can_handle; + } + + // bail on fifo and socket files + if !self.fs.path_is_file(path) { + return false; + } + + let file_features = self + .workspace + .file_features(SupportsFeatureParams { path:biome_path.clone(), features:self.execution.to_feature() }); + + let file_features = match file_features { + Ok(file_features) => { + if file_features.is_protected() { + self.protected_file(biome_path); + + return false; + } + + if file_features.is_not_supported() && !file_features.is_ignored() { + // we should throw a diagnostic if we can't handle a file that isn't ignored + self.miss_handler_err(extension_error(biome_path), biome_path); + + return false; + } + + file_features + }, + + Err(err) => { + self.miss_handler_err(err, biome_path); + + return false; + }, + }; + + match self.execution.traversal_mode() { + TraversalMode::Check { .. } | TraversalMode::CI { .. } => { + file_features.supports_lint() + || file_features.supports_format() + || file_features.supports_organize_imports() + }, + + TraversalMode::Format { .. } => file_features.supports_format(), + TraversalMode::Lint { .. } => file_features.supports_lint(), + // Imagine if Biome can't handle its own configuration file... + TraversalMode::Migrate { .. } => true, + TraversalMode::Search { .. } => file_features.supports_search(), + } + } + + fn handle_path(&self, path:BiomePath) { handle_file(self, &path) } + + fn store_path(&self, path:BiomePath) { + self.evaluated_paths.write().unwrap().insert(BiomePath::new(path.as_path())); + } } /// This function wraps the [process_file] function implementing the traversal /// in a [catch_unwind] block and emit diagnostics in case of error (either the /// traversal function returns Err or panics) -fn handle_file(ctx: &TraversalOptions, path: &BiomePath) { - match catch_unwind(move || process_file(ctx, path)) { - Ok(Ok(FileStatus::Changed)) => { - ctx.increment_changed(path); - } +fn handle_file(ctx:&TraversalOptions, path:&BiomePath) { + match catch_unwind(move || process_file(ctx, path)) { + Ok(Ok(FileStatus::Changed)) => { + ctx.increment_changed(path); + }, - Ok(Ok(FileStatus::Unchanged)) => { - ctx.increment_unchanged(); - } + Ok(Ok(FileStatus::Unchanged)) => { + ctx.increment_unchanged(); + }, - Ok(Ok(FileStatus::SearchResult(num_matches, msg))) => { - ctx.increment_unchanged(); + Ok(Ok(FileStatus::SearchResult(num_matches, msg))) => { + ctx.increment_unchanged(); - ctx.increment_matches(num_matches); + ctx.increment_matches(num_matches); - ctx.push_message(msg); - } + ctx.push_message(msg); + }, - Ok(Ok(FileStatus::Message(msg))) => { - ctx.increment_unchanged(); + Ok(Ok(FileStatus::Message(msg))) => { + ctx.increment_unchanged(); - ctx.push_message(msg); - } + ctx.push_message(msg); + }, - Ok(Ok(FileStatus::Protected(file_path))) => { - ctx.increment_unchanged(); + Ok(Ok(FileStatus::Protected(file_path))) => { + ctx.increment_unchanged(); - ctx.push_diagnostic(WorkspaceError::protected_file(file_path).into()); - } + ctx.push_diagnostic(WorkspaceError::protected_file(file_path).into()); + }, - Ok(Ok(FileStatus::Ignored)) => {} + Ok(Ok(FileStatus::Ignored)) => {}, - Ok(Err(err)) => { - ctx.increment_unchanged(); + Ok(Err(err)) => { + ctx.increment_unchanged(); - ctx.skipped.fetch_add(1, Ordering::Relaxed); + ctx.skipped.fetch_add(1, Ordering::Relaxed); - ctx.push_message(err); - } + ctx.push_message(err); + }, - Err(err) => { - let message = match err.downcast::() { - Ok(msg) => format!("processing panicked: {msg}"), - Err(err) => match err.downcast::<&'static str>() { - Ok(msg) => format!("processing panicked: {msg}"), - Err(_) => String::from("processing panicked"), - }, - }; + Err(err) => { + let message = match err.downcast::() { + Ok(msg) => format!("processing panicked: {msg}"), + Err(err) => { + match err.downcast::<&'static str>() { + Ok(msg) => format!("processing panicked: {msg}"), + Err(_) => String::from("processing panicked"), + } + }, + }; - ctx.push_message( - PanicDiagnostic { message }.with_file_path(path.display().to_string()), - ); - } - } + ctx.push_message(PanicDiagnostic { message }.with_file_path(path.display().to_string())); + }, + } } diff --git a/crates/biome_cli/Source/lib.rs b/crates/biome_cli/Source/lib.rs index 90a2a2a667da..b7f7892d9ac3 100644 --- a/crates/biome_cli/Source/lib.rs +++ b/crates/biome_cli/Source/lib.rs @@ -58,10 +58,7 @@ pub struct CliSession<'app> { } impl<'app> CliSession<'app> { - pub fn new( - workspace:&'app dyn Workspace, - console:&'app mut dyn Console, - ) -> Result { + pub fn new(workspace:&'app dyn Workspace, console:&'app mut dyn Console) -> Result { Ok(Self { app:App::new( DynRef::Owned(Box::::default()), @@ -281,27 +278,11 @@ impl<'app> CliSession<'app> { run_command( self, &cli_options, - SearchCommandPayload { - files_configuration, - paths, - pattern, - stdin_file_path, - vcs_configuration, - }, + SearchCommandPayload { files_configuration, paths, pattern, stdin_file_path, vcs_configuration }, ) }, - BiomeCommand::RunServer { - stop_on_disconnect, - config_path, - log_path, - log_prefix_name, - } => { - commands::daemon::run_server( - stop_on_disconnect, - config_path, - Some(log_path), - Some(log_prefix_name), - ) + BiomeCommand::RunServer { stop_on_disconnect, config_path, log_path, log_prefix_name } => { + commands::daemon::run_server(stop_on_disconnect, config_path, Some(log_path), Some(log_prefix_name)) }, BiomeCommand::PrintSocket => commands::daemon::print_socket(), }; diff --git a/crates/biome_cli/Source/logging.rs b/crates/biome_cli/Source/logging.rs index 95e645242a92..dc123e7fae28 100644 --- a/crates/biome_cli/Source/logging.rs +++ b/crates/biome_cli/Source/logging.rs @@ -104,8 +104,7 @@ struct LoggingFilter { } /// Tracing filter used for spans emitted by `biome*` crates -const SELF_FILTER:LevelFilter = - if cfg!(debug_assertions) { LevelFilter::TRACE } else { LevelFilter::DEBUG }; +const SELF_FILTER:LevelFilter = if cfg!(debug_assertions) { LevelFilter::TRACE } else { LevelFilter::DEBUG }; impl LoggingFilter { fn is_enabled(&self, meta:&Metadata<'_>) -> bool { diff --git a/crates/biome_cli/Source/metrics.rs b/crates/biome_cli/Source/metrics.rs index 979beecb5fc4..ed8508ef90f1 100644 --- a/crates/biome_cli/Source/metrics.rs +++ b/crates/biome_cli/Source/metrics.rs @@ -21,8 +21,7 @@ use tracing_subscriber::{ /// spans into [Histogram]s struct MetricsLayer; -static METRICS:LazyLock>>> = - LazyLock::new(RwLock::default); +static METRICS:LazyLock>>> = LazyLock::new(RwLock::default); /// Static pointer to the metadata of a callsite, used as a unique identifier /// for collecting spans created from there in the global metrics map diff --git a/crates/biome_cli/Source/reporter/github.rs b/crates/biome_cli/Source/reporter/github.rs index 96762b661f91..3a9a054486f1 100644 --- a/crates/biome_cli/Source/reporter/github.rs +++ b/crates/biome_cli/Source/reporter/github.rs @@ -1,46 +1,38 @@ -use crate::{DiagnosticsPayload, Execution, Reporter, ReporterVisitor, TraversalSummary}; -use biome_console::{markup, Console, ConsoleExt}; -use biome_diagnostics::PrintGitHubDiagnostic; use std::io; +use biome_console::{Console, ConsoleExt, markup}; +use biome_diagnostics::PrintGitHubDiagnostic; + +use crate::{DiagnosticsPayload, Execution, Reporter, ReporterVisitor, TraversalSummary}; + pub(crate) struct GithubReporter { - pub(crate) diagnostics_payload: DiagnosticsPayload, - pub(crate) execution: Execution, + pub(crate) diagnostics_payload:DiagnosticsPayload, + pub(crate) execution:Execution, } impl Reporter for GithubReporter { - fn write(self, visitor: &mut dyn ReporterVisitor) -> io::Result<()> { - visitor.report_diagnostics(&self.execution, self.diagnostics_payload)?; + fn write(self, visitor:&mut dyn ReporterVisitor) -> io::Result<()> { + visitor.report_diagnostics(&self.execution, self.diagnostics_payload)?; - Ok(()) - } + Ok(()) + } } pub(crate) struct GithubReporterVisitor<'a>(pub(crate) &'a mut dyn Console); impl<'a> ReporterVisitor for GithubReporterVisitor<'a> { - fn report_summary( - &mut self, - _execution: &Execution, - _summary: TraversalSummary, - ) -> io::Result<()> { - Ok(()) - } - - fn report_diagnostics( - &mut self, - _execution: &Execution, - diagnostics_payload: DiagnosticsPayload, - ) -> io::Result<()> { - for diagnostic in &diagnostics_payload.diagnostics { - if diagnostic.severity() >= diagnostics_payload.diagnostic_level { - if diagnostic.tags().is_verbose() && diagnostics_payload.verbose { - self.0.log(markup! {{PrintGitHubDiagnostic(diagnostic)}}); - } else if !diagnostics_payload.verbose { - self.0.log(markup! {{PrintGitHubDiagnostic(diagnostic)}}); - } - } - } - - Ok(()) - } + fn report_summary(&mut self, _execution:&Execution, _summary:TraversalSummary) -> io::Result<()> { Ok(()) } + + fn report_diagnostics(&mut self, _execution:&Execution, diagnostics_payload:DiagnosticsPayload) -> io::Result<()> { + for diagnostic in &diagnostics_payload.diagnostics { + if diagnostic.severity() >= diagnostics_payload.diagnostic_level { + if diagnostic.tags().is_verbose() && diagnostics_payload.verbose { + self.0.log(markup! {{PrintGitHubDiagnostic(diagnostic)}}); + } else if !diagnostics_payload.verbose { + self.0.log(markup! {{PrintGitHubDiagnostic(diagnostic)}}); + } + } + } + + Ok(()) + } } diff --git a/crates/biome_cli/Source/reporter/gitlab.rs b/crates/biome_cli/Source/reporter/gitlab.rs index d2449d5c2071..1d89046f6131 100644 --- a/crates/biome_cli/Source/reporter/gitlab.rs +++ b/crates/biome_cli/Source/reporter/gitlab.rs @@ -1,268 +1,237 @@ -use crate::{DiagnosticsPayload, Execution, Reporter, ReporterVisitor, TraversalSummary}; -use biome_console::fmt::{Display, Formatter}; -use biome_console::{markup, Console, ConsoleExt}; -use biome_diagnostics::display::SourceFile; -use biome_diagnostics::{Error, PrintDescription, Resource, Severity}; -use path_absolutize::Absolutize; -use serde::Serialize; -use std::sync::RwLock; use std::{ - collections::HashSet, - hash::{DefaultHasher, Hash, Hasher}, - path::{Path, PathBuf}, + collections::HashSet, + hash::{DefaultHasher, Hash, Hasher}, + path::{Path, PathBuf}, + sync::RwLock, +}; + +use biome_console::{ + Console, + ConsoleExt, + fmt::{Display, Formatter}, + markup, }; +use biome_diagnostics::{Error, PrintDescription, Resource, Severity, display::SourceFile}; +use path_absolutize::Absolutize; +use serde::Serialize; + +use crate::{DiagnosticsPayload, Execution, Reporter, ReporterVisitor, TraversalSummary}; pub struct GitLabReporter { - pub execution: Execution, - pub diagnostics: DiagnosticsPayload, + pub execution:Execution, + pub diagnostics:DiagnosticsPayload, } impl Reporter for GitLabReporter { - fn write(self, visitor: &mut dyn ReporterVisitor) -> std::io::Result<()> { - visitor.report_diagnostics(&self.execution, self.diagnostics)?; + fn write(self, visitor:&mut dyn ReporterVisitor) -> std::io::Result<()> { + visitor.report_diagnostics(&self.execution, self.diagnostics)?; - Ok(()) - } + Ok(()) + } } pub(crate) struct GitLabReporterVisitor<'a> { - console: &'a mut dyn Console, - repository_root: Option, + console:&'a mut dyn Console, + repository_root:Option, } #[derive(Default)] struct GitLabHasher(HashSet); impl GitLabHasher { - /// Enforces uniqueness of generated fingerprints in the context of a - /// single report. - fn rehash_until_unique(&mut self, fingerprint: u64) -> u64 { - let mut current = fingerprint; + /// Enforces uniqueness of generated fingerprints in the context of a + /// single report. + fn rehash_until_unique(&mut self, fingerprint:u64) -> u64 { + let mut current = fingerprint; - while self.0.contains(¤t) { - let mut hasher = DefaultHasher::new(); + while self.0.contains(¤t) { + let mut hasher = DefaultHasher::new(); - current.hash(&mut hasher); + current.hash(&mut hasher); - current = hasher.finish(); - } + current = hasher.finish(); + } - self.0.insert(current); + self.0.insert(current); - current - } + current + } } impl<'a> GitLabReporterVisitor<'a> { - pub fn new(console: &'a mut dyn Console, repository_root: Option) -> Self { - Self { - console, - repository_root, - } - } + pub fn new(console:&'a mut dyn Console, repository_root:Option) -> Self { + Self { console, repository_root } + } } impl<'a> ReporterVisitor for GitLabReporterVisitor<'a> { - fn report_summary(&mut self, _: &Execution, _: TraversalSummary) -> std::io::Result<()> { - Ok(()) - } + fn report_summary(&mut self, _:&Execution, _:TraversalSummary) -> std::io::Result<()> { Ok(()) } - fn report_diagnostics( - &mut self, - _execution: &Execution, - payload: DiagnosticsPayload, - ) -> std::io::Result<()> { - let hasher = RwLock::default(); + fn report_diagnostics(&mut self, _execution:&Execution, payload:DiagnosticsPayload) -> std::io::Result<()> { + let hasher = RwLock::default(); - let diagnostics = GitLabDiagnostics(payload, &hasher, self.repository_root.as_deref()); + let diagnostics = GitLabDiagnostics(payload, &hasher, self.repository_root.as_deref()); - self.console.log(markup!({ diagnostics })); + self.console.log(markup!({ diagnostics })); - Ok(()) - } + Ok(()) + } } -struct GitLabDiagnostics<'a>( - DiagnosticsPayload, - &'a RwLock, - Option<&'a Path>, -); +struct GitLabDiagnostics<'a>(DiagnosticsPayload, &'a RwLock, Option<&'a Path>); impl<'a> GitLabDiagnostics<'a> { - fn attempt_to_relativize(&self, subject: &str) -> Option { - let Ok(resolved) = Path::new(subject).absolutize() else { - return None; - }; - - let Ok(relativized) = resolved.strip_prefix(self.2?) else { - return None; - }; - - Some(relativized.to_path_buf()) - } - - fn compute_initial_fingerprint(&self, diagnostic: &Error, path: &str) -> u64 { - let location = diagnostic.location(); - - let code = match location.span { - Some(span) => match location.source_code { - Some(source_code) => &source_code.text[span], - None => "", - }, - None => "", - }; - - let check_name = diagnostic - .category() - .map(|category| category.name()) - .unwrap_or_default(); - - calculate_hash(&Fingerprint { - check_name, - path, - code, - }) - } + fn attempt_to_relativize(&self, subject:&str) -> Option { + let Ok(resolved) = Path::new(subject).absolutize() else { + return None; + }; + + let Ok(relativized) = resolved.strip_prefix(self.2?) else { + return None; + }; + + Some(relativized.to_path_buf()) + } + + fn compute_initial_fingerprint(&self, diagnostic:&Error, path:&str) -> u64 { + let location = diagnostic.location(); + + let code = match location.span { + Some(span) => { + match location.source_code { + Some(source_code) => &source_code.text[span], + None => "", + } + }, + None => "", + }; + + let check_name = diagnostic.category().map(|category| category.name()).unwrap_or_default(); + + calculate_hash(&Fingerprint { check_name, path, code }) + } } impl<'a> Display for GitLabDiagnostics<'a> { - fn fmt(&self, fmt: &mut Formatter) -> std::io::Result<()> { - let mut hasher = self.1.write().unwrap(); - - let gitlab_diagnostics: Vec<_> = self - .0 - .diagnostics - .iter() - .filter(|d| d.severity() >= self.0.diagnostic_level) - .filter(|d| { - if self.0.verbose { - d.tags().is_verbose() - } else { - true - } - }) - .filter_map(|biome_diagnostic| { - let absolute_path = match biome_diagnostic.location().resource { - Some(Resource::File(file)) => Some(file), - _ => None, - } - .unwrap_or_default(); - - let path_buf = self.attempt_to_relativize(absolute_path); - - let path = match path_buf { - Some(buf) => buf.to_str().unwrap_or(absolute_path).to_owned(), - None => absolute_path.to_owned(), - }; - - let initial_fingerprint = self.compute_initial_fingerprint(biome_diagnostic, &path); - - let fingerprint = hasher.rehash_until_unique(initial_fingerprint); - - GitLabDiagnostic::try_from_diagnostic( - biome_diagnostic, - path.to_string(), - fingerprint, - ) - }) - .collect(); - - let serialized = serde_json::to_string_pretty(&gitlab_diagnostics)?; - - fmt.write_str(serialized.as_str())?; - - Ok(()) - } + fn fmt(&self, fmt:&mut Formatter) -> std::io::Result<()> { + let mut hasher = self.1.write().unwrap(); + + let gitlab_diagnostics:Vec<_> = self + .0 + .diagnostics + .iter() + .filter(|d| d.severity() >= self.0.diagnostic_level) + .filter(|d| if self.0.verbose { d.tags().is_verbose() } else { true }) + .filter_map(|biome_diagnostic| { + let absolute_path = match biome_diagnostic.location().resource { + Some(Resource::File(file)) => Some(file), + _ => None, + } + .unwrap_or_default(); + + let path_buf = self.attempt_to_relativize(absolute_path); + + let path = match path_buf { + Some(buf) => buf.to_str().unwrap_or(absolute_path).to_owned(), + None => absolute_path.to_owned(), + }; + + let initial_fingerprint = self.compute_initial_fingerprint(biome_diagnostic, &path); + + let fingerprint = hasher.rehash_until_unique(initial_fingerprint); + + GitLabDiagnostic::try_from_diagnostic(biome_diagnostic, path.to_string(), fingerprint) + }) + .collect(); + + let serialized = serde_json::to_string_pretty(&gitlab_diagnostics)?; + + fmt.write_str(serialized.as_str())?; + + Ok(()) + } } /// An entry in the GitLab Code Quality report. /// See https://docs.gitlab.com/ee/ci/testing/code_quality.html#implement-a-custom-tool #[derive(Serialize)] pub struct GitLabDiagnostic<'a> { - /// A description of the code quality violation. - description: String, - /// A unique name representing the static analysis check that emitted this issue. - check_name: &'a str, - /// A unique fingerprint to identify the code quality violation. For example, an MD5 hash. - fingerprint: String, - /// A severity string (can be info, minor, major, critical, or blocker). - severity: &'a str, - /// The location where the code quality violation occurred. - location: Location, + /// A description of the code quality violation. + description:String, + /// A unique name representing the static analysis check that emitted this + /// issue. + check_name:&'a str, + /// A unique fingerprint to identify the code quality violation. For + /// example, an MD5 hash. + fingerprint:String, + /// A severity string (can be info, minor, major, critical, or blocker). + severity:&'a str, + /// The location where the code quality violation occurred. + location:Location, } impl<'a> GitLabDiagnostic<'a> { - pub fn try_from_diagnostic( - diagnostic: &'a Error, - path: String, - fingerprint: u64, - ) -> Option { - let location = diagnostic.location(); - - let span = location.span?; - - let source_code = location.source_code?; - - let description = PrintDescription(diagnostic).to_string(); - - let begin = match SourceFile::new(source_code).location(span.start()) { - Ok(start) => start.line_number.get(), - Err(_) => return None, - }; - - let check_name = diagnostic - .category() - .map(|category| category.name()) - .unwrap_or_default(); - - Some(GitLabDiagnostic { - severity: match diagnostic.severity() { - Severity::Hint => "info", - Severity::Information => "minor", - Severity::Warning => "major", - Severity::Error => "critical", - Severity::Fatal => "blocker", - }, - description, - check_name, - // A u64 does not fit into a JSON number, so we serialize this as a - // string - fingerprint: fingerprint.to_string(), - location: Location { - path, - lines: Lines { begin }, - }, - }) - } + pub fn try_from_diagnostic(diagnostic:&'a Error, path:String, fingerprint:u64) -> Option { + let location = diagnostic.location(); + + let span = location.span?; + + let source_code = location.source_code?; + + let description = PrintDescription(diagnostic).to_string(); + + let begin = match SourceFile::new(source_code).location(span.start()) { + Ok(start) => start.line_number.get(), + Err(_) => return None, + }; + + let check_name = diagnostic.category().map(|category| category.name()).unwrap_or_default(); + + Some(GitLabDiagnostic { + severity:match diagnostic.severity() { + Severity::Hint => "info", + Severity::Information => "minor", + Severity::Warning => "major", + Severity::Error => "critical", + Severity::Fatal => "blocker", + }, + description, + check_name, + // A u64 does not fit into a JSON number, so we serialize this as a + // string + fingerprint:fingerprint.to_string(), + location:Location { path, lines:Lines { begin } }, + }) + } } #[derive(Serialize)] struct Location { - /// The relative path to the file containing the code quality violation. - path: String, - lines: Lines, + /// The relative path to the file containing the code quality violation. + path:String, + lines:Lines, } #[derive(Serialize)] struct Lines { - /// The line on which the code quality violation occurred. - begin: usize, + /// The line on which the code quality violation occurred. + begin:usize, } #[derive(Hash)] struct Fingerprint<'a> { - // Including the source code in our hash leads to more stable - // fingerprints. If you instead rely on e.g. the line number and change - // the first line of a file, all of its fingerprint would change. - code: &'a str, - check_name: &'a str, - path: &'a str, + // Including the source code in our hash leads to more stable + // fingerprints. If you instead rely on e.g. the line number and change + // the first line of a file, all of its fingerprint would change. + code:&'a str, + check_name:&'a str, + path:&'a str, } -fn calculate_hash(t: &T) -> u64 { - let mut s = DefaultHasher::new(); +fn calculate_hash(t:&T) -> u64 { + let mut s = DefaultHasher::new(); - t.hash(&mut s); + t.hash(&mut s); - s.finish() + s.finish() } diff --git a/crates/biome_cli/Source/reporter/json.rs b/crates/biome_cli/Source/reporter/json.rs index f91d534f97af..c90faad30211 100644 --- a/crates/biome_cli/Source/reporter/json.rs +++ b/crates/biome_cli/Source/reporter/json.rs @@ -1,81 +1,66 @@ -use crate::{DiagnosticsPayload, Execution, Reporter, ReporterVisitor, TraversalSummary}; use biome_console::fmt::Formatter; use serde::Serialize; +use crate::{DiagnosticsPayload, Execution, Reporter, ReporterVisitor, TraversalSummary}; + #[derive(Debug, Default, Serialize)] #[serde(rename_all = "camelCase")] pub(crate) struct JsonReporterVisitor { - summary: TraversalSummary, - diagnostics: Vec, - command: String, + summary:TraversalSummary, + diagnostics:Vec, + command:String, } impl JsonReporterVisitor { - pub(crate) fn new(summary: TraversalSummary) -> Self { - Self { - summary, - diagnostics: vec![], - command: String::new(), - } - } + pub(crate) fn new(summary:TraversalSummary) -> Self { Self { summary, diagnostics:vec![], command:String::new() } } } impl biome_console::fmt::Display for JsonReporterVisitor { - fn fmt(&self, fmt: &mut Formatter) -> std::io::Result<()> { - let content = serde_json::to_string(&self)?; + fn fmt(&self, fmt:&mut Formatter) -> std::io::Result<()> { + let content = serde_json::to_string(&self)?; - fmt.write_str(content.as_str()) - } + fmt.write_str(content.as_str()) + } } pub struct JsonReporter { - pub execution: Execution, - pub diagnostics: DiagnosticsPayload, - pub summary: TraversalSummary, + pub execution:Execution, + pub diagnostics:DiagnosticsPayload, + pub summary:TraversalSummary, } impl Reporter for JsonReporter { - fn write(self, visitor: &mut dyn ReporterVisitor) -> std::io::Result<()> { - visitor.report_summary(&self.execution, self.summary)?; + fn write(self, visitor:&mut dyn ReporterVisitor) -> std::io::Result<()> { + visitor.report_summary(&self.execution, self.summary)?; - visitor.report_diagnostics(&self.execution, self.diagnostics)?; + visitor.report_diagnostics(&self.execution, self.diagnostics)?; - Ok(()) - } + Ok(()) + } } impl ReporterVisitor for JsonReporterVisitor { - fn report_summary( - &mut self, - execution: &Execution, - summary: TraversalSummary, - ) -> std::io::Result<()> { - self.summary = summary; + fn report_summary(&mut self, execution:&Execution, summary:TraversalSummary) -> std::io::Result<()> { + self.summary = summary; - self.command = format!("{}", execution.traversal_mode()); + self.command = format!("{}", execution.traversal_mode()); - Ok(()) - } + Ok(()) + } - fn report_diagnostics( - &mut self, - _execution: &Execution, - payload: DiagnosticsPayload, - ) -> std::io::Result<()> { - for diagnostic in payload.diagnostics { - if diagnostic.severity() >= payload.diagnostic_level { - if diagnostic.tags().is_verbose() { - if payload.verbose { - self.diagnostics - .push(biome_diagnostics::serde::Diagnostic::new(diagnostic)) - } - } else { - self.diagnostics - .push(biome_diagnostics::serde::Diagnostic::new(diagnostic)) - } - } - } + fn report_diagnostics(&mut self, _execution:&Execution, payload:DiagnosticsPayload) -> std::io::Result<()> { + for diagnostic in payload.diagnostics { + if diagnostic.severity() >= payload.diagnostic_level { + if diagnostic.tags().is_verbose() { + if payload.verbose { + self.diagnostics.push(biome_diagnostics::serde::Diagnostic::new(diagnostic)) + } + } else { + self.diagnostics.push(biome_diagnostics::serde::Diagnostic::new(diagnostic)) + } + } + } - Ok(()) - } + Ok(()) + } } diff --git a/crates/biome_cli/Source/reporter/junit.rs b/crates/biome_cli/Source/reporter/junit.rs index 828f5f187a91..24e47aae4ade 100644 --- a/crates/biome_cli/Source/reporter/junit.rs +++ b/crates/biome_cli/Source/reporter/junit.rs @@ -1,134 +1,114 @@ -use crate::{DiagnosticsPayload, Execution, Reporter, ReporterVisitor, TraversalSummary}; -use biome_console::{markup, Console, ConsoleExt}; -use biome_diagnostics::display::SourceFile; -use biome_diagnostics::{Error, Resource}; +use std::{ + fmt::{Display, Formatter}, + io, +}; + +use biome_console::{Console, ConsoleExt, markup}; +use biome_diagnostics::{Error, Resource, display::SourceFile}; use quick_junit::{NonSuccessKind, Report, TestCase, TestCaseStatus, TestSuite}; -use std::fmt::{Display, Formatter}; -use std::io; + +use crate::{DiagnosticsPayload, Execution, Reporter, ReporterVisitor, TraversalSummary}; pub(crate) struct JunitReporter { - pub(crate) diagnostics_payload: DiagnosticsPayload, - pub(crate) execution: Execution, - pub(crate) summary: TraversalSummary, + pub(crate) diagnostics_payload:DiagnosticsPayload, + pub(crate) execution:Execution, + pub(crate) summary:TraversalSummary, } impl Reporter for JunitReporter { - fn write(self, visitor: &mut dyn ReporterVisitor) -> io::Result<()> { - visitor.report_summary(&self.execution, self.summary)?; + fn write(self, visitor:&mut dyn ReporterVisitor) -> io::Result<()> { + visitor.report_summary(&self.execution, self.summary)?; - visitor.report_diagnostics(&self.execution, self.diagnostics_payload)?; + visitor.report_diagnostics(&self.execution, self.diagnostics_payload)?; - Ok(()) - } + Ok(()) + } } struct JunitDiagnostic<'a> { - diagnostic: &'a Error, + diagnostic:&'a Error, } impl<'a> Display for JunitDiagnostic<'a> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - self.diagnostic.description(f) - } + fn fmt(&self, f:&mut Formatter<'_>) -> std::fmt::Result { self.diagnostic.description(f) } } pub(crate) struct JunitReporterVisitor<'a>(pub(crate) Report, pub(crate) &'a mut dyn Console); impl<'a> JunitReporterVisitor<'a> { - pub(crate) fn new(console: &'a mut dyn Console) -> Self { - let report = Report::new("Biome"); + pub(crate) fn new(console:&'a mut dyn Console) -> Self { + let report = Report::new("Biome"); - Self(report, console) - } + Self(report, console) + } } impl<'a> ReporterVisitor for JunitReporterVisitor<'a> { - fn report_summary( - &mut self, - _execution: &Execution, - summary: TraversalSummary, - ) -> io::Result<()> { - self.0.time = Some(summary.duration); - - self.0.errors = summary.errors as usize; - - Ok(()) - } - - fn report_diagnostics( - &mut self, - _execution: &Execution, - payload: DiagnosticsPayload, - ) -> io::Result<()> { - let diagnostics = payload.diagnostics.iter().filter(|diagnostic| { - if diagnostic.tags().is_verbose() { - payload.verbose - } else { - true - } - }); - - for diagnostic in diagnostics { - let mut status = TestCaseStatus::non_success(NonSuccessKind::Failure); - - let message = format!("{}", JunitDiagnostic { diagnostic }); - - status.set_message(message.clone()); - - let location = diagnostic.location(); - - if let (Some(span), Some(source_code), Some(resource)) = - (location.span, location.source_code, location.resource) - { - let source = SourceFile::new(source_code); - - let start = source.location(span.start())?; - - status.set_description(format!( - "line {row:?}, col {col:?}, {body}", - row = start.line_number.to_zero_indexed(), - col = start.column_number.to_zero_indexed(), - body = message - )); - - let mut case = TestCase::new( - format!( - "org.biome.{}", - diagnostic - .category() - .map(|c| c.name()) - .unwrap_or_default() - .replace('/', ".") - ), - status, - ); - - if let Resource::File(path) = resource { - let mut test_suite = TestSuite::new(path); - - case.extra - .insert("line".into(), start.line_number.get().to_string().into()); - - case.extra.insert( - "column".into(), - start.column_number.get().to_string().into(), - ); - - test_suite - .extra - .insert("package".into(), "org.biome".into()); - - test_suite.add_test_case(case); - - self.0.add_test_suite(test_suite); - } - } - } - - self.1.log(markup! { - {self.0.to_string().unwrap()} - }); - - Ok(()) - } + fn report_summary(&mut self, _execution:&Execution, summary:TraversalSummary) -> io::Result<()> { + self.0.time = Some(summary.duration); + + self.0.errors = summary.errors as usize; + + Ok(()) + } + + fn report_diagnostics(&mut self, _execution:&Execution, payload:DiagnosticsPayload) -> io::Result<()> { + let diagnostics = payload + .diagnostics + .iter() + .filter(|diagnostic| if diagnostic.tags().is_verbose() { payload.verbose } else { true }); + + for diagnostic in diagnostics { + let mut status = TestCaseStatus::non_success(NonSuccessKind::Failure); + + let message = format!("{}", JunitDiagnostic { diagnostic }); + + status.set_message(message.clone()); + + let location = diagnostic.location(); + + if let (Some(span), Some(source_code), Some(resource)) = + (location.span, location.source_code, location.resource) + { + let source = SourceFile::new(source_code); + + let start = source.location(span.start())?; + + status.set_description(format!( + "line {row:?}, col {col:?}, {body}", + row = start.line_number.to_zero_indexed(), + col = start.column_number.to_zero_indexed(), + body = message + )); + + let mut case = TestCase::new( + format!( + "org.biome.{}", + diagnostic.category().map(|c| c.name()).unwrap_or_default().replace('/', ".") + ), + status, + ); + + if let Resource::File(path) = resource { + let mut test_suite = TestSuite::new(path); + + case.extra.insert("line".into(), start.line_number.get().to_string().into()); + + case.extra.insert("column".into(), start.column_number.get().to_string().into()); + + test_suite.extra.insert("package".into(), "org.biome".into()); + + test_suite.add_test_case(case); + + self.0.add_test_suite(test_suite); + } + } + } + + self.1.log(markup! { + {self.0.to_string().unwrap()} + }); + + Ok(()) + } } diff --git a/crates/biome_cli/Source/reporter/mod.rs b/crates/biome_cli/Source/reporter/mod.rs index a30b684fb5c6..7bd3dc66faa7 100644 --- a/crates/biome_cli/Source/reporter/mod.rs +++ b/crates/biome_cli/Source/reporter/mod.rs @@ -5,63 +5,57 @@ pub(crate) mod junit; pub(crate) mod summary; pub(crate) mod terminal; -use crate::execute::Execution; +use std::{collections::BTreeSet, io, time::Duration}; + use biome_diagnostics::{Error, Severity}; use biome_fs::BiomePath; use serde::Serialize; -use std::collections::BTreeSet; -use std::io; -use std::time::Duration; + +use crate::execute::Execution; pub struct DiagnosticsPayload { - pub diagnostics: Vec, - pub verbose: bool, - pub diagnostic_level: Severity, + pub diagnostics:Vec, + pub verbose:bool, + pub diagnostic_level:Severity, } /// A type that holds the result of the traversal #[derive(Debug, Default, Serialize, Copy, Clone)] #[serde(rename_all = "camelCase")] pub struct TraversalSummary { - pub changed: usize, - pub unchanged: usize, - pub matches: usize, - // We skip it during testing because the time isn't predictable - #[cfg_attr(debug_assertions, serde(skip))] - pub duration: Duration, - pub errors: u32, - pub warnings: u32, - pub skipped: usize, - pub suggested_fixes_skipped: u32, - pub diagnostics_not_printed: u32, + pub changed:usize, + pub unchanged:usize, + pub matches:usize, + // We skip it during testing because the time isn't predictable + #[cfg_attr(debug_assertions, serde(skip))] + pub duration:Duration, + pub errors:u32, + pub warnings:u32, + pub skipped:usize, + pub suggested_fixes_skipped:u32, + pub diagnostics_not_printed:u32, } -/// When using this trait, the type that implements this trait is the one that holds the read-only information to pass around +/// When using this trait, the type that implements this trait is the one that +/// holds the read-only information to pass around pub trait Reporter: Sized { - /// Writes the summary using the underling visitor - fn write(self, visitor: &mut dyn ReporterVisitor) -> io::Result<()>; + /// Writes the summary using the underling visitor + fn write(self, visitor:&mut dyn ReporterVisitor) -> io::Result<()>; } -/// When using this trait, the type that implements this trait is the one that will **write** the data, ideally inside a buffer +/// When using this trait, the type that implements this trait is the one that +/// will **write** the data, ideally inside a buffer pub trait ReporterVisitor { - /// Writes the summary in the underling writer - fn report_summary( - &mut self, - execution: &Execution, - summary: TraversalSummary, - ) -> io::Result<()>; + /// Writes the summary in the underling writer + fn report_summary(&mut self, execution:&Execution, summary:TraversalSummary) -> io::Result<()>; - /// Writes the paths that were handled during a run. - fn report_handled_paths(&mut self, evaluated_paths: BTreeSet) -> io::Result<()> { - let _ = evaluated_paths; + /// Writes the paths that were handled during a run. + fn report_handled_paths(&mut self, evaluated_paths:BTreeSet) -> io::Result<()> { + let _ = evaluated_paths; - Ok(()) - } + Ok(()) + } - /// Writes a diagnostics - fn report_diagnostics( - &mut self, - execution: &Execution, - payload: DiagnosticsPayload, - ) -> io::Result<()>; + /// Writes a diagnostics + fn report_diagnostics(&mut self, execution:&Execution, payload:DiagnosticsPayload) -> io::Result<()>; } diff --git a/crates/biome_cli/Source/reporter/summary.rs b/crates/biome_cli/Source/reporter/summary.rs index 8fc23f337062..6a9231324f57 100644 --- a/crates/biome_cli/Source/reporter/summary.rs +++ b/crates/biome_cli/Source/reporter/summary.rs @@ -1,163 +1,170 @@ -use crate::reporter::terminal::ConsoleTraversalSummary; -use crate::{DiagnosticsPayload, Execution, Reporter, ReporterVisitor, TraversalSummary}; -use biome_console::fmt::{Display, Formatter}; -use biome_console::{markup, Console, ConsoleExt}; +use std::{ + cmp::Ordering, + collections::{BTreeMap, BTreeSet}, + fmt::Debug, + io, +}; + +use biome_console::{ + Console, + ConsoleExt, + fmt::{Display, Formatter}, + markup, +}; use biome_diagnostics::{ - category, Advices, Category, Diagnostic, MessageAndDescription, PrintDiagnostic, Resource, - Severity, Visit, + Advices, + Category, + Diagnostic, + MessageAndDescription, + PrintDiagnostic, + Resource, + Severity, + Visit, + category, +}; + +use crate::{ + DiagnosticsPayload, + Execution, + Reporter, + ReporterVisitor, + TraversalSummary, + reporter::terminal::ConsoleTraversalSummary, }; -use std::cmp::Ordering; -use std::collections::{BTreeMap, BTreeSet}; -use std::fmt::Debug; -use std::io; pub(crate) struct SummaryReporter { - pub(crate) summary: TraversalSummary, - pub(crate) diagnostics_payload: DiagnosticsPayload, - pub(crate) execution: Execution, + pub(crate) summary:TraversalSummary, + pub(crate) diagnostics_payload:DiagnosticsPayload, + pub(crate) execution:Execution, } impl Reporter for SummaryReporter { - fn write(self, visitor: &mut dyn ReporterVisitor) -> io::Result<()> { - visitor.report_diagnostics(&self.execution, self.diagnostics_payload)?; + fn write(self, visitor:&mut dyn ReporterVisitor) -> io::Result<()> { + visitor.report_diagnostics(&self.execution, self.diagnostics_payload)?; - visitor.report_summary(&self.execution, self.summary)?; + visitor.report_summary(&self.execution, self.summary)?; - Ok(()) - } + Ok(()) + } } pub(crate) struct SummaryReporterVisitor<'a>(pub(crate) &'a mut dyn Console); impl<'a> ReporterVisitor for SummaryReporterVisitor<'a> { - fn report_summary( - &mut self, - execution: &Execution, - summary: TraversalSummary, - ) -> io::Result<()> { - if execution.is_check() && summary.suggested_fixes_skipped > 0 { - self.0.log(markup! { + fn report_summary(&mut self, execution:&Execution, summary:TraversalSummary) -> io::Result<()> { + if execution.is_check() && summary.suggested_fixes_skipped > 0 { + self.0.log(markup! { "Skipped "{summary.suggested_fixes_skipped}" suggested fixes.\n" "If you wish to apply the suggested (unsafe) fixes, use the command ""biome check --write --unsafe\n" }) - } - - if !execution.is_ci() && summary.diagnostics_not_printed > 0 { - self.0.log(markup! { - "The number of diagnostics exceeds the number allowed by Biome.\n" - "Diagnostics not shown: "{summary.diagnostics_not_printed}"." - }) - } - - self.0.log(markup! { - {ConsoleTraversalSummary(execution.traversal_mode(), &summary)} - }); - - Ok(()) - } - - fn report_diagnostics( - &mut self, - execution: &Execution, - diagnostics_payload: DiagnosticsPayload, - ) -> io::Result<()> { - let mut files_to_diagnostics = FileToDiagnostics::default(); - - for diagnostic in &diagnostics_payload.diagnostics { - let location = diagnostic.location().resource.and_then(|r| match r { - Resource::File(p) => Some(p), - _ => None, - }); - - let Some(location) = location else { - continue; - }; - - let category = diagnostic.category(); - - let severity = &diagnostic.severity(); - - if diagnostic.severity() >= diagnostics_payload.diagnostic_level { - if diagnostic.tags().is_verbose() { - if diagnostics_payload.verbose { - if execution.is_check() || execution.is_lint() { - if let Some(category) = category { - if category.name().starts_with("lint/") { - files_to_diagnostics.insert_lint(category.name(), severity); - } - } - } - } else { - continue; - } - } - - if let Some(category) = category { - if category.name() == "parse" { - files_to_diagnostics.insert_parse(location); - } - } - - if execution.is_check() || execution.is_lint() || execution.is_ci() { - if let Some(category) = category { - if category.name().starts_with("lint/") - || category.name().starts_with("suppressions/") - { - files_to_diagnostics.insert_lint(category.name(), severity); - } - } - } - - if execution.is_check() || execution.is_format() || execution.is_ci() { - if let Some(category) = category { - if category.name() == "format" { - files_to_diagnostics.insert_format(location); - } - } - } - - if execution.is_check() || execution.is_ci() { - if let Some(category) = category { - if category.name() == "organizeImports" { - files_to_diagnostics.insert_organize_imports(location); - } - } - } - } - } - - self.0.log(markup! {{files_to_diagnostics}}); - - Ok(()) - } + } + + if !execution.is_ci() && summary.diagnostics_not_printed > 0 { + self.0.log(markup! { + "The number of diagnostics exceeds the number allowed by Biome.\n" + "Diagnostics not shown: "{summary.diagnostics_not_printed}"." + }) + } + + self.0.log(markup! { + {ConsoleTraversalSummary(execution.traversal_mode(), &summary)} + }); + + Ok(()) + } + + fn report_diagnostics(&mut self, execution:&Execution, diagnostics_payload:DiagnosticsPayload) -> io::Result<()> { + let mut files_to_diagnostics = FileToDiagnostics::default(); + + for diagnostic in &diagnostics_payload.diagnostics { + let location = diagnostic.location().resource.and_then(|r| { + match r { + Resource::File(p) => Some(p), + _ => None, + } + }); + + let Some(location) = location else { + continue; + }; + + let category = diagnostic.category(); + + let severity = &diagnostic.severity(); + + if diagnostic.severity() >= diagnostics_payload.diagnostic_level { + if diagnostic.tags().is_verbose() { + if diagnostics_payload.verbose { + if execution.is_check() || execution.is_lint() { + if let Some(category) = category { + if category.name().starts_with("lint/") { + files_to_diagnostics.insert_lint(category.name(), severity); + } + } + } + } else { + continue; + } + } + + if let Some(category) = category { + if category.name() == "parse" { + files_to_diagnostics.insert_parse(location); + } + } + + if execution.is_check() || execution.is_lint() || execution.is_ci() { + if let Some(category) = category { + if category.name().starts_with("lint/") || category.name().starts_with("suppressions/") { + files_to_diagnostics.insert_lint(category.name(), severity); + } + } + } + + if execution.is_check() || execution.is_format() || execution.is_ci() { + if let Some(category) = category { + if category.name() == "format" { + files_to_diagnostics.insert_format(location); + } + } + } + + if execution.is_check() || execution.is_ci() { + if let Some(category) = category { + if category.name() == "organizeImports" { + files_to_diagnostics.insert_organize_imports(location); + } + } + } + } + } + + self.0.log(markup! {{files_to_diagnostics}}); + + Ok(()) + } } #[derive(Debug, Default)] struct FileToDiagnostics { - formats: BTreeSet, - organize_imports: BTreeSet, - lints: LintsByCategory, - parse: BTreeSet, + formats:BTreeSet, + organize_imports:BTreeSet, + lints:LintsByCategory, + parse:BTreeSet, } impl FileToDiagnostics { - fn insert_lint(&mut self, rule_name: impl Into, severity: &Severity) { - let rule_name = rule_name.into(); + fn insert_lint(&mut self, rule_name:impl Into, severity:&Severity) { + let rule_name = rule_name.into(); - self.lints.insert(rule_name, severity); - } + self.lints.insert(rule_name, severity); + } - fn insert_format(&mut self, location: &str) { - self.formats.insert(location.into()); - } + fn insert_format(&mut self, location:&str) { self.formats.insert(location.into()); } - fn insert_organize_imports(&mut self, location: &str) { - self.organize_imports.insert(location.into()); - } + fn insert_organize_imports(&mut self, location:&str) { self.organize_imports.insert(location.into()); } - fn insert_parse(&mut self, location: &str) { - self.parse.insert(location.into()); - } + fn insert_parse(&mut self, location:&str) { self.parse.insert(location.into()); } } #[derive(Debug, Diagnostic)] @@ -165,14 +172,14 @@ impl FileToDiagnostics { severity = Information )] struct SummaryListDiagnostic<'a> { - #[category] - category: &'static Category, + #[category] + category:&'static Category, - #[message] - message: MessageAndDescription, + #[message] + message:MessageAndDescription, - #[advice] - list: SummaryListAdvice<'a>, + #[advice] + list:SummaryListAdvice<'a>, } #[derive(Debug, Diagnostic)] @@ -182,220 +189,200 @@ struct SummaryListDiagnostic<'a> { message = "Some analyzer rules were triggered" )] struct SummaryTableDiagnostic<'a> { - #[advice] - tables: &'a LintsByCategory, + #[advice] + tables:&'a LintsByCategory, } #[derive(Debug)] struct SummaryListAdvice<'a>(&'a BTreeSet); impl<'a> Advices for SummaryListAdvice<'a> { - fn record(&self, visitor: &mut dyn Visit) -> io::Result<()> { - let list: Vec<_> = self.0.iter().map(|s| s as &dyn Display).collect(); + fn record(&self, visitor:&mut dyn Visit) -> io::Result<()> { + let list:Vec<_> = self.0.iter().map(|s| s as &dyn Display).collect(); - visitor.record_list(&list) - } + visitor.record_list(&list) + } } impl Display for FileToDiagnostics { - fn fmt(&self, fmt: &mut Formatter) -> io::Result<()> { - if !self.parse.is_empty() { - let diagnostic = SummaryListDiagnostic { - message: MessageAndDescription::from( - markup! { - "The following files have parsing errors." - } - .to_owned(), - ), - list: SummaryListAdvice(&self.parse), - category: category!("reporter/parse"), - }; - - fmt.write_markup(markup! { - {PrintDiagnostic::simple(&diagnostic)} - })?; - } - - if !self.formats.is_empty() { - let diagnostic = SummaryListDiagnostic { - message: MessageAndDescription::from( - markup! { - "The following files needs to be formatted." - } - .to_owned(), - ), - list: SummaryListAdvice(&self.formats), - category: category!("reporter/format"), - }; - - fmt.write_markup(markup! { - {PrintDiagnostic::simple(&diagnostic)} - })?; - } - - if !self.organize_imports.is_empty() { - let diagnostic = SummaryListDiagnostic { - message: MessageAndDescription::from( - markup! { - "The following files needs to have their imports sorted." - } - .to_owned(), - ), - list: SummaryListAdvice(&self.organize_imports), - category: category!("reporter/organizeImports"), - }; - - fmt.write_markup(markup! { - {PrintDiagnostic::simple(&diagnostic)} - })?; - } - - if !self.lints.0.is_empty() { - let diagnostic = SummaryTableDiagnostic { - tables: &self.lints, - }; - - fmt.write_markup(markup! { - {PrintDiagnostic::simple(&diagnostic)} - })?; - } - - Ok(()) - } + fn fmt(&self, fmt:&mut Formatter) -> io::Result<()> { + if !self.parse.is_empty() { + let diagnostic = SummaryListDiagnostic { + message:MessageAndDescription::from( + markup! { + "The following files have parsing errors." + } + .to_owned(), + ), + list:SummaryListAdvice(&self.parse), + category:category!("reporter/parse"), + }; + + fmt.write_markup(markup! { + {PrintDiagnostic::simple(&diagnostic)} + })?; + } + + if !self.formats.is_empty() { + let diagnostic = SummaryListDiagnostic { + message:MessageAndDescription::from( + markup! { + "The following files needs to be formatted." + } + .to_owned(), + ), + list:SummaryListAdvice(&self.formats), + category:category!("reporter/format"), + }; + + fmt.write_markup(markup! { + {PrintDiagnostic::simple(&diagnostic)} + })?; + } + + if !self.organize_imports.is_empty() { + let diagnostic = SummaryListDiagnostic { + message:MessageAndDescription::from( + markup! { + "The following files needs to have their imports sorted." + } + .to_owned(), + ), + list:SummaryListAdvice(&self.organize_imports), + category:category!("reporter/organizeImports"), + }; + + fmt.write_markup(markup! { + {PrintDiagnostic::simple(&diagnostic)} + })?; + } + + if !self.lints.0.is_empty() { + let diagnostic = SummaryTableDiagnostic { tables:&self.lints }; + + fmt.write_markup(markup! { + {PrintDiagnostic::simple(&diagnostic)} + })?; + } + + Ok(()) + } } #[derive(Debug, Default)] struct LintsByCategory(BTreeMap); impl LintsByCategory { - fn insert(&mut self, rule: RuleName, severity: &Severity) { - if let Some(value) = self.0.get_mut(&rule) { - value.track_severity(severity); - } else { - let mut diagnostics_by_severity = DiagnosticsBySeverity::default(); + fn insert(&mut self, rule:RuleName, severity:&Severity) { + if let Some(value) = self.0.get_mut(&rule) { + value.track_severity(severity); + } else { + let mut diagnostics_by_severity = DiagnosticsBySeverity::default(); - diagnostics_by_severity.track_severity(severity); + diagnostics_by_severity.track_severity(severity); - self.0.insert(rule, diagnostics_by_severity); - } - } + self.0.insert(rule, diagnostics_by_severity); + } + } } impl<'a> Advices for &'a LintsByCategory { - fn record(&self, visitor: &mut dyn Visit) -> io::Result<()> { - let headers = &[ - markup!("Rule Name").to_owned(), - markup!("Diagnostics").to_owned(), - ]; - - let (first, second): (Vec<_>, Vec<_>) = self - .0 - .iter() - .rev() - .map(|(rule_name, diagnostic)| { - ( - markup! {{rule_name}}.to_owned(), - markup! {{diagnostic}}.to_owned(), - ) - }) - .unzip(); + fn record(&self, visitor:&mut dyn Visit) -> io::Result<()> { + let headers = &[markup!("Rule Name").to_owned(), markup!("Diagnostics").to_owned()]; + + let (first, second):(Vec<_>, Vec<_>) = self + .0 + .iter() + .rev() + .map(|(rule_name, diagnostic)| (markup! {{rule_name}}.to_owned(), markup! {{diagnostic}}.to_owned())) + .unzip(); - let array = [first.as_slice(), second.as_slice()]; + let array = [first.as_slice(), second.as_slice()]; - visitor.record_table(15usize, headers, &array) - } + visitor.record_table(15usize, headers, &array) + } } #[derive(Debug, Default)] struct RuleName(&'static str); impl AsRef for RuleName { - fn as_ref(&self) -> &'static str { - self.0 - } + fn as_ref(&self) -> &'static str { self.0 } } impl From<&'static str> for RuleName { - fn from(value: &'static str) -> Self { - Self(value) - } + fn from(value:&'static str) -> Self { Self(value) } } impl Eq for RuleName {} impl PartialEq for RuleName { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } + fn eq(&self, other:&Self) -> bool { self.0 == other.0 } } impl PartialOrd for RuleName { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } + fn partial_cmp(&self, other:&Self) -> Option { Some(self.cmp(other)) } } impl Ord for RuleName { - fn cmp(&self, other: &Self) -> Ordering { - self.0.len().cmp(&other.0.len()) - } + fn cmp(&self, other:&Self) -> Ordering { self.0.len().cmp(&other.0.len()) } } impl Display for RuleName { - fn fmt(&self, fmt: &mut Formatter) -> io::Result<()> { - fmt.write_markup(markup!( - {self.0} - )) - } + fn fmt(&self, fmt:&mut Formatter) -> io::Result<()> { + fmt.write_markup(markup!( + {self.0} + )) + } } #[derive(Debug, Default)] struct DiagnosticsBySeverity { - errors: usize, - warnings: usize, - info: usize, + errors:usize, + warnings:usize, + info:usize, } impl DiagnosticsBySeverity { - fn track_severity(&mut self, severity: &Severity) { - match severity { - Severity::Information => self.info += 1, - Severity::Warning => { - self.warnings += 1; - } - - Severity::Error => { - self.errors += 1; - } - // not used for now inside the linter - Severity::Hint | Severity::Fatal => {} - } - } + fn track_severity(&mut self, severity:&Severity) { + match severity { + Severity::Information => self.info += 1, + Severity::Warning => { + self.warnings += 1; + }, + + Severity::Error => { + self.errors += 1; + }, + // not used for now inside the linter + Severity::Hint | Severity::Fatal => {}, + } + } } impl Display for DiagnosticsBySeverity { - fn fmt(&self, fmt: &mut Formatter) -> io::Result<()> { - let total = self.warnings + self.info + self.errors; + fn fmt(&self, fmt:&mut Formatter) -> io::Result<()> { + let total = self.warnings + self.info + self.errors; - fmt.write_str(&format!("{total}"))?; + fmt.write_str(&format!("{total}"))?; - fmt.write_str(" ")?; + fmt.write_str(" ")?; - fmt.write_str("(")?; + fmt.write_str("(")?; - fmt.write_markup(markup! { - {self.errors}" error(s), " - })?; + fmt.write_markup(markup! { + {self.errors}" error(s), " + })?; - fmt.write_markup(markup! { - {self.warnings}" warning(s), " - })?; + fmt.write_markup(markup! { + {self.warnings}" warning(s), " + })?; - fmt.write_markup(markup! { - {self.info}" info(s)" - })?; + fmt.write_markup(markup! { + {self.info}" info(s)" + })?; - fmt.write_str(")")?; + fmt.write_str(")")?; - Ok(()) - } + Ok(()) + } } diff --git a/crates/biome_cli/Source/reporter/terminal.rs b/crates/biome_cli/Source/reporter/terminal.rs index 7c242f1170da..e59cd39288ef 100644 --- a/crates/biome_cli/Source/reporter/terminal.rs +++ b/crates/biome_cli/Source/reporter/terminal.rs @@ -1,36 +1,36 @@ -use crate::execute::{Execution, TraversalMode}; -use crate::reporter::{DiagnosticsPayload, ReporterVisitor, TraversalSummary}; -use crate::Reporter; -use biome_console::fmt::Formatter; -use biome_console::{fmt, markup, Console, ConsoleExt}; -use biome_diagnostics::advice::ListAdvice; -use biome_diagnostics::{Diagnostic, PrintDiagnostic}; +use std::{collections::BTreeSet, io, time::Duration}; + +use biome_console::{Console, ConsoleExt, fmt, fmt::Formatter, markup}; +use biome_diagnostics::{Diagnostic, PrintDiagnostic, advice::ListAdvice}; use biome_fs::BiomePath; -use std::collections::BTreeSet; -use std::io; -use std::time::Duration; + +use crate::{ + Reporter, + execute::{Execution, TraversalMode}, + reporter::{DiagnosticsPayload, ReporterVisitor, TraversalSummary}, +}; pub(crate) struct ConsoleReporter { - pub(crate) summary: TraversalSummary, - pub(crate) diagnostics_payload: DiagnosticsPayload, - pub(crate) execution: Execution, - pub(crate) evaluated_paths: BTreeSet, + pub(crate) summary:TraversalSummary, + pub(crate) diagnostics_payload:DiagnosticsPayload, + pub(crate) execution:Execution, + pub(crate) evaluated_paths:BTreeSet, } impl Reporter for ConsoleReporter { - fn write(self, visitor: &mut dyn ReporterVisitor) -> io::Result<()> { - let verbose = self.diagnostics_payload.verbose; + fn write(self, visitor:&mut dyn ReporterVisitor) -> io::Result<()> { + let verbose = self.diagnostics_payload.verbose; - visitor.report_diagnostics(&self.execution, self.diagnostics_payload)?; + visitor.report_diagnostics(&self.execution, self.diagnostics_payload)?; - visitor.report_summary(&self.execution, self.summary)?; + visitor.report_summary(&self.execution, self.summary)?; - if verbose { - visitor.report_handled_paths(self.evaluated_paths)?; - } + if verbose { + visitor.report_handled_paths(self.evaluated_paths)?; + } - Ok(()) - } + Ok(()) + } } #[derive(Debug, Diagnostic)] @@ -40,8 +40,8 @@ impl Reporter for ConsoleReporter { message = "Files processed:" )] struct EvaluatedPathsDiagnostic { - #[advice] - advice: ListAdvice, + #[advice] + advice:ListAdvice, } #[derive(Debug, Diagnostic)] @@ -51,210 +51,190 @@ struct EvaluatedPathsDiagnostic { message = "Files fixed:" )] struct FixedPathsDiagnostic { - #[advice] - advice: ListAdvice, + #[advice] + advice:ListAdvice, } pub(crate) struct ConsoleReporterVisitor<'a>(pub(crate) &'a mut dyn Console); impl<'a> ReporterVisitor for ConsoleReporterVisitor<'a> { - fn report_summary( - &mut self, - execution: &Execution, - summary: TraversalSummary, - ) -> io::Result<()> { - if execution.is_check() && summary.suggested_fixes_skipped > 0 { - self.0.log(markup! { + fn report_summary(&mut self, execution:&Execution, summary:TraversalSummary) -> io::Result<()> { + if execution.is_check() && summary.suggested_fixes_skipped > 0 { + self.0.log(markup! { "Skipped "{summary.suggested_fixes_skipped}" suggested fixes.\n" "If you wish to apply the suggested (unsafe) fixes, use the command ""biome check --fix --unsafe\n" }) - } - - if !execution.is_ci() && summary.diagnostics_not_printed > 0 { - self.0.log(markup! { - "The number of diagnostics exceeds the number allowed by Biome.\n" - "Diagnostics not shown: "{summary.diagnostics_not_printed}"." - }) - } - - self.0.log(markup! { - {ConsoleTraversalSummary(execution.traversal_mode(), &summary)} - }); - - Ok(()) - } - - fn report_handled_paths(&mut self, evaluated_paths: BTreeSet) -> io::Result<()> { - let evaluated_paths_diagnostic = EvaluatedPathsDiagnostic { - advice: ListAdvice { - list: evaluated_paths - .iter() - .map(|p| p.display().to_string()) - .collect(), - }, - }; - - let fixed_paths_diagnostic = FixedPathsDiagnostic { - advice: ListAdvice { - list: evaluated_paths - .iter() - .filter(|p| p.was_written()) - .map(|p| p.display().to_string()) - .collect(), - }, - }; - - self.0.log(markup! { - {PrintDiagnostic::verbose(&evaluated_paths_diagnostic)} - }); - - self.0.log(markup! { - {PrintDiagnostic::verbose(&fixed_paths_diagnostic)} - }); - - Ok(()) - } - - fn report_diagnostics( - &mut self, - execution: &Execution, - diagnostics_payload: DiagnosticsPayload, - ) -> io::Result<()> { - for diagnostic in &diagnostics_payload.diagnostics { - if execution.is_search() { - self.0.log(markup! {{PrintDiagnostic::search(diagnostic)}}); - - continue; - } - - if diagnostic.severity() >= diagnostics_payload.diagnostic_level { - if diagnostic.tags().is_verbose() && diagnostics_payload.verbose { - self.0 - .error(markup! {{PrintDiagnostic::verbose(diagnostic)}}); - } else { - self.0 - .error(markup! {{PrintDiagnostic::simple(diagnostic)}}); - } - } - } - - Ok(()) - } + } + + if !execution.is_ci() && summary.diagnostics_not_printed > 0 { + self.0.log(markup! { + "The number of diagnostics exceeds the number allowed by Biome.\n" + "Diagnostics not shown: "{summary.diagnostics_not_printed}"." + }) + } + + self.0.log(markup! { + {ConsoleTraversalSummary(execution.traversal_mode(), &summary)} + }); + + Ok(()) + } + + fn report_handled_paths(&mut self, evaluated_paths:BTreeSet) -> io::Result<()> { + let evaluated_paths_diagnostic = EvaluatedPathsDiagnostic { + advice:ListAdvice { list:evaluated_paths.iter().map(|p| p.display().to_string()).collect() }, + }; + + let fixed_paths_diagnostic = FixedPathsDiagnostic { + advice:ListAdvice { + list:evaluated_paths + .iter() + .filter(|p| p.was_written()) + .map(|p| p.display().to_string()) + .collect(), + }, + }; + + self.0.log(markup! { + {PrintDiagnostic::verbose(&evaluated_paths_diagnostic)} + }); + + self.0.log(markup! { + {PrintDiagnostic::verbose(&fixed_paths_diagnostic)} + }); + + Ok(()) + } + + fn report_diagnostics(&mut self, execution:&Execution, diagnostics_payload:DiagnosticsPayload) -> io::Result<()> { + for diagnostic in &diagnostics_payload.diagnostics { + if execution.is_search() { + self.0.log(markup! {{PrintDiagnostic::search(diagnostic)}}); + + continue; + } + + if diagnostic.severity() >= diagnostics_payload.diagnostic_level { + if diagnostic.tags().is_verbose() && diagnostics_payload.verbose { + self.0.error(markup! {{PrintDiagnostic::verbose(diagnostic)}}); + } else { + self.0.error(markup! {{PrintDiagnostic::simple(diagnostic)}}); + } + } + } + + Ok(()) + } } struct Files(usize); impl fmt::Display for Files { - fn fmt(&self, fmt: &mut Formatter) -> io::Result<()> { - fmt.write_markup(markup!({self.0} " "))?; - - if self.0 == 1 { - fmt.write_str("file") - } else { - fmt.write_str("files") - } - } + fn fmt(&self, fmt:&mut Formatter) -> io::Result<()> { + fmt.write_markup(markup!({self.0} " "))?; + + if self.0 == 1 { fmt.write_str("file") } else { fmt.write_str("files") } + } } struct SummaryDetail<'a>(pub(crate) &'a TraversalMode, usize); impl<'a> fmt::Display for SummaryDetail<'a> { - fn fmt(&self, fmt: &mut Formatter) -> io::Result<()> { - if let TraversalMode::Search { .. } = self.0 { - return Ok(()); - } - - if self.1 > 0 { - fmt.write_markup(markup! { - " Fixed "{Files(self.1)}"." - }) - } else { - fmt.write_markup(markup! { - " No fixes applied." - }) - } - } + fn fmt(&self, fmt:&mut Formatter) -> io::Result<()> { + if let TraversalMode::Search { .. } = self.0 { + return Ok(()); + } + + if self.1 > 0 { + fmt.write_markup(markup! { + " Fixed "{Files(self.1)}"." + }) + } else { + fmt.write_markup(markup! { + " No fixes applied." + }) + } + } } struct SummaryTotal<'a>(&'a TraversalMode, usize, &'a Duration); impl<'a> fmt::Display for SummaryTotal<'a> { - fn fmt(&self, fmt: &mut Formatter) -> io::Result<()> { - let files = Files(self.1); - - match self.0 { - TraversalMode::Check { .. } | TraversalMode::Lint { .. } | TraversalMode::CI { .. } => { - fmt.write_markup(markup! { - "Checked "{files}" in "{self.2}"." - }) - } - - TraversalMode::Format { write, .. } => { - if *write { - fmt.write_markup(markup! { - "Formatted "{files}" in "{self.2}"." - }) - } else { - fmt.write_markup(markup! { - "Checked "{files}" in "{self.2}"." - }) - } - } - - TraversalMode::Migrate { write, .. } => { - if *write { - fmt.write_markup(markup! { - "Migrated your configuration file in "{self.2}"." - }) - } else { - fmt.write_markup(markup! { - "Checked your configuration file in "{self.2}"." - }) - } - } - - TraversalMode::Search { .. } => fmt.write_markup(markup! { - "Searched "{files}" in "{self.2}"." - }), - } - } + fn fmt(&self, fmt:&mut Formatter) -> io::Result<()> { + let files = Files(self.1); + + match self.0 { + TraversalMode::Check { .. } | TraversalMode::Lint { .. } | TraversalMode::CI { .. } => { + fmt.write_markup(markup! { + "Checked "{files}" in "{self.2}"." + }) + }, + + TraversalMode::Format { write, .. } => { + if *write { + fmt.write_markup(markup! { + "Formatted "{files}" in "{self.2}"." + }) + } else { + fmt.write_markup(markup! { + "Checked "{files}" in "{self.2}"." + }) + } + }, + + TraversalMode::Migrate { write, .. } => { + if *write { + fmt.write_markup(markup! { + "Migrated your configuration file in "{self.2}"." + }) + } else { + fmt.write_markup(markup! { + "Checked your configuration file in "{self.2}"." + }) + } + }, + + TraversalMode::Search { .. } => { + fmt.write_markup(markup! { + "Searched "{files}" in "{self.2}"." + }) + }, + } + } } -pub(crate) struct ConsoleTraversalSummary<'a>( - pub(crate) &'a TraversalMode, - pub(crate) &'a TraversalSummary, -); +pub(crate) struct ConsoleTraversalSummary<'a>(pub(crate) &'a TraversalMode, pub(crate) &'a TraversalSummary); impl<'a> fmt::Display for ConsoleTraversalSummary<'a> { - fn fmt(&self, fmt: &mut Formatter) -> io::Result<()> { - let summary = SummaryTotal(self.0, self.1.changed + self.1.unchanged, &self.1.duration); - - let detail = SummaryDetail(self.0, self.1.changed); - - fmt.write_markup(markup!({summary}{detail}))?; - - if self.1.errors > 0 { - if self.1.errors == 1 { - fmt.write_markup(markup!("\n""Found "{self.1.errors}" error."))?; - } else { - fmt.write_markup(markup!("\n""Found "{self.1.errors}" errors."))?; - } - } - - if self.1.warnings > 0 { - if self.1.warnings == 1 { - fmt.write_markup(markup!("\n""Found "{self.1.warnings}" warning."))?; - } else { - fmt.write_markup(markup!("\n""Found "{self.1.warnings}" warnings."))?; - } - } - - if let TraversalMode::Search { .. } = self.0 { - if self.1.matches == 1 { - fmt.write_markup(markup!(" ""Found "{self.1.matches}" match."))? - } else { - fmt.write_markup(markup!(" ""Found "{self.1.matches}" matches."))? - }; - }; - - Ok(()) - } + fn fmt(&self, fmt:&mut Formatter) -> io::Result<()> { + let summary = SummaryTotal(self.0, self.1.changed + self.1.unchanged, &self.1.duration); + + let detail = SummaryDetail(self.0, self.1.changed); + + fmt.write_markup(markup!({summary}{detail}))?; + + if self.1.errors > 0 { + if self.1.errors == 1 { + fmt.write_markup(markup!("\n""Found "{self.1.errors}" error."))?; + } else { + fmt.write_markup(markup!("\n""Found "{self.1.errors}" errors."))?; + } + } + + if self.1.warnings > 0 { + if self.1.warnings == 1 { + fmt.write_markup(markup!("\n""Found "{self.1.warnings}" warning."))?; + } else { + fmt.write_markup(markup!("\n""Found "{self.1.warnings}" warnings."))?; + } + } + + if let TraversalMode::Search { .. } = self.0 { + if self.1.matches == 1 { + fmt.write_markup(markup!(" ""Found "{self.1.matches}" match."))? + } else { + fmt.write_markup(markup!(" ""Found "{self.1.matches}" matches."))? + }; + }; + + Ok(()) + } } diff --git a/crates/biome_cli/Source/service/mod.rs b/crates/biome_cli/Source/service/mod.rs index 63dc978b58f2..e8bc20698595 100644 --- a/crates/biome_cli/Source/service/mod.rs +++ b/crates/biome_cli/Source/service/mod.rs @@ -5,63 +5,59 @@ //! a simplified derivative of the HTTP protocol use std::{ - any::type_name, - borrow::Cow, - io, - ops::Deref, - panic::RefUnwindSafe, - str::{from_utf8, FromStr}, - sync::Arc, - time::Duration, + any::type_name, + borrow::Cow, + io, + ops::Deref, + panic::RefUnwindSafe, + str::{FromStr, from_utf8}, + sync::Arc, + time::Duration, }; -use anyhow::{bail, ensure, Context, Error}; +use anyhow::{Context, Error, bail, ensure}; use biome_service::{ - workspace::{TransportRequest, WorkspaceTransport}, - TransportError, + TransportError, + workspace::{TransportRequest, WorkspaceTransport}, }; use dashmap::DashMap; -use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use serde::{Deserialize, Serialize, de::DeserializeOwned}; use serde_json::{ - from_slice, from_str, to_vec, - value::{to_raw_value, RawValue}, - Value, + Value, + from_slice, + from_str, + to_vec, + value::{RawValue, to_raw_value}, }; use tokio::{ - io::{ - AsyncBufRead, AsyncBufReadExt, AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, - BufReader, BufWriter, - }, - runtime::Runtime, - sync::{ - mpsc::{channel, Receiver, Sender}, - oneshot, Notify, - }, - time::sleep, + io::{AsyncBufRead, AsyncBufReadExt, AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, BufReader, BufWriter}, + runtime::Runtime, + sync::{ + Notify, + mpsc::{Receiver, Sender, channel}, + oneshot, + }, + time::sleep, }; #[cfg(windows)] mod windows; #[cfg(windows)] -pub(crate) use self::windows::{ - ensure_daemon, enumerate_pipes, open_socket, print_socket, run_daemon, -}; +pub(crate) use self::windows::{ensure_daemon, enumerate_pipes, open_socket, print_socket, run_daemon}; #[cfg(unix)] mod unix; #[cfg(unix)] -pub(crate) use self::unix::{ - ensure_daemon, enumerate_pipes, open_socket, print_socket, run_daemon, -}; +pub(crate) use self::unix::{ensure_daemon, enumerate_pipes, open_socket, print_socket, run_daemon}; /// Tries to open a connection to a running daemon instance, returning a /// [WorkspaceTransport] instance if the socket is currently active -pub fn open_transport(runtime: Runtime) -> io::Result> { - match runtime.block_on(open_socket()) { - Ok(Some((read, write))) => Ok(Some(SocketTransport::open(runtime, read, write))), - Ok(None) => Ok(None), - Err(err) => Err(err), - } +pub fn open_transport(runtime:Runtime) -> io::Result> { + match runtime.block_on(open_socket()) { + Ok(Some((read, write))) => Ok(Some(SocketTransport::open(runtime, read, write))), + Ok(None) => Ok(None), + Err(err) => Err(err), + } } type JsonRpcResult = Result, TransportError>; @@ -72,11 +68,11 @@ type JsonRpcResult = Result, TransportError>; /// This structs holds an instance of the `tokio` runtime, as well as the /// following fields: /// - `write_send` is a sender handle to the "write channel", an MPSC channel -/// that's used to queue up requests to be sent to the server (for simplicity -/// the requests are pushed to the channel as serialized byte buffers) +/// that's used to queue up requests to be sent to the server (for simplicity +/// the requests are pushed to the channel as serialized byte buffers) /// - `pending_requests` is handle to a shared hashmap where the keys are `u64` -/// corresponding to request IDs, and the values are sender handles to oneshot -/// channel instances that can be consumed to fulfill the associated request +/// corresponding to request IDs, and the values are sender handles to oneshot +/// channel instances that can be consumed to fulfill the associated request /// /// Creating a new `SocketTransport` instance requires providing a `tokio` /// runtime instance as well as the "read half" and "write half" of the socket @@ -85,9 +81,10 @@ type JsonRpcResult = Result, TransportError>; /// same underlying I/O object but are represented as separate so they can be /// used concurrently /// -/// This concurrent handling of I/O is implemented useing two "background tasks": +/// This concurrent handling of I/O is implemented useing two "background +/// tasks": /// - the `write_task` pulls outgoing messages from the "write channel" and -/// writes them to the "write half" of the socket +/// writes them to the "write half" of the socket /// - the `read_task` reads incoming messages from the "read half" of the /// - the `read_task` reads incoming messages from the "read half" of the /// socket, then looks up a request with an ID corresponding to the received @@ -101,24 +98,22 @@ type JsonRpcResult = Result, TransportError>; /// the current thread until a response is received over the oneshot channel /// from the read task, or the request times out pub struct SocketTransport { - runtime: Runtime, - write_send: Sender<(Vec, bool)>, - pending_requests: PendingRequests, + runtime:Runtime, + write_send:Sender<(Vec, bool)>, + pending_requests:PendingRequests, } /// Stores a handle to the map of pending requests, and clears the map /// automatically when the handle is dropped #[derive(Clone, Default)] struct PendingRequests { - inner: Arc>>, + inner:Arc>>, } impl Deref for PendingRequests { - type Target = DashMap>; + type Target = DashMap>; - fn deref(&self) -> &Self::Target { - self.inner.as_ref() - } + fn deref(&self) -> &Self::Target { self.inner.as_ref() } } /// There are two live handles to the pending requests map: one is in the @@ -130,366 +125,337 @@ impl Deref for PendingRequests { /// this case the `Drop` implementation will ensure that all pending requests /// are cancelled immediately instead of timing out. impl Drop for PendingRequests { - fn drop(&mut self) { - self.inner.clear(); - } + fn drop(&mut self) { self.inner.clear(); } } impl SocketTransport { - pub fn open(runtime: Runtime, socket_read: R, socket_write: W) -> Self - where - R: AsyncRead + Unpin + Send + 'static, - W: AsyncWrite + Unpin + Send + 'static, - { - /// Capacity of the "write channel", once this many requests have been - /// queued up, calls to `write_send.send` will block the sending task - /// until enough capacity is available again - /// - /// Note that this does not limit how many requests can be in flight at - /// a given time, it only serves as a loose rate-limit on how many new - /// requests can be sent to the server within a given time frame - const WRITE_CHANNEL_CAPACITY: usize = 16; - - let (write_send, write_recv) = channel(WRITE_CHANNEL_CAPACITY); - - let pending_requests = PendingRequests::default(); - - let pending_requests_2 = pending_requests.clone(); - - let socket_read = BufReader::new(socket_read); - - let socket_write = BufWriter::new(socket_write); - - let broadcast_shutdown = Arc::new(Notify::new()); - - runtime.spawn(write_task( - broadcast_shutdown.clone(), - write_recv, - socket_write, - )); - - runtime.spawn(async move { - tokio::select! { - _ = read_task(socket_read, &pending_requests) => {} - - _ = broadcast_shutdown.notified() => {} - } - }); - - Self { - runtime, - write_send, - pending_requests: pending_requests_2, - } - } + pub fn open(runtime:Runtime, socket_read:R, socket_write:W) -> Self + where + R: AsyncRead + Unpin + Send + 'static, + W: AsyncWrite + Unpin + Send + 'static, { + /// Capacity of the "write channel", once this many requests have been + /// queued up, calls to `write_send.send` will block the sending task + /// until enough capacity is available again + /// + /// Note that this does not limit how many requests can be in flight at + /// a given time, it only serves as a loose rate-limit on how many new + /// requests can be sent to the server within a given time frame + const WRITE_CHANNEL_CAPACITY:usize = 16; + + let (write_send, write_recv) = channel(WRITE_CHANNEL_CAPACITY); + + let pending_requests = PendingRequests::default(); + + let pending_requests_2 = pending_requests.clone(); + + let socket_read = BufReader::new(socket_read); + + let socket_write = BufWriter::new(socket_write); + + let broadcast_shutdown = Arc::new(Notify::new()); + + runtime.spawn(write_task(broadcast_shutdown.clone(), write_recv, socket_write)); + + runtime.spawn(async move { + tokio::select! { + _ = read_task(socket_read, &pending_requests) => {} + + _ = broadcast_shutdown.notified() => {} + } + }); + + Self { runtime, write_send, pending_requests:pending_requests_2 } + } } // Allow the socket to be recovered across panic boundaries impl RefUnwindSafe for SocketTransport {} impl WorkspaceTransport for SocketTransport { - fn request(&self, request: TransportRequest

) -> Result - where - P: Serialize, - R: DeserializeOwned, - { - let (send, recv) = oneshot::channel(); - - self.pending_requests.insert(request.id, send); - - let is_shutdown = request.method == "biome/shutdown"; - - let request = JsonRpcRequest { - jsonrpc: Cow::Borrowed("2.0"), - id: request.id, - method: Cow::Borrowed(request.method), - params: request.params, - }; - - let request = to_vec(&request).map_err(|err| { - TransportError::SerdeError(format!( - "failed to serialize {} into byte buffer: {err}", - type_name::

() - )) - })?; - - let response = self.runtime.block_on(async move { - self.write_send - .send((request, is_shutdown)) - .await - .map_err(|_| TransportError::ChannelClosed)?; - - tokio::select! { - result = recv => { - match result { - Ok(Ok(response)) => Ok(response), - Ok(Err(error)) => Err(error), - Err(_) => Err(TransportError::ChannelClosed), - } - } - - _ = sleep(Duration::from_secs(15)) => { - Err(TransportError::Timeout) - } - } - })?; - - let response = response.get(); - - let result = from_str(response).map_err(|err| { - TransportError::SerdeError(format!( - "failed to deserialize {} from {response:?}: {err}", - type_name::() - )) - })?; - - Ok(result) - } + fn request(&self, request:TransportRequest

) -> Result + where + P: Serialize, + R: DeserializeOwned, { + let (send, recv) = oneshot::channel(); + + self.pending_requests.insert(request.id, send); + + let is_shutdown = request.method == "biome/shutdown"; + + let request = JsonRpcRequest { + jsonrpc:Cow::Borrowed("2.0"), + id:request.id, + method:Cow::Borrowed(request.method), + params:request.params, + }; + + let request = to_vec(&request).map_err(|err| { + TransportError::SerdeError(format!("failed to serialize {} into byte buffer: {err}", type_name::

())) + })?; + + let response = self.runtime.block_on(async move { + self.write_send + .send((request, is_shutdown)) + .await + .map_err(|_| TransportError::ChannelClosed)?; + + tokio::select! { + result = recv => { + match result { + Ok(Ok(response)) => Ok(response), + Ok(Err(error)) => Err(error), + Err(_) => Err(TransportError::ChannelClosed), + } + } + + _ = sleep(Duration::from_secs(15)) => { + Err(TransportError::Timeout) + } + } + })?; + + let response = response.get(); + + let result = from_str(response).map_err(|err| { + TransportError::SerdeError(format!("failed to deserialize {} from {response:?}: {err}", type_name::())) + })?; + + Ok(result) + } } -async fn read_task(mut socket_read: BufReader, pending_requests: &PendingRequests) +async fn read_task(mut socket_read:BufReader, pending_requests:&PendingRequests) where - R: AsyncRead + Unpin, -{ - loop { - let message = read_message(&mut socket_read).await; - - let message = match message { - Ok(message) => { - let response = from_slice(&message).with_context(|| { - if let Ok(message) = from_utf8(&message) { - format!("failed to deserialize JSON-RPC response from {message:?}") - } else { - format!("failed to deserialize JSON-RPC response from {message:?}") - } - }); - - response.map(|response| (message, response)) - } - - Err(err) => Err(err), - }; - - let (message, response): (_, JsonRpcResponse) = match message { - Ok(message) => message, - Err(err) => { - eprintln!( - "{:?}", - err.context("remote connection read task exited with an error") - ); - - break; - } - }; - - if let Some((_, channel)) = pending_requests.remove(&response.id) { - let response = match (response.result, response.error) { - (Some(result), None) => Ok(result), - (None, Some(err)) => Err(TransportError::RPCError(err.message)), - - // Both result and error will be None if the request - // returns a null-ish result, in this case create a - // "null" RawValue as the result - // - // SAFETY: Calling `to_raw_value` with a static "null" - // JSON Value will always succeed - (None, None) => Ok(to_raw_value(&Value::Null).unwrap()), - - _ => { - let message = if let Ok(message) = from_utf8(&message) { - format!("invalid response {message:?}") - } else { - format!("invalid response {message:?}") - }; - - Err(TransportError::SerdeError(message)) - } - }; - - channel.send(response).ok(); - } - } + R: AsyncRead + Unpin, { + loop { + let message = read_message(&mut socket_read).await; + + let message = match message { + Ok(message) => { + let response = from_slice(&message).with_context(|| { + if let Ok(message) = from_utf8(&message) { + format!("failed to deserialize JSON-RPC response from {message:?}") + } else { + format!("failed to deserialize JSON-RPC response from {message:?}") + } + }); + + response.map(|response| (message, response)) + }, + + Err(err) => Err(err), + }; + + let (message, response):(_, JsonRpcResponse) = match message { + Ok(message) => message, + Err(err) => { + eprintln!("{:?}", err.context("remote connection read task exited with an error")); + + break; + }, + }; + + if let Some((_, channel)) = pending_requests.remove(&response.id) { + let response = match (response.result, response.error) { + (Some(result), None) => Ok(result), + (None, Some(err)) => Err(TransportError::RPCError(err.message)), + + // Both result and error will be None if the request + // returns a null-ish result, in this case create a + // "null" RawValue as the result + // + // SAFETY: Calling `to_raw_value` with a static "null" + // JSON Value will always succeed + (None, None) => Ok(to_raw_value(&Value::Null).unwrap()), + + _ => { + let message = if let Ok(message) = from_utf8(&message) { + format!("invalid response {message:?}") + } else { + format!("invalid response {message:?}") + }; + + Err(TransportError::SerdeError(message)) + }, + }; + + channel.send(response).ok(); + } + } } -async fn read_message(mut socket_read: R) -> Result, Error> +async fn read_message(mut socket_read:R) -> Result, Error> where - R: AsyncBufRead + Unpin, -{ - let mut length = None; - - let mut line = String::new(); - - loop { - match socket_read - .read_line(&mut line) - .await - .context("failed to read header line from the socket")? - { - // A read of 0 bytes means the connection was closed - 0 => { - bail!("the connection to the remote workspace was unexpectedly closed"); - } - // A read of two bytes corresponds to the "\r\n" sequence - // that indicates the end of the header section - 2 => { - if line != "\r\n" { - bail!("unexpected byte sequence received from the remote workspace, got {line:?} expected \"\\r\\n\""); - } - - break; - } - - _ => { - let header: TransportHeader = line - .parse() - .context("failed to parse header from the remote workspace")?; - - match header { - TransportHeader::ContentLength(value) => { - length = Some(value); - } - - TransportHeader::ContentType => {} - - TransportHeader::Unknown(name) => { - eprintln!("ignoring unknown header {name:?}"); - } - } - - line.clear(); - } - } - } - - let length = length.context( - "incoming response from the remote workspace is missing the Content-Length header", - )?; - - let mut result = vec![0u8; length]; - - socket_read - .read_exact(&mut result) - .await - .with_context(|| format!("failed to read message of {length} bytes from the socket"))?; - - Ok(result) + R: AsyncBufRead + Unpin, { + let mut length = None; + + let mut line = String::new(); + + loop { + match socket_read + .read_line(&mut line) + .await + .context("failed to read header line from the socket")? + { + // A read of 0 bytes means the connection was closed + 0 => { + bail!("the connection to the remote workspace was unexpectedly closed"); + }, + // A read of two bytes corresponds to the "\r\n" sequence + // that indicates the end of the header section + 2 => { + if line != "\r\n" { + bail!( + "unexpected byte sequence received from the remote workspace, got {line:?} expected \"\\r\\n\"" + ); + } + + break; + }, + + _ => { + let header:TransportHeader = + line.parse().context("failed to parse header from the remote workspace")?; + + match header { + TransportHeader::ContentLength(value) => { + length = Some(value); + }, + + TransportHeader::ContentType => {}, + + TransportHeader::Unknown(name) => { + eprintln!("ignoring unknown header {name:?}"); + }, + } + + line.clear(); + }, + } + } + + let length = length.context("incoming response from the remote workspace is missing the Content-Length header")?; + + let mut result = vec![0u8; length]; + + socket_read + .read_exact(&mut result) + .await + .with_context(|| format!("failed to read message of {length} bytes from the socket"))?; + + Ok(result) } async fn write_task( - broadcast_shutdown: Arc, - mut write_recv: Receiver<(Vec, bool)>, - mut socket_write: BufWriter, + broadcast_shutdown:Arc, + mut write_recv:Receiver<(Vec, bool)>, + mut socket_write:BufWriter, ) where - W: AsyncWrite + Unpin, -{ - while let Some((message, is_shutdown)) = write_recv.recv().await { - if is_shutdown { - broadcast_shutdown.notify_waiters(); - } - - if let Err(err) = write_message(&mut socket_write, message).await { - eprintln!( - "{:?}", - err.context("remote connection write task exited with an error") - ); - - break; - } - - if is_shutdown { - break; - } - } + W: AsyncWrite + Unpin, { + while let Some((message, is_shutdown)) = write_recv.recv().await { + if is_shutdown { + broadcast_shutdown.notify_waiters(); + } + + if let Err(err) = write_message(&mut socket_write, message).await { + eprintln!("{:?}", err.context("remote connection write task exited with an error")); + + break; + } + + if is_shutdown { + break; + } + } } -async fn write_message(mut socket_write: W, message: Vec) -> Result<(), Error> +async fn write_message(mut socket_write:W, message:Vec) -> Result<(), Error> where - W: AsyncWrite + Unpin, -{ - socket_write.write_all(b"Content-Length: ").await?; + W: AsyncWrite + Unpin, { + socket_write.write_all(b"Content-Length: ").await?; - let length = message.len().to_string(); + let length = message.len().to_string(); - socket_write.write_all(length.as_bytes()).await?; + socket_write.write_all(length.as_bytes()).await?; - socket_write.write_all(b"\r\n").await?; + socket_write.write_all(b"\r\n").await?; - socket_write - .write_all(b"Content-Type: application/vscode-jsonrpc; charset=utf-8\r\n") - .await?; + socket_write + .write_all(b"Content-Type: application/vscode-jsonrpc; charset=utf-8\r\n") + .await?; - socket_write.write_all(b"\r\n").await?; + socket_write.write_all(b"\r\n").await?; - socket_write.write_all(&message).await?; + socket_write.write_all(&message).await?; - socket_write.flush().await?; + socket_write.flush().await?; - Ok(()) + Ok(()) } #[derive(Debug, Serialize)] struct JsonRpcRequest

{ - jsonrpc: Cow<'static, str>, - id: u64, - method: Cow<'static, str>, - params: P, + jsonrpc:Cow<'static, str>, + id:u64, + method:Cow<'static, str>, + params:P, } #[derive(Debug, Deserialize)] #[serde(deny_unknown_fields)] struct JsonRpcResponse { - #[allow(dead_code)] - jsonrpc: Cow<'static, str>, - id: u64, - result: Option>, - error: Option, + #[allow(dead_code)] + jsonrpc:Cow<'static, str>, + id:u64, + result:Option>, + error:Option, } #[derive(Debug, Deserialize)] struct JsonRpcError { - #[allow(dead_code)] - code: i64, - message: String, - #[allow(dead_code)] - data: Option>, + #[allow(dead_code)] + code:i64, + message:String, + #[allow(dead_code)] + data:Option>, } enum TransportHeader { - ContentLength(usize), - ContentType, - Unknown(String), + ContentLength(usize), + ContentType, + Unknown(String), } impl FromStr for TransportHeader { - type Err = Error; + type Err = Error; - fn from_str(line: &str) -> Result { - let colon = line - .find(':') - .with_context(|| format!("could not find colon token in {line:?}"))?; + fn from_str(line:&str) -> Result { + let colon = line + .find(':') + .with_context(|| format!("could not find colon token in {line:?}"))?; - let (name, value) = line.split_at(colon); + let (name, value) = line.split_at(colon); - let value = value[1..].trim(); + let value = value[1..].trim(); - match name { - "Content-Length" => { - let value = value.parse().with_context(|| { - format!("could not parse Content-Length header value {value:?}") - })?; + match name { + "Content-Length" => { + let value = value + .parse() + .with_context(|| format!("could not parse Content-Length header value {value:?}"))?; - Ok(TransportHeader::ContentLength(value)) - } - "Content-Type" => { - ensure!( - value.starts_with( "application/vscode-jsonrpc"), - "invalid value for Content-Type expected \"application/vscode-jsonrpc\", got {value:?}" - ); + Ok(TransportHeader::ContentLength(value)) + }, + "Content-Type" => { + ensure!( + value.starts_with("application/vscode-jsonrpc"), + "invalid value for Content-Type expected \"application/vscode-jsonrpc\", got {value:?}" + ); - Ok(TransportHeader::ContentType) - } + Ok(TransportHeader::ContentType) + }, - _ => Ok(TransportHeader::Unknown(name.into())), - } - } + _ => Ok(TransportHeader::Unknown(name.into())), + } + } } diff --git a/crates/biome_cli/Source/service/unix.rs b/crates/biome_cli/Source/service/unix.rs index ab61115f3e73..54e890f1bc16 100644 --- a/crates/biome_cli/Source/service/unix.rs +++ b/crates/biome_cli/Source/service/unix.rs @@ -1,123 +1,124 @@ use std::{ - convert::Infallible, - env, fs, - io::{self, ErrorKind}, - path::PathBuf, - time::Duration, + convert::Infallible, + env, + fs, + io::{self, ErrorKind}, + path::PathBuf, + time::Duration, }; use biome_lsp::{ServerConnection, ServerFactory}; use tokio::{ - io::Interest, - net::{ - unix::{OwnedReadHalf, OwnedWriteHalf}, - UnixListener, UnixStream, - }, - process::{Child, Command}, - time, + io::Interest, + net::{ + UnixListener, + UnixStream, + unix::{OwnedReadHalf, OwnedWriteHalf}, + }, + process::{Child, Command}, + time, }; -use tracing::{debug, info, Instrument}; +use tracing::{Instrument, debug, info}; /// Returns the filesystem path of the global socket used to communicate with /// the server daemon fn get_socket_name() -> PathBuf { - biome_fs::ensure_cache_dir().join(format!("biome-socket-{}", biome_configuration::VERSION)) + biome_fs::ensure_cache_dir().join(format!("biome-socket-{}", biome_configuration::VERSION)) } pub(crate) fn enumerate_pipes() -> io::Result> { - fs::read_dir(biome_fs::ensure_cache_dir()).map(|iter| { - iter.filter_map(|entry| { - let entry = entry.ok()?.path(); + fs::read_dir(biome_fs::ensure_cache_dir()).map(|iter| { + iter.filter_map(|entry| { + let entry = entry.ok()?.path(); - let file_name = entry.file_name()?; + let file_name = entry.file_name()?; - let file_name = file_name.to_str()?; + let file_name = file_name.to_str()?; - let version = file_name.strip_prefix("biome-socket")?; + let version = file_name.strip_prefix("biome-socket")?; - if version.is_empty() { - Some(String::new()) - } else { - Some(version.strip_prefix('-')?.to_string()) - } - }) - }) + if version.is_empty() { + Some(String::new()) + } else { + Some(version.strip_prefix('-')?.to_string()) + } + }) + }) } -/// Try to connect to the global socket and wait for the connection to become ready +/// Try to connect to the global socket and wait for the connection to become +/// ready async fn try_connect() -> io::Result { - let socket_name = get_socket_name(); + let socket_name = get_socket_name(); - info!("Trying to connect to socket {}", socket_name.display()); + info!("Trying to connect to socket {}", socket_name.display()); - let stream = UnixStream::connect(socket_name).await?; + let stream = UnixStream::connect(socket_name).await?; - stream - .ready(Interest::READABLE | Interest::WRITABLE) - .await?; + stream.ready(Interest::READABLE | Interest::WRITABLE).await?; - Ok(stream) + Ok(stream) } /// Spawn the daemon server process in the background fn spawn_daemon( - stop_on_disconnect: bool, - config_path: Option, - log_path: Option, - log_file_name_prefix: Option, + stop_on_disconnect:bool, + config_path:Option, + log_path:Option, + log_file_name_prefix:Option, ) -> io::Result { - let binary = env::current_exe()?; + let binary = env::current_exe()?; - let mut cmd = Command::new(binary); + let mut cmd = Command::new(binary); - debug!("command {:?}", &cmd); + debug!("command {:?}", &cmd); - cmd.arg("__run_server"); + cmd.arg("__run_server"); - if stop_on_disconnect { - cmd.arg("--stop-on-disconnect"); - } + if stop_on_disconnect { + cmd.arg("--stop-on-disconnect"); + } - if let Some(config_path) = config_path { - cmd.arg(format!("--config-path={}", config_path.display())); - } + if let Some(config_path) = config_path { + cmd.arg(format!("--config-path={}", config_path.display())); + } - if let Some(log_path) = log_path { - cmd.arg(format!("--log-path={}", log_path.display())); - } + if let Some(log_path) = log_path { + cmd.arg(format!("--log-path={}", log_path.display())); + } - if let Some(log_file_name_prefix) = log_file_name_prefix { - cmd.arg(format!("--log-prefix-name={}", log_file_name_prefix)); - } + if let Some(log_file_name_prefix) = log_file_name_prefix { + cmd.arg(format!("--log-prefix-name={}", log_file_name_prefix)); + } - // Create a new session for the process and make it the leader, this will - // ensures that the child process is fully detached from its parent and will - // continue running in the background even after the parent process exits - // - // SAFETY: This closure runs in the forked child process before it starts - // executing, this is a highly unsafe environment because the process isn't - // running yet so seemingly innocuous operation like allocating memory may - // hang indefinitely. - // The only thing we do here is issuing a syscall, which is safe to do in - // this state but still "unsafe" in Rust semantics because it's technically - // mutating the shared global state of the process - unsafe { - cmd.pre_exec(|| { - libc::setsid(); - - Ok(()) - }); - } + // Create a new session for the process and make it the leader, this will + // ensures that the child process is fully detached from its parent and will + // continue running in the background even after the parent process exits + // + // SAFETY: This closure runs in the forked child process before it starts + // executing, this is a highly unsafe environment because the process isn't + // running yet so seemingly innocuous operation like allocating memory may + // hang indefinitely. + // The only thing we do here is issuing a syscall, which is safe to do in + // this state but still "unsafe" in Rust semantics because it's technically + // mutating the shared global state of the process + unsafe { + cmd.pre_exec(|| { + libc::setsid(); + + Ok(()) + }); + } - let child = cmd.spawn()?; + let child = cmd.spawn()?; - Ok(child) + Ok(child) } /// Open a connection to the daemon server process, returning [None] if the /// server is not running pub(crate) async fn open_socket() -> io::Result> { - match try_connect().await { + match try_connect().await { Ok(socket) => Ok(Some(socket.into_split())), Err(err) // The OS will return `ConnectionRefused` if the socket file exists @@ -139,119 +140,106 @@ pub(crate) async fn open_socket() -> io::Result, - log_path: Option, - log_file_name_prefix: Option, + stop_on_disconnect:bool, + config_path:Option, + log_path:Option, + log_file_name_prefix:Option, ) -> io::Result { - let mut current_child: Option = None; - - let mut last_error = None; - - // Try to initialize the connection a few times - for _ in 0..10 { - // Try to open a connection on the global socket - match try_connect().await { - // The connection is open and ready - Ok(_) => { - return Ok(current_child.is_some()); - } - - // There's no process listening on the global socket - Err(err) - if matches!( - err.kind(), - ErrorKind::NotFound | ErrorKind::ConnectionRefused - ) => - { - last_error = Some(err); - - if let Some(current_child) = &mut current_child { - // If we have a handle to the daemon process, wait for a few - // milliseconds for it to exit, or retry the connection - tokio::select! { - result = current_child.wait() => { - let _status = result?; - - return Err(io::Error::new( - io::ErrorKind::ConnectionReset, - "the server process exited before the connection could be established", - )); - } - - _ = time::sleep(Duration::from_millis(50)) => {} - } - } else { - // Spawn the daemon process and wait a few milliseconds for - // it to become ready then retry the connection - current_child = Some(spawn_daemon( - stop_on_disconnect, - config_path.clone(), - log_path.clone(), - log_file_name_prefix.clone(), - )?); - - time::sleep(Duration::from_millis(50)).await; - } - } - - Err(err) => return Err(err), - } - } - - // If the connection couldn't be opened after 10 tries fail with the last - // error message from the OS, or a generic error message otherwise - Err(last_error.unwrap_or_else(|| { - io::Error::new( - io::ErrorKind::Other, - "could not connect to the daemon socket", - ) - })) + let mut current_child:Option = None; + + let mut last_error = None; + + // Try to initialize the connection a few times + for _ in 0..10 { + // Try to open a connection on the global socket + match try_connect().await { + // The connection is open and ready + Ok(_) => { + return Ok(current_child.is_some()); + }, + + // There's no process listening on the global socket + Err(err) if matches!(err.kind(), ErrorKind::NotFound | ErrorKind::ConnectionRefused) => { + last_error = Some(err); + + if let Some(current_child) = &mut current_child { + // If we have a handle to the daemon process, wait for a few + // milliseconds for it to exit, or retry the connection + tokio::select! { + result = current_child.wait() => { + let _status = result?; + + return Err(io::Error::new( + io::ErrorKind::ConnectionReset, + "the server process exited before the connection could be established", + )); + } + + _ = time::sleep(Duration::from_millis(50)) => {} + } + } else { + // Spawn the daemon process and wait a few milliseconds for + // it to become ready then retry the connection + current_child = Some(spawn_daemon( + stop_on_disconnect, + config_path.clone(), + log_path.clone(), + log_file_name_prefix.clone(), + )?); + + time::sleep(Duration::from_millis(50)).await; + } + }, + + Err(err) => return Err(err), + } + } + + // If the connection couldn't be opened after 10 tries fail with the last + // error message from the OS, or a generic error message otherwise + Err(last_error.unwrap_or_else(|| io::Error::new(io::ErrorKind::Other, "could not connect to the daemon socket"))) } /// Ensure the server daemon is running and ready to receive connections and /// print the global socket name in the standard output pub(crate) async fn print_socket() -> io::Result<()> { - ensure_daemon(true, None, None, None).await?; + ensure_daemon(true, None, None, None).await?; - println!("{}", get_socket_name().display()); + println!("{}", get_socket_name().display()); - Ok(()) + Ok(()) } /// Start listening on the global socket and accepting connections with the /// provided [ServerFactory] -pub(crate) async fn run_daemon( - factory: ServerFactory, - config_path: Option, -) -> io::Result { - let path = get_socket_name(); +pub(crate) async fn run_daemon(factory:ServerFactory, config_path:Option) -> io::Result { + let path = get_socket_name(); - info!("Trying to connect to socket {}", path.display()); + info!("Trying to connect to socket {}", path.display()); - // Try to remove the socket file if it already exists - if path.exists() { - info!("Remove socket folder {}", path.display()); + // Try to remove the socket file if it already exists + if path.exists() { + info!("Remove socket folder {}", path.display()); - fs::remove_file(&path)?; - } + fs::remove_file(&path)?; + } - let listener = UnixListener::bind(path)?; + let listener = UnixListener::bind(path)?; - loop { - let (stream, _) = listener.accept().await?; + loop { + let (stream, _) = listener.accept().await?; - let connection = factory.create(config_path.clone()); + let connection = factory.create(config_path.clone()); - let span = tracing::trace_span!("run_server"); + let span = tracing::trace_span!("run_server"); - tokio::spawn(run_server(connection, stream).instrument(span.or_current())); - } + tokio::spawn(run_server(connection, stream).instrument(span.or_current())); + } } /// Async task driving a single client connection -async fn run_server(connection: ServerConnection, stream: UnixStream) { - let (read, write) = stream.into_split(); +async fn run_server(connection:ServerConnection, stream:UnixStream) { + let (read, write) = stream.into_split(); - connection.accept(read, write).await; + connection.accept(read, write).await; } diff --git a/crates/biome_cli/Source/service/windows.rs b/crates/biome_cli/Source/service/windows.rs index d54578355223..d263a3d05423 100644 --- a/crates/biome_cli/Source/service/windows.rs +++ b/crates/biome_cli/Source/service/windows.rs @@ -1,193 +1,179 @@ use std::{ - convert::Infallible, - env, - fs::read_dir, - io::{self, ErrorKind}, - mem::swap, - os::windows::process::CommandExt, - path::PathBuf, - pin::Pin, - process::Command, - sync::Arc, - task::{Context, Poll}, - time::Duration, + convert::Infallible, + env, + fs::read_dir, + io::{self, ErrorKind}, + mem::swap, + os::windows::process::CommandExt, + path::PathBuf, + pin::Pin, + process::Command, + sync::Arc, + task::{Context, Poll}, + time::Duration, }; use biome_lsp::{ServerConnection, ServerFactory}; use tokio::{ - io::{AsyncRead, AsyncWrite, ReadBuf}, - net::windows::named_pipe::{ClientOptions, NamedPipeClient, NamedPipeServer, ServerOptions}, - time, + io::{AsyncRead, AsyncWrite, ReadBuf}, + net::windows::named_pipe::{ClientOptions, NamedPipeClient, NamedPipeServer, ServerOptions}, + time, }; use tracing::Instrument; /// Returns the name of the global named pipe used to communicate with the /// server daemon -fn get_pipe_name() -> String { - format!(r"\\.\pipe\biome-service-{}", biome_configuration::VERSION) -} +fn get_pipe_name() -> String { format!(r"\\.\pipe\biome-service-{}", biome_configuration::VERSION) } pub(crate) fn enumerate_pipes() -> io::Result> { - read_dir(r"\\.\pipe").map(|iter| { - iter.filter_map(|entry| { - let entry = entry.ok()?.path(); + read_dir(r"\\.\pipe").map(|iter| { + iter.filter_map(|entry| { + let entry = entry.ok()?.path(); - let file_name = entry.file_name()?; + let file_name = entry.file_name()?; - let file_name = file_name.to_str()?; + let file_name = file_name.to_str()?; - let version = file_name.strip_prefix("rome-service")?; + let version = file_name.strip_prefix("rome-service")?; - if version.is_empty() { - Some(String::new()) - } else { - Some(version.strip_prefix('-')?.to_string()) - } - }) - }) + if version.is_empty() { + Some(String::new()) + } else { + Some(version.strip_prefix('-')?.to_string()) + } + }) + }) } /// Error code from the Win32 API -const ERROR_PIPE_BUSY: i32 = 231; +const ERROR_PIPE_BUSY:i32 = 231; -/// Try to connect to the global pipe and wait for the connection to become ready +/// Try to connect to the global pipe and wait for the connection to become +/// ready async fn try_connect() -> io::Result { - loop { - match ClientOptions::new().open(get_pipe_name()) { - Ok(client) => return Ok(client), - // If the connection failed with ERROR_PIPE_BUSY, wait a few - // milliseconds then retry the connection (we should be using - // WaitNamedPipe here but that's not exposed by tokio / mio) - Err(e) if e.raw_os_error() == Some(ERROR_PIPE_BUSY) => {} - - Err(e) => return Err(e), - } - - time::sleep(Duration::from_millis(50)).await; - } + loop { + match ClientOptions::new().open(get_pipe_name()) { + Ok(client) => return Ok(client), + // If the connection failed with ERROR_PIPE_BUSY, wait a few + // milliseconds then retry the connection (we should be using + // WaitNamedPipe here but that's not exposed by tokio / mio) + Err(e) if e.raw_os_error() == Some(ERROR_PIPE_BUSY) => {}, + + Err(e) => return Err(e), + } + + time::sleep(Duration::from_millis(50)).await; + } } /// Process creation flag from the Win32 API, ensures the process is created /// in its own group and will not be killed when the parent process exits -const CREATE_NEW_PROCESS_GROUP: u32 = 0x00000200; +const CREATE_NEW_PROCESS_GROUP:u32 = 0x00000200; /// Spawn the daemon server process in the background fn spawn_daemon( - stop_on_disconnect: bool, - config_path: Option, - log_path: Option, - log_file_name_prefix: Option, + stop_on_disconnect:bool, + config_path:Option, + log_path:Option, + log_file_name_prefix:Option, ) -> io::Result<()> { - let binary = env::current_exe()?; + let binary = env::current_exe()?; - let mut cmd = Command::new(binary); + let mut cmd = Command::new(binary); - cmd.arg("__run_server"); + cmd.arg("__run_server"); - if stop_on_disconnect { - cmd.arg("--stop-on-disconnect"); - } + if stop_on_disconnect { + cmd.arg("--stop-on-disconnect"); + } - if let Some(config_path) = config_path { - cmd.arg(format!("--config-path={}", config_path.display())); - } + if let Some(config_path) = config_path { + cmd.arg(format!("--config-path={}", config_path.display())); + } - if let Some(log_path) = log_path { - cmd.arg(format!("--log-path={}", log_path.display())); - } + if let Some(log_path) = log_path { + cmd.arg(format!("--log-path={}", log_path.display())); + } - if let Some(log_file_name_prefix) = log_file_name_prefix { - cmd.arg(format!("--log-prefix-name={}", log_file_name_prefix)); - } + if let Some(log_file_name_prefix) = log_file_name_prefix { + cmd.arg(format!("--log-prefix-name={}", log_file_name_prefix)); + } - cmd.creation_flags(CREATE_NEW_PROCESS_GROUP); + cmd.creation_flags(CREATE_NEW_PROCESS_GROUP); - cmd.spawn()?; + cmd.spawn()?; - Ok(()) + Ok(()) } /// Open a connection to the daemon server process, returning [None] if the /// server is not running pub(crate) async fn open_socket() -> io::Result> { - match try_connect().await { - Ok(socket) => { - let inner = Arc::new(socket); - - Ok(Some(( - ClientReadHalf { - inner: inner.clone(), - }, - ClientWriteHalf { inner }, - ))) - } - - Err(err) if err.kind() == ErrorKind::NotFound => Ok(None), - Err(err) => Err(err), - } + match try_connect().await { + Ok(socket) => { + let inner = Arc::new(socket); + + Ok(Some((ClientReadHalf { inner:inner.clone() }, ClientWriteHalf { inner }))) + }, + + Err(err) if err.kind() == ErrorKind::NotFound => Ok(None), + Err(err) => Err(err), + } } pub(crate) struct ClientReadHalf { - inner: Arc, + inner:Arc, } impl AsyncRead for ClientReadHalf { - fn poll_read( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut ReadBuf<'_>, - ) -> Poll> { - loop { - match self.inner.poll_read_ready(cx) { - Poll::Ready(Ok(())) => match self.inner.try_read(buf.initialize_unfilled()) { - Ok(count) => { - buf.advance(count); - - return Poll::Ready(Ok(())); - } - - Err(err) if err.kind() == io::ErrorKind::WouldBlock => continue, - Err(err) => return Poll::Ready(Err(err)), - }, - - Poll::Ready(Err(err)) => return Poll::Ready(Err(err)), - Poll::Pending => return Poll::Pending, - }; - } - } + fn poll_read(self: Pin<&mut Self>, cx:&mut Context<'_>, buf:&mut ReadBuf<'_>) -> Poll> { + loop { + match self.inner.poll_read_ready(cx) { + Poll::Ready(Ok(())) => { + match self.inner.try_read(buf.initialize_unfilled()) { + Ok(count) => { + buf.advance(count); + + return Poll::Ready(Ok(())); + }, + + Err(err) if err.kind() == io::ErrorKind::WouldBlock => continue, + Err(err) => return Poll::Ready(Err(err)), + } + }, + + Poll::Ready(Err(err)) => return Poll::Ready(Err(err)), + Poll::Pending => return Poll::Pending, + }; + } + } } pub(crate) struct ClientWriteHalf { - inner: Arc, + inner:Arc, } impl AsyncWrite for ClientWriteHalf { - fn poll_write( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - loop { - match self.inner.poll_write_ready(cx) { - Poll::Ready(Ok(())) => match self.inner.try_write(buf) { - Ok(count) => return Poll::Ready(Ok(count)), - Err(err) if err.kind() == io::ErrorKind::WouldBlock => continue, - Err(err) => return Poll::Ready(Err(err)), - }, - - Poll::Ready(Err(err)) => return Poll::Ready(Err(err)), - Poll::Pending => return Poll::Pending, - } - } - } - - fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - - fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.poll_flush(cx) - } + fn poll_write(self: Pin<&mut Self>, cx:&mut Context<'_>, buf:&[u8]) -> Poll> { + loop { + match self.inner.poll_write_ready(cx) { + Poll::Ready(Ok(())) => { + match self.inner.try_write(buf) { + Ok(count) => return Poll::Ready(Ok(count)), + Err(err) if err.kind() == io::ErrorKind::WouldBlock => continue, + Err(err) => return Poll::Ready(Err(err)), + } + }, + + Poll::Ready(Err(err)) => return Poll::Ready(Err(err)), + Poll::Pending => return Poll::Pending, + } + } + } + + fn poll_flush(self: Pin<&mut Self>, _cx:&mut Context<'_>) -> Poll> { Poll::Ready(Ok(())) } + + fn poll_shutdown(self: Pin<&mut Self>, cx:&mut Context<'_>) -> Poll> { self.poll_flush(cx) } } /// Ensure the server daemon is running and ready to receive connections @@ -195,143 +181,128 @@ impl AsyncWrite for ClientWriteHalf { /// Returns false if the daemon process was already running or true if it had /// to be started pub(crate) async fn ensure_daemon( - stop_on_disconnect: bool, - config_path: Option, - log_path: Option, - log_file_name_prefix: Option, + stop_on_disconnect:bool, + config_path:Option, + log_path:Option, + log_file_name_prefix:Option, ) -> io::Result { - let mut did_spawn = false; + let mut did_spawn = false; - loop { - match open_socket().await { - Ok(Some(_)) => break, - Ok(None) => { - spawn_daemon( - stop_on_disconnect, - config_path.clone(), - log_path.clone(), - log_file_name_prefix.clone(), - )?; + loop { + match open_socket().await { + Ok(Some(_)) => break, + Ok(None) => { + spawn_daemon( + stop_on_disconnect, + config_path.clone(), + log_path.clone(), + log_file_name_prefix.clone(), + )?; - did_spawn = true; + did_spawn = true; - time::sleep(Duration::from_millis(50)).await; - } + time::sleep(Duration::from_millis(50)).await; + }, - Err(err) => return Err(err), - } - } + Err(err) => return Err(err), + } + } - Ok(did_spawn) + Ok(did_spawn) } /// Ensure the server daemon is running and ready to receive connections and /// print the global pipe name in the standard output pub(crate) async fn print_socket() -> io::Result<()> { - ensure_daemon(true, None, None, None).await?; + ensure_daemon(true, None, None, None).await?; - println!("{}", get_pipe_name()); + println!("{}", get_pipe_name()); - Ok(()) + Ok(()) } /// Start listening on the global pipe and accepting connections with the /// provided [ServerFactory] -pub(crate) async fn run_daemon( - factory: ServerFactory, - config_path: Option, -) -> io::Result { - let mut prev_server = ServerOptions::new() - .first_pipe_instance(true) - .create(get_pipe_name())?; +pub(crate) async fn run_daemon(factory:ServerFactory, config_path:Option) -> io::Result { + let mut prev_server = ServerOptions::new().first_pipe_instance(true).create(get_pipe_name())?; - loop { - prev_server.connect().await?; + loop { + prev_server.connect().await?; - let mut next_server = ServerOptions::new().create(get_pipe_name())?; + let mut next_server = ServerOptions::new().create(get_pipe_name())?; - swap(&mut prev_server, &mut next_server); + swap(&mut prev_server, &mut next_server); - let connection = factory.create(config_path.clone()); + let connection = factory.create(config_path.clone()); - let span = tracing::trace_span!("run_server"); + let span = tracing::trace_span!("run_server"); - tokio::spawn(run_server(connection, next_server).instrument(span.or_current())); - } + tokio::spawn(run_server(connection, next_server).instrument(span.or_current())); + } } /// Async task driving a single client connection -async fn run_server(connection: ServerConnection, stream: NamedPipeServer) { - let inner = Arc::new(stream); +async fn run_server(connection:ServerConnection, stream:NamedPipeServer) { + let inner = Arc::new(stream); - let read = ServerReadHalf { - inner: inner.clone(), - }; + let read = ServerReadHalf { inner:inner.clone() }; - let write = ServerWriteHalf { inner }; + let write = ServerWriteHalf { inner }; - connection.accept(read, write).await; + connection.accept(read, write).await; } struct ServerReadHalf { - inner: Arc, + inner:Arc, } impl AsyncRead for ServerReadHalf { - fn poll_read( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut ReadBuf<'_>, - ) -> Poll> { - loop { - match self.inner.poll_read_ready(cx) { - Poll::Ready(Ok(())) => match self.inner.try_read(buf.initialize_unfilled()) { - Ok(count) => { - buf.advance(count); - - return Poll::Ready(Ok(())); - } - - Err(err) if err.kind() == io::ErrorKind::WouldBlock => continue, - Err(err) => return Poll::Ready(Err(err)), - }, - - Poll::Ready(Err(err)) => return Poll::Ready(Err(err)), - Poll::Pending => return Poll::Pending, - }; - } - } + fn poll_read(self: Pin<&mut Self>, cx:&mut Context<'_>, buf:&mut ReadBuf<'_>) -> Poll> { + loop { + match self.inner.poll_read_ready(cx) { + Poll::Ready(Ok(())) => { + match self.inner.try_read(buf.initialize_unfilled()) { + Ok(count) => { + buf.advance(count); + + return Poll::Ready(Ok(())); + }, + + Err(err) if err.kind() == io::ErrorKind::WouldBlock => continue, + Err(err) => return Poll::Ready(Err(err)), + } + }, + + Poll::Ready(Err(err)) => return Poll::Ready(Err(err)), + Poll::Pending => return Poll::Pending, + }; + } + } } struct ServerWriteHalf { - inner: Arc, + inner:Arc, } impl AsyncWrite for ServerWriteHalf { - fn poll_write( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - loop { - match self.inner.poll_write_ready(cx) { - Poll::Ready(Ok(())) => match self.inner.try_write(buf) { - Ok(count) => return Poll::Ready(Ok(count)), - Err(err) if err.kind() == io::ErrorKind::WouldBlock => continue, - Err(err) => return Poll::Ready(Err(err)), - }, - - Poll::Ready(Err(err)) => return Poll::Ready(Err(err)), - Poll::Pending => return Poll::Pending, - } - } - } - - fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - - fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.poll_flush(cx) - } + fn poll_write(self: Pin<&mut Self>, cx:&mut Context<'_>, buf:&[u8]) -> Poll> { + loop { + match self.inner.poll_write_ready(cx) { + Poll::Ready(Ok(())) => { + match self.inner.try_write(buf) { + Ok(count) => return Poll::Ready(Ok(count)), + Err(err) if err.kind() == io::ErrorKind::WouldBlock => continue, + Err(err) => return Poll::Ready(Err(err)), + } + }, + + Poll::Ready(Err(err)) => return Poll::Ready(Err(err)), + Poll::Pending => return Poll::Pending, + } + } + } + + fn poll_flush(self: Pin<&mut Self>, _cx:&mut Context<'_>) -> Poll> { Poll::Ready(Ok(())) } + + fn poll_shutdown(self: Pin<&mut Self>, cx:&mut Context<'_>) -> Poll> { self.poll_flush(cx) } } diff --git a/crates/biome_cli/examples/text_reporter.rs b/crates/biome_cli/examples/text_reporter.rs index 69b7f67c84e3..db724a9f3db5 100644 --- a/crates/biome_cli/examples/text_reporter.rs +++ b/crates/biome_cli/examples/text_reporter.rs @@ -1,11 +1,4 @@ -use biome_cli::{ - DiagnosticsPayload, - Execution, - Reporter, - ReporterVisitor, - TraversalSummary, - VcsTargeted, -}; +use biome_cli::{DiagnosticsPayload, Execution, Reporter, ReporterVisitor, TraversalSummary, VcsTargeted}; /// This will be the visitor, which where we **write** the data struct BufferVisitor(String); @@ -27,21 +20,13 @@ impl Reporter for TextReport { } impl ReporterVisitor for BufferVisitor { - fn report_summary( - &mut self, - _execution:&Execution, - summary:TraversalSummary, - ) -> std::io::Result<()> { + fn report_summary(&mut self, _execution:&Execution, summary:TraversalSummary) -> std::io::Result<()> { self.0.push_str(&format!("Total is {}", summary.changed + summary.unchanged)); Ok(()) } - fn report_diagnostics( - &mut self, - _execution:&Execution, - _payload:DiagnosticsPayload, - ) -> std::io::Result<()> { + fn report_diagnostics(&mut self, _execution:&Execution, _payload:DiagnosticsPayload) -> std::io::Result<()> { todo!() } } diff --git a/crates/biome_configuration/Source/analyzer/assists/actions.rs b/crates/biome_configuration/Source/analyzer/assists/actions.rs index fb7263fd5ff1..6688d10aa230 100644 --- a/crates/biome_configuration/Source/analyzer/assists/actions.rs +++ b/crates/biome_configuration/Source/analyzer/assists/actions.rs @@ -1,182 +1,185 @@ //! Generated file, do not edit by hand, see `xtask/codegen` -use crate::analyzer::{RuleAssistConfiguration, RuleAssistPlainConfiguration}; -use biome_analyze::{options::RuleOptions, RuleFilter}; +use biome_analyze::{RuleFilter, options::RuleOptions}; use biome_deserialize_macros::{Deserializable, Merge}; use biome_diagnostics::{Category, Severity}; use rustc_hash::FxHashSet; #[cfg(feature = "schema")] use schemars::JsonSchema; use serde::{Deserialize, Serialize}; + +use crate::analyzer::{RuleAssistConfiguration, RuleAssistPlainConfiguration}; #[derive( - Clone, - Copy, - Debug, - Deserializable, - Eq, - Hash, - Merge, - Ord, - PartialEq, - PartialOrd, - serde :: Deserialize, - serde :: Serialize, + Clone, + Copy, + Debug, + Deserializable, + Eq, + Hash, + Merge, + Ord, + PartialEq, + PartialOrd, + serde :: Deserialize, + serde :: Serialize, )] #[cfg_attr(feature = "schema", derive(JsonSchema))] #[serde(rename_all = "camelCase")] pub enum RuleGroup { - Source, + Source, } impl RuleGroup { - pub const fn as_str(self) -> &'static str { - match self { - Self::Source => Source::GROUP_NAME, - } - } + pub const fn as_str(self) -> &'static str { + match self { + Self::Source => Source::GROUP_NAME, + } + } } impl std::str::FromStr for RuleGroup { - type Err = &'static str; - - fn from_str(s: &str) -> Result { - match s { - Source::GROUP_NAME => Ok(Self::Source), - _ => Err("This rule group doesn't exist."), - } - } + type Err = &'static str; + + fn from_str(s:&str) -> Result { + match s { + Source::GROUP_NAME => Ok(Self::Source), + _ => Err("This rule group doesn't exist."), + } + } } #[derive(Clone, Debug, Default, Deserialize, Deserializable, Eq, Merge, PartialEq, Serialize)] #[cfg_attr(feature = "schema", derive(JsonSchema))] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct Actions { - #[deserializable(rename = "source")] - #[serde(skip_serializing_if = "Option::is_none")] - pub source: Option, + #[deserializable(rename = "source")] + #[serde(skip_serializing_if = "Option::is_none")] + pub source:Option, } impl Actions { - #[doc = r" Checks if the code coming from [biome_diagnostics::Diagnostic] corresponds to a rule."] - #[doc = r" Usually the code is built like {group}/{rule_name}"] - pub fn has_rule(group: RuleGroup, rule_name: &str) -> Option<&'static str> { - match group { - RuleGroup::Source => Source::has_rule(rule_name), - } - } - #[doc = r" Given a category coming from [Diagnostic](biome_diagnostics::Diagnostic), this function returns"] - #[doc = r" the [Severity](biome_diagnostics::Severity) associated to the rule, if the configuration changed it."] - #[doc = r" If the severity is off or not set, then the function returns the default severity of the rule:"] - #[doc = r" [Severity::Error] for recommended rules and [Severity::Warning] for other rules."] - #[doc = r""] - #[doc = r" If not, the function returns [None]."] - pub fn get_severity_from_code(&self, category: &Category) -> Option { - let mut split_code = category.name().split('/'); - - let _lint = split_code.next(); - - debug_assert_eq!(_lint, Some("assists")); - - let group = ::from_str(split_code.next()?).ok()?; - - let rule_name = split_code.next()?; - - let rule_name = Self::has_rule(group, rule_name)?; - - match group { - RuleGroup::Source => self - .source - .as_ref() - .and_then(|group| group.get_rule_configuration(rule_name)) - .filter(|(level, _)| !matches!(level, RuleAssistPlainConfiguration::Off)) - .map(|(level, _)| level.into()), - } - } - #[doc = r" It returns the enabled rules by default."] - #[doc = r""] - #[doc = r" The enabled rules are calculated from the difference with the disabled rules."] - pub fn as_enabled_rules(&self) -> FxHashSet> { - let mut enabled_rules = FxHashSet::default(); - - if let Some(group) = self.source.as_ref() { - enabled_rules.extend(&group.get_enabled_rules()); - } - - enabled_rules - } + /// Checks if the code coming from [biome_diagnostics::Diagnostic] + /// corresponds to a rule. + /// Usually the code is built like {group}/{rule_name} + pub fn has_rule(group:RuleGroup, rule_name:&str) -> Option<&'static str> { + match group { + RuleGroup::Source => Source::has_rule(rule_name), + } + } + + /// Given a category coming from + /// [Diagnostic](biome_diagnostics::Diagnostic), this function returns + /// the [Severity](biome_diagnostics::Severity) associated to the rule, if + /// the configuration changed it. + /// If the severity is off or not set, then the function returns the default + /// severity of the rule: + /// [Severity::Error] for recommended rules and [Severity::Warning] for + /// other rules. + /// + /// If not, the function returns [None]. + pub fn get_severity_from_code(&self, category:&Category) -> Option { + let mut split_code = category.name().split('/'); + + let _lint = split_code.next(); + + debug_assert_eq!(_lint, Some("assists")); + + let group = ::from_str(split_code.next()?).ok()?; + + let rule_name = split_code.next()?; + + let rule_name = Self::has_rule(group, rule_name)?; + + match group { + RuleGroup::Source => { + self.source + .as_ref() + .and_then(|group| group.get_rule_configuration(rule_name)) + .filter(|(level, _)| !matches!(level, RuleAssistPlainConfiguration::Off)) + .map(|(level, _)| level.into()) + }, + } + } + + /// It returns the enabled rules by default. + /// + /// The enabled rules are calculated from the difference with the disabled + /// rules. + pub fn as_enabled_rules(&self) -> FxHashSet> { + let mut enabled_rules = FxHashSet::default(); + + if let Some(group) = self.source.as_ref() { + enabled_rules.extend(&group.get_enabled_rules()); + } + + enabled_rules + } } #[derive(Clone, Debug, Default, Deserialize, Deserializable, Eq, Merge, PartialEq, Serialize)] #[cfg_attr(feature = "schema", derive(JsonSchema))] #[serde(rename_all = "camelCase", default, deny_unknown_fields)] -#[doc = r" A list of rules that belong to this group"] +/// A list of rules that belong to this group pub struct Source { - #[doc = "Provides a whole-source code action to sort the imports in the file using import groups and natural ordering."] - #[serde(skip_serializing_if = "Option::is_none")] - pub organize_imports: - Option>, - #[doc = "Enforce attribute sorting in JSX elements."] - #[serde(skip_serializing_if = "Option::is_none")] - pub use_sorted_attributes: - Option>, - #[doc = "Sorts the keys of a JSON object in natural order"] - #[serde(skip_serializing_if = "Option::is_none")] - pub use_sorted_keys: - Option>, + /// Provides a whole-source code action to sort the imports in the file + /// using import groups and natural ordering. + #[serde(skip_serializing_if = "Option::is_none")] + pub organize_imports:Option>, + /// Enforce attribute sorting in JSX elements. + #[serde(skip_serializing_if = "Option::is_none")] + pub use_sorted_attributes:Option>, + /// Sorts the keys of a JSON object in natural order + #[serde(skip_serializing_if = "Option::is_none")] + pub use_sorted_keys:Option>, } impl Source { - const GROUP_NAME: &'static str = "source"; - - pub(crate) const GROUP_RULES: &'static [&'static str] = - &["organizeImports", "useSortedAttributes", "useSortedKeys"]; - - pub(crate) fn get_enabled_rules(&self) -> FxHashSet> { - let mut index_set = FxHashSet::default(); - - if let Some(rule) = self.organize_imports.as_ref() { - if rule.is_enabled() { - index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[0])); - } - } - - if let Some(rule) = self.use_sorted_attributes.as_ref() { - if rule.is_enabled() { - index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[1])); - } - } - - if let Some(rule) = self.use_sorted_keys.as_ref() { - if rule.is_enabled() { - index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[2])); - } - } - - index_set - } - #[doc = r" Checks if, given a rule name, matches one of the rules contained in this category"] - pub(crate) fn has_rule(rule_name: &str) -> Option<&'static str> { - Some(Self::GROUP_RULES[Self::GROUP_RULES.binary_search(&rule_name).ok()?]) - } - - pub(crate) fn get_rule_configuration( - &self, - rule_name: &str, - ) -> Option<(RuleAssistPlainConfiguration, Option)> { - match rule_name { - "organizeImports" => self - .organize_imports - .as_ref() - .map(|conf| (conf.level(), conf.get_options())), - "useSortedAttributes" => self - .use_sorted_attributes - .as_ref() - .map(|conf| (conf.level(), conf.get_options())), - "useSortedKeys" => self - .use_sorted_keys - .as_ref() - .map(|conf| (conf.level(), conf.get_options())), - _ => None, - } - } + const GROUP_NAME:&'static str = "source"; + pub(crate) const GROUP_RULES:&'static [&'static str] = &["organizeImports", "useSortedAttributes", "useSortedKeys"]; + + pub(crate) fn get_enabled_rules(&self) -> FxHashSet> { + let mut index_set = FxHashSet::default(); + + if let Some(rule) = self.organize_imports.as_ref() { + if rule.is_enabled() { + index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[0])); + } + } + + if let Some(rule) = self.use_sorted_attributes.as_ref() { + if rule.is_enabled() { + index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[1])); + } + } + + if let Some(rule) = self.use_sorted_keys.as_ref() { + if rule.is_enabled() { + index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[2])); + } + } + + index_set + } + + /// Checks if, given a rule name, matches one of the rules contained in this + /// category + pub(crate) fn has_rule(rule_name:&str) -> Option<&'static str> { + Some(Self::GROUP_RULES[Self::GROUP_RULES.binary_search(&rule_name).ok()?]) + } + + pub(crate) fn get_rule_configuration( + &self, + rule_name:&str, + ) -> Option<(RuleAssistPlainConfiguration, Option)> { + match rule_name { + "organizeImports" => self.organize_imports.as_ref().map(|conf| (conf.level(), conf.get_options())), + "useSortedAttributes" => { + self.use_sorted_attributes + .as_ref() + .map(|conf| (conf.level(), conf.get_options())) + }, + "useSortedKeys" => self.use_sorted_keys.as_ref().map(|conf| (conf.level(), conf.get_options())), + _ => None, + } + } } #[test] fn test_order() { - for items in Source::GROUP_RULES.windows(2) { - assert!(items[0] < items[1], "{} < {}", items[0], items[1]); - } + for items in Source::GROUP_RULES.windows(2) { + assert!(items[0] < items[1], "{} < {}", items[0], items[1]); + } } diff --git a/crates/biome_configuration/Source/analyzer/assists/mod.rs b/crates/biome_configuration/Source/analyzer/assists/mod.rs index 1fe0db5add13..96d7ff24cfa2 100644 --- a/crates/biome_configuration/Source/analyzer/assists/mod.rs +++ b/crates/biome_configuration/Source/analyzer/assists/mod.rs @@ -1,42 +1,44 @@ mod actions; -pub use crate::analyzer::assists::actions::*; use biome_deserialize::StringSet; use biome_deserialize_macros::{Deserializable, Merge, Partial}; use bpaf::Bpaf; use serde::{Deserialize, Serialize}; +pub use crate::analyzer::assists::actions::*; + #[derive(Clone, Debug, Deserialize, Eq, Partial, PartialEq, Serialize)] #[partial(derive(Bpaf, Clone, Deserializable, Eq, Merge, PartialEq))] #[partial(cfg_attr(feature = "schema", derive(schemars::JsonSchema)))] #[partial(serde(deny_unknown_fields, rename_all = "camelCase"))] pub struct AssistsConfiguration { - /// Whether Biome should enable assists via LSP. - #[partial(bpaf(long("assists-enabled"), argument("true|false")))] - pub enabled: bool, + /// Whether Biome should enable assists via LSP. + #[partial(bpaf(long("assists-enabled"), argument("true|false")))] + pub enabled:bool, - /// Whether Biome should fail in CLI if the assists were not applied to the code. - #[partial(bpaf(pure(Default::default()), optional, hide))] - pub actions: Actions, + /// Whether Biome should fail in CLI if the assists were not applied to the + /// code. + #[partial(bpaf(pure(Default::default()), optional, hide))] + pub actions:Actions, - /// A list of Unix shell style patterns. The formatter will ignore files/folders that will - /// match these patterns. - #[partial(bpaf(hide))] - pub ignore: StringSet, + /// A list of Unix shell style patterns. The formatter will ignore + /// files/folders that will match these patterns. + #[partial(bpaf(hide))] + pub ignore:StringSet, - /// A list of Unix shell style patterns. The formatter will include files/folders that will - /// match these patterns. - #[partial(bpaf(hide))] - pub include: StringSet, + /// A list of Unix shell style patterns. The formatter will include + /// files/folders that will match these patterns. + #[partial(bpaf(hide))] + pub include:StringSet, } impl Default for AssistsConfiguration { - fn default() -> Self { - Self { - enabled: true, - actions: Actions::default(), - ignore: StringSet::default(), - include: StringSet::default(), - } - } + fn default() -> Self { + Self { + enabled:true, + actions:Actions::default(), + ignore:StringSet::default(), + include:StringSet::default(), + } + } } diff --git a/crates/biome_configuration/Source/analyzer/linter/mod.rs b/crates/biome_configuration/Source/analyzer/linter/mod.rs index 3b3564381018..0fcd739a1e87 100644 --- a/crates/biome_configuration/Source/analyzer/linter/mod.rs +++ b/crates/biome_configuration/Source/analyzer/linter/mod.rs @@ -12,48 +12,43 @@ use serde::{Deserialize, Serialize}; #[partial(cfg_attr(feature = "schema", derive(schemars::JsonSchema)))] #[partial(serde(rename_all = "camelCase", default, deny_unknown_fields))] pub struct LinterConfiguration { - /// if `false`, it disables the feature and the linter won't be executed. `true` by default - #[partial(bpaf(hide))] - pub enabled: bool, - - /// List of rules - #[partial(bpaf(pure(Default::default()), optional, hide))] - pub rules: Rules, - - /// A list of Unix shell style patterns. The formatter will ignore files/folders that will - /// match these patterns. - #[partial(bpaf(hide))] - pub ignore: StringSet, - - /// A list of Unix shell style patterns. The formatter will include files/folders that will - /// match these patterns. - #[partial(bpaf(hide))] - pub include: StringSet, + /// if `false`, it disables the feature and the linter won't be executed. + /// `true` by default + #[partial(bpaf(hide))] + pub enabled:bool, + + /// List of rules + #[partial(bpaf(pure(Default::default()), optional, hide))] + pub rules:Rules, + + /// A list of Unix shell style patterns. The formatter will ignore + /// files/folders that will match these patterns. + #[partial(bpaf(hide))] + pub ignore:StringSet, + + /// A list of Unix shell style patterns. The formatter will include + /// files/folders that will match these patterns. + #[partial(bpaf(hide))] + pub include:StringSet, } impl LinterConfiguration { - pub const fn is_disabled(&self) -> bool { - !self.enabled - } + pub const fn is_disabled(&self) -> bool { !self.enabled } } impl Default for LinterConfiguration { - fn default() -> Self { - Self { - enabled: true, - rules: Default::default(), - ignore: Default::default(), - include: Default::default(), - } - } + fn default() -> Self { + Self { + enabled:true, + rules:Default::default(), + ignore:Default::default(), + include:Default::default(), + } + } } impl PartialLinterConfiguration { - pub const fn is_disabled(&self) -> bool { - matches!(self.enabled, Some(false)) - } + pub const fn is_disabled(&self) -> bool { matches!(self.enabled, Some(false)) } - pub fn get_rules(&self) -> Rules { - self.rules.clone().unwrap_or_default() - } + pub fn get_rules(&self) -> Rules { self.rules.clone().unwrap_or_default() } } diff --git a/crates/biome_configuration/Source/analyzer/linter/rules.rs b/crates/biome_configuration/Source/analyzer/linter/rules.rs index 9e86087ec783..f5138cda1d7a 100644 --- a/crates/biome_configuration/Source/analyzer/linter/rules.rs +++ b/crates/biome_configuration/Source/analyzer/linter/rules.rs @@ -1,7 +1,6 @@ //! Generated file, do not edit by hand, see `xtask/codegen` -use crate::analyzer::{RuleConfiguration, RuleFixConfiguration, RulePlainConfiguration}; -use biome_analyze::{options::RuleOptions, RuleFilter}; +use biome_analyze::{RuleFilter, options::RuleOptions}; use biome_console::markup; use biome_deserialize::{DeserializableValidator, DeserializationDiagnostic}; use biome_deserialize_macros::{Deserializable, Merge}; @@ -11,8190 +10,7696 @@ use rustc_hash::FxHashSet; #[cfg(feature = "schema")] use schemars::JsonSchema; use serde::{Deserialize, Serialize}; + +use crate::analyzer::{RuleConfiguration, RuleFixConfiguration, RulePlainConfiguration}; #[derive( - Clone, - Copy, - Debug, - Deserializable, - Eq, - Hash, - Merge, - Ord, - PartialEq, - PartialOrd, - serde :: Deserialize, - serde :: Serialize, + Clone, + Copy, + Debug, + Deserializable, + Eq, + Hash, + Merge, + Ord, + PartialEq, + PartialOrd, + serde :: Deserialize, + serde :: Serialize, )] #[cfg_attr(feature = "schema", derive(JsonSchema))] #[serde(rename_all = "camelCase")] pub enum RuleGroup { - A11y, - Complexity, - Correctness, - Nursery, - Performance, - Security, - Style, - Suspicious, + A11y, + Complexity, + Correctness, + Nursery, + Performance, + Security, + Style, + Suspicious, } impl RuleGroup { - pub const fn as_str(self) -> &'static str { - match self { - Self::A11y => A11y::GROUP_NAME, - Self::Complexity => Complexity::GROUP_NAME, - Self::Correctness => Correctness::GROUP_NAME, - Self::Nursery => Nursery::GROUP_NAME, - Self::Performance => Performance::GROUP_NAME, - Self::Security => Security::GROUP_NAME, - Self::Style => Style::GROUP_NAME, - Self::Suspicious => Suspicious::GROUP_NAME, - } - } + pub const fn as_str(self) -> &'static str { + match self { + Self::A11y => A11y::GROUP_NAME, + Self::Complexity => Complexity::GROUP_NAME, + Self::Correctness => Correctness::GROUP_NAME, + Self::Nursery => Nursery::GROUP_NAME, + Self::Performance => Performance::GROUP_NAME, + Self::Security => Security::GROUP_NAME, + Self::Style => Style::GROUP_NAME, + Self::Suspicious => Suspicious::GROUP_NAME, + } + } } impl std::str::FromStr for RuleGroup { - type Err = &'static str; - - fn from_str(s: &str) -> Result { - match s { - A11y::GROUP_NAME => Ok(Self::A11y), - Complexity::GROUP_NAME => Ok(Self::Complexity), - Correctness::GROUP_NAME => Ok(Self::Correctness), - Nursery::GROUP_NAME => Ok(Self::Nursery), - Performance::GROUP_NAME => Ok(Self::Performance), - Security::GROUP_NAME => Ok(Self::Security), - Style::GROUP_NAME => Ok(Self::Style), - Suspicious::GROUP_NAME => Ok(Self::Suspicious), - _ => Err("This rule group doesn't exist."), - } - } + type Err = &'static str; + + fn from_str(s:&str) -> Result { + match s { + A11y::GROUP_NAME => Ok(Self::A11y), + Complexity::GROUP_NAME => Ok(Self::Complexity), + Correctness::GROUP_NAME => Ok(Self::Correctness), + Nursery::GROUP_NAME => Ok(Self::Nursery), + Performance::GROUP_NAME => Ok(Self::Performance), + Security::GROUP_NAME => Ok(Self::Security), + Style::GROUP_NAME => Ok(Self::Style), + Suspicious::GROUP_NAME => Ok(Self::Suspicious), + _ => Err("This rule group doesn't exist."), + } + } } #[derive(Clone, Debug, Default, Deserialize, Deserializable, Eq, Merge, PartialEq, Serialize)] #[deserializable(with_validator)] #[cfg_attr(feature = "schema", derive(JsonSchema))] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct Rules { - #[doc = r" It enables the lint rules recommended by Biome. `true` by default."] - #[serde(skip_serializing_if = "Option::is_none")] - pub recommended: Option, - #[doc = r" It enables ALL rules. The rules that belong to `nursery` won't be enabled."] - #[serde(skip_serializing_if = "Option::is_none")] - pub all: Option, - #[deserializable(rename = "a11y")] - #[serde(skip_serializing_if = "Option::is_none")] - pub a11y: Option, - #[deserializable(rename = "complexity")] - #[serde(skip_serializing_if = "Option::is_none")] - pub complexity: Option, - #[deserializable(rename = "correctness")] - #[serde(skip_serializing_if = "Option::is_none")] - pub correctness: Option, - #[deserializable(rename = "nursery")] - #[serde(skip_serializing_if = "Option::is_none")] - pub nursery: Option, - #[deserializable(rename = "performance")] - #[serde(skip_serializing_if = "Option::is_none")] - pub performance: Option, - #[deserializable(rename = "security")] - #[serde(skip_serializing_if = "Option::is_none")] - pub security: Option, - #[deserializable(rename = "style")] - #[serde(skip_serializing_if = "Option::is_none")] - pub style: Option