diff --git a/crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs b/crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs index fb664749979c..b81d75e9e3af 100644 --- a/crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs +++ b/crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs @@ -883,6 +883,16 @@ pub(crate) fn migrate_eslint_any_rule( .get_or_insert(Default::default()); rule.set_level(rule_severity.into()); } + "no-irregular-whitespace" => { + if !options.include_nursery { + return false; + } + let group = rules.nursery.get_or_insert_with(Default::default); + let rule = group + .no_irregular_whitespace + .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + } "no-label-var" => { let group = rules.suspicious.get_or_insert_with(Default::default); let rule = group.no_label_var.get_or_insert(Default::default()); diff --git a/crates/biome_configuration/src/linter/rules.rs b/crates/biome_configuration/src/linter/rules.rs index 9d3bd6fde12a..467627fa8a62 100644 --- a/crates/biome_configuration/src/linter/rules.rs +++ b/crates/biome_configuration/src/linter/rules.rs @@ -2860,6 +2860,9 @@ pub struct Nursery { #[serde(skip_serializing_if = "Option::is_none")] pub no_invalid_position_at_import_rule: Option>, + #[doc = "Disallows the use of irregular whitespace characters."] + #[serde(skip_serializing_if = "Option::is_none")] + pub no_irregular_whitespace: Option>, #[doc = "Enforce that a label element or component has a text label and an associated input."] #[serde(skip_serializing_if = "Option::is_none")] pub no_label_without_control: Option>, @@ -3011,6 +3014,7 @@ impl Nursery { "noImportantInKeyframe", "noInvalidDirectionInLinearGradient", "noInvalidPositionAtImportRule", + "noIrregularWhitespace", "noLabelWithoutControl", "noMisplacedAssertion", "noReactSpecificProps", @@ -3088,19 +3092,19 @@ impl Nursery { RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[12]), RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[13]), RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[14]), - RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[15]), - RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[19]), - RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[22]), - RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[24]), + RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[16]), + RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[20]), + RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[23]), RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[25]), RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[26]), RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[27]), RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[28]), - RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[38]), - RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[41]), + RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[29]), + RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[39]), RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[42]), - RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[46]), - RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[48]), + RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[43]), + RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[47]), + RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[49]), ]; const ALL_RULES_AS_FILTERS: &'static [RuleFilter<'static>] = &[ RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[0]), @@ -3156,6 +3160,7 @@ impl Nursery { RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[50]), RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[51]), RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[52]), + RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[53]), ]; #[doc = r" Retrieves the recommended rules"] pub(crate) fn is_recommended_true(&self) -> bool { @@ -3247,196 +3252,201 @@ impl Nursery { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[14])); } } - if let Some(rule) = self.no_label_without_control.as_ref() { + if let Some(rule) = self.no_irregular_whitespace.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[15])); } } - if let Some(rule) = self.no_misplaced_assertion.as_ref() { + if let Some(rule) = self.no_label_without_control.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[16])); } } - if let Some(rule) = self.no_react_specific_props.as_ref() { + if let Some(rule) = self.no_misplaced_assertion.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[17])); } } - if let Some(rule) = self.no_restricted_imports.as_ref() { + if let Some(rule) = self.no_react_specific_props.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[18])); } } - if let Some(rule) = self.no_shorthand_property_overrides.as_ref() { + if let Some(rule) = self.no_restricted_imports.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[19])); } } - if let Some(rule) = self.no_substr.as_ref() { + if let Some(rule) = self.no_shorthand_property_overrides.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[20])); } } - if let Some(rule) = self.no_undeclared_dependencies.as_ref() { + if let Some(rule) = self.no_substr.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[21])); } } - if let Some(rule) = self.no_unknown_function.as_ref() { + if let Some(rule) = self.no_undeclared_dependencies.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[22])); } } - if let Some(rule) = self.no_unknown_media_feature_name.as_ref() { + if let Some(rule) = self.no_unknown_function.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[23])); } } - if let Some(rule) = self.no_unknown_property.as_ref() { + if let Some(rule) = self.no_unknown_media_feature_name.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[24])); } } - if let Some(rule) = self.no_unknown_pseudo_class_selector.as_ref() { + if let Some(rule) = self.no_unknown_property.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[25])); } } - if let Some(rule) = self.no_unknown_selector_pseudo_element.as_ref() { + if let Some(rule) = self.no_unknown_pseudo_class_selector.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[26])); } } - if let Some(rule) = self.no_unknown_unit.as_ref() { + if let Some(rule) = self.no_unknown_selector_pseudo_element.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[27])); } } - if let Some(rule) = self.no_unmatchable_anb_selector.as_ref() { + if let Some(rule) = self.no_unknown_unit.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[28])); } } - if let Some(rule) = self.no_unused_function_parameters.as_ref() { + if let Some(rule) = self.no_unmatchable_anb_selector.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[29])); } } - if let Some(rule) = self.no_useless_string_concat.as_ref() { + if let Some(rule) = self.no_unused_function_parameters.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[30])); } } - if let Some(rule) = self.no_useless_undefined_initialization.as_ref() { + if let Some(rule) = self.no_useless_string_concat.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[31])); } } - if let Some(rule) = self.no_yoda_expression.as_ref() { + if let Some(rule) = self.no_useless_undefined_initialization.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[32])); } } - if let Some(rule) = self.use_adjacent_overload_signatures.as_ref() { + if let Some(rule) = self.no_yoda_expression.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[33])); } } - if let Some(rule) = self.use_consistent_builtin_instantiation.as_ref() { + if let Some(rule) = self.use_adjacent_overload_signatures.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[34])); } } - if let Some(rule) = self.use_consistent_grid_areas.as_ref() { + if let Some(rule) = self.use_consistent_builtin_instantiation.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[35])); } } - if let Some(rule) = self.use_date_now.as_ref() { + if let Some(rule) = self.use_consistent_grid_areas.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[36])); } } - if let Some(rule) = self.use_default_switch_clause.as_ref() { + if let Some(rule) = self.use_date_now.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[37])); } } - if let Some(rule) = self.use_deprecated_reason.as_ref() { + if let Some(rule) = self.use_default_switch_clause.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[38])); } } - if let Some(rule) = self.use_error_message.as_ref() { + if let Some(rule) = self.use_deprecated_reason.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[39])); } } - if let Some(rule) = self.use_explicit_length_check.as_ref() { + if let Some(rule) = self.use_error_message.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[40])); } } - if let Some(rule) = self.use_focusable_interactive.as_ref() { + if let Some(rule) = self.use_explicit_length_check.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[41])); } } - if let Some(rule) = self.use_generic_font_names.as_ref() { + if let Some(rule) = self.use_focusable_interactive.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[42])); } } - if let Some(rule) = self.use_import_extensions.as_ref() { + if let Some(rule) = self.use_generic_font_names.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[43])); } } - if let Some(rule) = self.use_import_restrictions.as_ref() { + if let Some(rule) = self.use_import_extensions.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[44])); } } - if let Some(rule) = self.use_number_to_fixed_digits_argument.as_ref() { + if let Some(rule) = self.use_import_restrictions.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[45])); } } - if let Some(rule) = self.use_semantic_elements.as_ref() { + if let Some(rule) = self.use_number_to_fixed_digits_argument.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[46])); } } - if let Some(rule) = self.use_sorted_classes.as_ref() { + if let Some(rule) = self.use_semantic_elements.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[47])); } } - if let Some(rule) = self.use_strict_mode.as_ref() { + if let Some(rule) = self.use_sorted_classes.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[48])); } } - if let Some(rule) = self.use_throw_new_error.as_ref() { + if let Some(rule) = self.use_strict_mode.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[49])); } } - if let Some(rule) = self.use_throw_only_error.as_ref() { + if let Some(rule) = self.use_throw_new_error.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[50])); } } - if let Some(rule) = self.use_top_level_regex.as_ref() { + if let Some(rule) = self.use_throw_only_error.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[51])); } } - if let Some(rule) = self.use_valid_autocomplete.as_ref() { + if let Some(rule) = self.use_top_level_regex.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[52])); } } + if let Some(rule) = self.use_valid_autocomplete.as_ref() { + if rule.is_enabled() { + index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[53])); + } + } index_set } pub(crate) fn get_disabled_rules(&self) -> FxHashSet> { @@ -3516,196 +3526,201 @@ impl Nursery { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[14])); } } - if let Some(rule) = self.no_label_without_control.as_ref() { + if let Some(rule) = self.no_irregular_whitespace.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[15])); } } - if let Some(rule) = self.no_misplaced_assertion.as_ref() { + if let Some(rule) = self.no_label_without_control.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[16])); } } - if let Some(rule) = self.no_react_specific_props.as_ref() { + if let Some(rule) = self.no_misplaced_assertion.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[17])); } } - if let Some(rule) = self.no_restricted_imports.as_ref() { + if let Some(rule) = self.no_react_specific_props.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[18])); } } - if let Some(rule) = self.no_shorthand_property_overrides.as_ref() { + if let Some(rule) = self.no_restricted_imports.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[19])); } } - if let Some(rule) = self.no_substr.as_ref() { + if let Some(rule) = self.no_shorthand_property_overrides.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[20])); } } - if let Some(rule) = self.no_undeclared_dependencies.as_ref() { + if let Some(rule) = self.no_substr.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[21])); } } - if let Some(rule) = self.no_unknown_function.as_ref() { + if let Some(rule) = self.no_undeclared_dependencies.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[22])); } } - if let Some(rule) = self.no_unknown_media_feature_name.as_ref() { + if let Some(rule) = self.no_unknown_function.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[23])); } } - if let Some(rule) = self.no_unknown_property.as_ref() { + if let Some(rule) = self.no_unknown_media_feature_name.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[24])); } } - if let Some(rule) = self.no_unknown_pseudo_class_selector.as_ref() { + if let Some(rule) = self.no_unknown_property.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[25])); } } - if let Some(rule) = self.no_unknown_selector_pseudo_element.as_ref() { + if let Some(rule) = self.no_unknown_pseudo_class_selector.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[26])); } } - if let Some(rule) = self.no_unknown_unit.as_ref() { + if let Some(rule) = self.no_unknown_selector_pseudo_element.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[27])); } } - if let Some(rule) = self.no_unmatchable_anb_selector.as_ref() { + if let Some(rule) = self.no_unknown_unit.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[28])); } } - if let Some(rule) = self.no_unused_function_parameters.as_ref() { + if let Some(rule) = self.no_unmatchable_anb_selector.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[29])); } } - if let Some(rule) = self.no_useless_string_concat.as_ref() { + if let Some(rule) = self.no_unused_function_parameters.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[30])); } } - if let Some(rule) = self.no_useless_undefined_initialization.as_ref() { + if let Some(rule) = self.no_useless_string_concat.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[31])); } } - if let Some(rule) = self.no_yoda_expression.as_ref() { + if let Some(rule) = self.no_useless_undefined_initialization.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[32])); } } - if let Some(rule) = self.use_adjacent_overload_signatures.as_ref() { + if let Some(rule) = self.no_yoda_expression.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[33])); } } - if let Some(rule) = self.use_consistent_builtin_instantiation.as_ref() { + if let Some(rule) = self.use_adjacent_overload_signatures.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[34])); } } - if let Some(rule) = self.use_consistent_grid_areas.as_ref() { + if let Some(rule) = self.use_consistent_builtin_instantiation.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[35])); } } - if let Some(rule) = self.use_date_now.as_ref() { + if let Some(rule) = self.use_consistent_grid_areas.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[36])); } } - if let Some(rule) = self.use_default_switch_clause.as_ref() { + if let Some(rule) = self.use_date_now.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[37])); } } - if let Some(rule) = self.use_deprecated_reason.as_ref() { + if let Some(rule) = self.use_default_switch_clause.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[38])); } } - if let Some(rule) = self.use_error_message.as_ref() { + if let Some(rule) = self.use_deprecated_reason.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[39])); } } - if let Some(rule) = self.use_explicit_length_check.as_ref() { + if let Some(rule) = self.use_error_message.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[40])); } } - if let Some(rule) = self.use_focusable_interactive.as_ref() { + if let Some(rule) = self.use_explicit_length_check.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[41])); } } - if let Some(rule) = self.use_generic_font_names.as_ref() { + if let Some(rule) = self.use_focusable_interactive.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[42])); } } - if let Some(rule) = self.use_import_extensions.as_ref() { + if let Some(rule) = self.use_generic_font_names.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[43])); } } - if let Some(rule) = self.use_import_restrictions.as_ref() { + if let Some(rule) = self.use_import_extensions.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[44])); } } - if let Some(rule) = self.use_number_to_fixed_digits_argument.as_ref() { + if let Some(rule) = self.use_import_restrictions.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[45])); } } - if let Some(rule) = self.use_semantic_elements.as_ref() { + if let Some(rule) = self.use_number_to_fixed_digits_argument.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[46])); } } - if let Some(rule) = self.use_sorted_classes.as_ref() { + if let Some(rule) = self.use_semantic_elements.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[47])); } } - if let Some(rule) = self.use_strict_mode.as_ref() { + if let Some(rule) = self.use_sorted_classes.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[48])); } } - if let Some(rule) = self.use_throw_new_error.as_ref() { + if let Some(rule) = self.use_strict_mode.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[49])); } } - if let Some(rule) = self.use_throw_only_error.as_ref() { + if let Some(rule) = self.use_throw_new_error.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[50])); } } - if let Some(rule) = self.use_top_level_regex.as_ref() { + if let Some(rule) = self.use_throw_only_error.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[51])); } } - if let Some(rule) = self.use_valid_autocomplete.as_ref() { + if let Some(rule) = self.use_top_level_regex.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[52])); } } + if let Some(rule) = self.use_valid_autocomplete.as_ref() { + if rule.is_disabled() { + index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[53])); + } + } index_set } #[doc = r" Checks if, given a rule name, matches one of the rules contained in this category"] @@ -3802,6 +3817,10 @@ impl Nursery { .no_invalid_position_at_import_rule .as_ref() .map(|conf| (conf.level(), conf.get_options())), + "noIrregularWhitespace" => self + .no_irregular_whitespace + .as_ref() + .map(|conf| (conf.level(), conf.get_options())), "noLabelWithoutControl" => self .no_label_without_control .as_ref() diff --git a/crates/biome_diagnostics/src/display/frame.rs b/crates/biome_diagnostics/src/display/frame.rs index e5effc6fa1a8..92837307399e 100644 --- a/crates/biome_diagnostics/src/display/frame.rs +++ b/crates/biome_diagnostics/src/display/frame.rs @@ -230,10 +230,8 @@ pub(super) fn print_frame(fmt: &mut fmt::Formatter<'_>, location: Location<'_>) match c { '\t' => fmt.write_str("\t")?, _ => { - if let Some(width) = c.width() { - for _ in 0..width { - fmt.write_str(" ")?; - } + for _ in 0..char_width(c) { + fmt.write_str(" ")?; } } } @@ -338,20 +336,35 @@ pub(super) fn calculate_print_width(mut value: OneIndexed) -> NonZeroUsize { width } +/// Compute the unicode display width of a string, with the width of tab +/// characters set to [TAB_WIDTH] and the width of control characters set to 0 +pub(super) fn text_width(text: &str) -> usize { + text.chars().map(char_width).sum() +} + /// We need to set a value here since we have no way of knowing what the user's /// preferred tab display width is, so this is set to `2` to match how tab /// characters are printed by [print_invisibles] const TAB_WIDTH: usize = 2; -/// Compute the unicode display width of a string, with the width of tab -/// characters set to [TAB_WIDTH] and the width of control characters set to 0 -pub(super) fn text_width(text: &str) -> usize { - text.chars() - .map(|char| match char { - '\t' => TAB_WIDTH, - _ => char.width().unwrap_or(0), - }) - .sum() +/// Some esoteric space characters don't return a width using `char.width()`, so +/// we need to assume a fixed length for them +const ESOTERIC_SPACE_WIDTH: usize = 1; + +/// Return the width of characters, treating whitespace characters in the way +/// we need to properly display it +pub(super) fn char_width(char: char) -> usize { + match char { + '\t' => TAB_WIDTH, + '\u{c}' => ESOTERIC_SPACE_WIDTH, + '\u{b}' => ESOTERIC_SPACE_WIDTH, + '\u{85}' => ESOTERIC_SPACE_WIDTH, + '\u{feff}' => ESOTERIC_SPACE_WIDTH, + '\u{180e}' => ESOTERIC_SPACE_WIDTH, + '\u{200b}' => ESOTERIC_SPACE_WIDTH, + '\u{3000}' => ESOTERIC_SPACE_WIDTH, + _ => char.width().unwrap_or(0), + } } pub(super) struct PrintInvisiblesOptions { @@ -462,14 +475,31 @@ pub(super) fn print_invisibles( fn show_invisible_char(char: char) -> Option<&'static str> { match char { - ' ' => Some("\u{b7}"), // Middle Dot - '\r' => Some("\u{240d}"), // Carriage Return Symbol - '\n' => Some("\u{23ce}"), // Return Symbol - '\t' => Some("\u{2192} "), // Rightwards Arrow - '\0' => Some("\u{2400}"), // Null Symbol - '\x0b' => Some("\u{240b}"), // Vertical Tabulation Symbol - '\x08' => Some("\u{232b}"), // Backspace Symbol - '\x0c' => Some("\u{21a1}"), // Downards Two Headed Arrow + ' ' => Some("\u{b7}"), // Middle Dot + '\r' => Some("\u{240d}"), // Carriage Return Symbol + '\n' => Some("\u{23ce}"), // Return Symbol + '\t' => Some("\u{2192} "), // Rightwards Arrow + '\0' => Some("\u{2400}"), // Null Symbol + '\x0b' => Some("\u{240b}"), // Vertical Tabulation Symbol + '\x08' => Some("\u{232b}"), // Backspace Symbol + '\x0c' => Some("\u{21a1}"), // Downwards Two Headed Arrow + '\u{85}' => Some("\u{2420}"), // Space Symbol + '\u{a0}' => Some("\u{2420}"), // Space Symbol + '\u{1680}' => Some("\u{2420}"), // Space Symbol + '\u{2000}' => Some("\u{2420}"), // Space Symbol + '\u{2001}' => Some("\u{2420}"), // Space Symbol + '\u{2002}' => Some("\u{2420}"), // Space Symbol + '\u{2003}' => Some("\u{2420}"), // Space Symbol + '\u{2004}' => Some("\u{2420}"), // Space Symbol + '\u{2005}' => Some("\u{2420}"), // Space Symbol + '\u{2006}' => Some("\u{2420}"), // Space Symbol + '\u{2007}' => Some("\u{2420}"), // Space Symbol + '\u{2008}' => Some("\u{2420}"), // Space Symbol + '\u{2009}' => Some("\u{2420}"), // Space Symbol + '\u{200a}' => Some("\u{2420}"), // Space Symbol + '\u{202f}' => Some("\u{2420}"), // Space Symbol + '\u{205f}' => Some("\u{2420}"), // Space Symbol + '\u{3000}' => Some("\u{2420}"), // Space Symbol _ => None, } } diff --git a/crates/biome_diagnostics_categories/src/categories.rs b/crates/biome_diagnostics_categories/src/categories.rs index edb01b8e5e79..3f7187d88e2c 100644 --- a/crates/biome_diagnostics_categories/src/categories.rs +++ b/crates/biome_diagnostics_categories/src/categories.rs @@ -130,6 +130,7 @@ define_categories! { "lint/nursery/noImportantInKeyframe": "https://biomejs.dev/linter/rules/no-important-in-keyframe", "lint/nursery/noInvalidDirectionInLinearGradient": "https://biomejs.dev/linter/rules/no-invalid-direction-in-linear-gradient", "lint/nursery/noInvalidPositionAtImportRule": "https://biomejs.dev/linter/rules/no-invalid-position-at-import-rule", + "lint/nursery/noIrregularWhitespace": "https://biomejs.dev/linter/rules/no-irregular-whitespace", "lint/nursery/noLabelWithoutControl": "https://biomejs.dev/linter/rules/no-label-without-control", "lint/nursery/noMisplacedAssertion": "https://biomejs.dev/linter/rules/no-misplaced-assertion", "lint/nursery/noMissingGenericFamilyKeyword": "https://biomejs.dev/linter/rules/no-missing-generic-family-keyword", diff --git a/crates/biome_js_analyze/src/lint/nursery.rs b/crates/biome_js_analyze/src/lint/nursery.rs index ed892ded4458..d46c086a1070 100644 --- a/crates/biome_js_analyze/src/lint/nursery.rs +++ b/crates/biome_js_analyze/src/lint/nursery.rs @@ -8,6 +8,7 @@ pub mod no_duplicate_else_if; pub mod no_dynamic_namespace_import_access; pub mod no_evolving_types; pub mod no_exported_imports; +pub mod no_irregular_whitespace; pub mod no_label_without_control; pub mod no_misplaced_assertion; pub mod no_react_specific_props; @@ -46,6 +47,7 @@ declare_lint_group! { self :: no_dynamic_namespace_import_access :: NoDynamicNamespaceImportAccess , self :: no_evolving_types :: NoEvolvingTypes , self :: no_exported_imports :: NoExportedImports , + self :: no_irregular_whitespace :: NoIrregularWhitespace , self :: no_label_without_control :: NoLabelWithoutControl , self :: no_misplaced_assertion :: NoMisplacedAssertion , self :: no_react_specific_props :: NoReactSpecificProps , diff --git a/crates/biome_js_analyze/src/lint/nursery/no_irregular_whitespace.rs b/crates/biome_js_analyze/src/lint/nursery/no_irregular_whitespace.rs new file mode 100644 index 000000000000..f878e0be1eb3 --- /dev/null +++ b/crates/biome_js_analyze/src/lint/nursery/no_irregular_whitespace.rs @@ -0,0 +1,112 @@ +use biome_analyze::{context::RuleContext, declare_lint_rule, Ast, Rule, RuleDiagnostic}; +use biome_analyze::{RuleSource, RuleSourceKind}; +use biome_console::markup; +use biome_js_syntax::{JsLanguage, JsModule}; +use biome_rowan::{AstNode, Direction, SyntaxTriviaPiece, TextRange}; + +const IRREGULAR_WHITESPACES: &[char; 22] = &[ + '\u{c}', '\u{b}', '\u{85}', '\u{feff}', '\u{a0}', '\u{1680}', '\u{180e}', '\u{2000}', + '\u{2001}', '\u{2002}', '\u{2003}', '\u{2004}', '\u{2005}', '\u{2006}', '\u{2007}', '\u{2008}', + '\u{2009}', '\u{200a}', '\u{200b}', '\u{202f}', '\u{205f}', '\u{3000}', +]; + +declare_lint_rule! { + /// Disallows the use of irregular whitespace characters. + /// + /// Invalid or irregular whitespace causes issues with ECMAScript 5 parsers and also makes code harder to debug. + /// + /// ## Examples + /// + /// ### Invalid + /// + /// ```js,expect_diagnostic + /// const count = 1; + /// ``` + /// + /// ```js,expect_diagnostic + /// const foo = 'thing'; + /// ``` + /// + /// ### Valid + /// + /// ```js + /// const count = 1; + /// ``` + /// + /// ```js + /// const foo = ' '; + /// ``` + /// + pub NoIrregularWhitespace { + version: "next", + name: "noIrregularWhitespace", + language: "js", + recommended: false, + sources: &[RuleSource::Eslint("no-irregular-whitespace")], + source_kind: RuleSourceKind::SameLogic, + } +} + +impl Rule for NoIrregularWhitespace { + type Query = Ast; + type State = TextRange; + type Signals = Vec; + type Options = (); + + fn run(ctx: &RuleContext) -> Self::Signals { + let node = ctx.query(); + get_irregular_whitespace(node) + } + + fn diagnostic(_ctx: &RuleContext, range: &Self::State) -> Option { + Some( + RuleDiagnostic::new( + rule_category!(), + range, + markup! { + "Irregular whitespaces found." + }, + ) + .note(markup! { + "Replace the irregular whitespaces with normal whitespaces or tabs." + }), + ) + } +} + +fn get_irregular_whitespace(node: &JsModule) -> Vec { + let syntax = node.syntax(); + let mut all_whitespaces_trivia: Vec> = vec![]; + let is_whitespace = |trivia: &SyntaxTriviaPiece| { + trivia.is_whitespace() && !trivia.text().replace(' ', "").is_empty() + }; + + for token in syntax.descendants_tokens(Direction::Next) { + let leading_trivia_pieces = token.leading_trivia().pieces(); + let trailing_trivia_pieces = token.trailing_trivia().pieces(); + + for trivia in leading_trivia_pieces { + if is_whitespace(&trivia) { + all_whitespaces_trivia.push(trivia); + } + } + + for trivia in trailing_trivia_pieces { + if is_whitespace(&trivia) { + all_whitespaces_trivia.push(trivia); + } + } + } + + all_whitespaces_trivia + .iter() + .filter_map(|trivia| { + let has_irregular_whitespace = trivia.text().chars().any(|char| { + IRREGULAR_WHITESPACES + .iter() + .any(|irregular_whitespace| &char == irregular_whitespace) + }); + has_irregular_whitespace.then(|| trivia.text_range()) + }) + .collect::>() +} diff --git a/crates/biome_js_analyze/src/options.rs b/crates/biome_js_analyze/src/options.rs index db983215350a..a0fb7ce10af6 100644 --- a/crates/biome_js_analyze/src/options.rs +++ b/crates/biome_js_analyze/src/options.rs @@ -124,6 +124,8 @@ pub type NoInteractiveElementToNoninteractiveRole = < lint :: a11y :: no_interac pub type NoInvalidConstructorSuper = < lint :: correctness :: no_invalid_constructor_super :: NoInvalidConstructorSuper as biome_analyze :: Rule > :: Options ; pub type NoInvalidNewBuiltin = < lint :: correctness :: no_invalid_new_builtin :: NoInvalidNewBuiltin as biome_analyze :: Rule > :: Options ; pub type NoInvalidUseBeforeDeclaration = < lint :: correctness :: no_invalid_use_before_declaration :: NoInvalidUseBeforeDeclaration as biome_analyze :: Rule > :: Options ; +pub type NoIrregularWhitespace = + ::Options; pub type NoLabelVar = ::Options; pub type NoLabelWithoutControl = < lint :: nursery :: no_label_without_control :: NoLabelWithoutControl as biome_analyze :: Rule > :: Options ; pub type NoMisleadingCharacterClass = < lint :: suspicious :: no_misleading_character_class :: NoMisleadingCharacterClass as biome_analyze :: Rule > :: Options ; diff --git a/crates/biome_js_analyze/tests/specs/nursery/noIrregularWhitespace/invalid.js b/crates/biome_js_analyze/tests/specs/nursery/noIrregularWhitespace/invalid.js new file mode 100644 index 000000000000..1447546409bf --- /dev/null +++ b/crates/biome_js_analyze/tests/specs/nursery/noIrregularWhitespace/invalid.js @@ -0,0 +1,20 @@ +/* \u{b} */ const foo = 'thing'; +/* \u{c} */ const foo = 'thing'; +/* \u{feff} */ constfoo='thing'; +/* \u{a0} */ const foo = 'thing'; +/* \u{1680} */ const foo = 'thing'; +/* \u{2000} */ const foo = 'thing'; +/* \u{2001} */ const foo = 'thing'; +/* \u{2002} */ const foo = 'thing'; +/* \u{2003} */ const foo = 'thing'; +/* \u{2004} */ const foo = 'thing'; +/* \u{2005} */ const foo = 'thing'; +/* \u{2006} */ const foo = 'thing'; +/* \u{2007} */ const foo = 'thing'; +/* \u{2008} */ const foo = 'thing'; +/* \u{2009} */ const foo = 'thing'; +/* \u{200a} */ const foo = 'thing'; +/* \u{200b} */ const​foo​=​'thing'; +/* \u{202f} */ const foo = 'thing'; +/* \u{205f} */ const foo = 'thing'; +/* \u{3000} */ const foo = 'thing'; diff --git a/crates/biome_js_analyze/tests/specs/nursery/noIrregularWhitespace/invalid.js.snap b/crates/biome_js_analyze/tests/specs/nursery/noIrregularWhitespace/invalid.js.snap new file mode 100644 index 000000000000..54fc119d74f8 --- /dev/null +++ b/crates/biome_js_analyze/tests/specs/nursery/noIrregularWhitespace/invalid.js.snap @@ -0,0 +1,1037 @@ +--- +source: crates/biome_js_analyze/tests/spec_tests.rs +expression: invalid.js +--- +# Input +```jsx +/* \u{b} */ const foo = 'thing'; +/* \u{c} */ const foo = 'thing'; +/* \u{feff} */ constfoo='thing'; +/* \u{a0} */ const foo = 'thing'; +/* \u{1680} */ const foo = 'thing'; +/* \u{2000} */ const foo = 'thing'; +/* \u{2001} */ const foo = 'thing'; +/* \u{2002} */ const foo = 'thing'; +/* \u{2003} */ const foo = 'thing'; +/* \u{2004} */ const foo = 'thing'; +/* \u{2005} */ const foo = 'thing'; +/* \u{2006} */ const foo = 'thing'; +/* \u{2007} */ const foo = 'thing'; +/* \u{2008} */ const foo = 'thing'; +/* \u{2009} */ const foo = 'thing'; +/* \u{200a} */ const foo = 'thing'; +/* \u{200b} */ const​foo​=​'thing'; +/* \u{202f} */ const foo = 'thing'; +/* \u{205f} */ const foo = 'thing'; +/* \u{3000} */ const foo = 'thing'; + +``` + +# Diagnostics +``` +invalid.js:1:21 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + > 1 │ /* \u{b} */ const␋foo␋=␋'thing'; + │ ^ + 2 │ /* \u{c} */ const↡foo↡=↡'thing'; + 3 │ /* \u{feff} */ const�foo�=�'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:1:25 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + > 1 │ /* \u{b} */ const␋foo␋=␋'thing'; + │ ^ + 2 │ /* \u{c} */ const↡foo↡=↡'thing'; + 3 │ /* \u{feff} */ const�foo�=�'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:1:27 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + > 1 │ /* \u{b} */ const␋foo␋=␋'thing'; + │ ^ + 2 │ /* \u{c} */ const↡foo↡=↡'thing'; + 3 │ /* \u{feff} */ const�foo�=�'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:2:21 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 1 │ /* \u{b} */ const␋foo␋=␋'thing'; + > 2 │ /* \u{c} */ const↡foo↡=↡'thing'; + │ ^ + 3 │ /* \u{feff} */ const�foo�=�'thing'; + 4 │ /* \u{a0} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:2:25 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 1 │ /* \u{b} */ const␋foo␋=␋'thing'; + > 2 │ /* \u{c} */ const↡foo↡=↡'thing'; + │ ^ + 3 │ /* \u{feff} */ const�foo�=�'thing'; + 4 │ /* \u{a0} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:2:27 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 1 │ /* \u{b} */ const␋foo␋=␋'thing'; + > 2 │ /* \u{c} */ const↡foo↡=↡'thing'; + │ ^ + 3 │ /* \u{feff} */ const�foo�=�'thing'; + 4 │ /* \u{a0} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:3:21 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 1 │ /* \u{b} */ const␋foo␋=␋'thing'; + 2 │ /* \u{c} */ const↡foo↡=↡'thing'; + > 3 │ /* \u{feff} */ const�foo�=�'thing'; + │ ^ + 4 │ /* \u{a0} */ const␠foo␠=␠'thing'; + 5 │ /* \u{1680} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:3:25 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 1 │ /* \u{b} */ const␋foo␋=␋'thing'; + 2 │ /* \u{c} */ const↡foo↡=↡'thing'; + > 3 │ /* \u{feff} */ const�foo�=�'thing'; + │ ^ + 4 │ /* \u{a0} */ const␠foo␠=␠'thing'; + 5 │ /* \u{1680} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:3:27 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 1 │ /* \u{b} */ const␋foo␋=␋'thing'; + 2 │ /* \u{c} */ const↡foo↡=↡'thing'; + > 3 │ /* \u{feff} */ const�foo�=�'thing'; + │ ^ + 4 │ /* \u{a0} */ const␠foo␠=␠'thing'; + 5 │ /* \u{1680} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:4:21 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 2 │ /* \u{c} */ const↡foo↡=↡'thing'; + 3 │ /* \u{feff} */ const�foo�=�'thing'; + > 4 │ /* \u{a0} */ const␠foo␠=␠'thing'; + │ ^ + 5 │ /* \u{1680} */ const␠foo␠=␠'thing'; + 6 │ /* \u{2000} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:4:25 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 2 │ /* \u{c} */ const↡foo↡=↡'thing'; + 3 │ /* \u{feff} */ const�foo�=�'thing'; + > 4 │ /* \u{a0} */ const␠foo␠=␠'thing'; + │ ^ + 5 │ /* \u{1680} */ const␠foo␠=␠'thing'; + 6 │ /* \u{2000} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:4:27 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 2 │ /* \u{c} */ const↡foo↡=↡'thing'; + 3 │ /* \u{feff} */ const�foo�=�'thing'; + > 4 │ /* \u{a0} */ const␠foo␠=␠'thing'; + │ ^ + 5 │ /* \u{1680} */ const␠foo␠=␠'thing'; + 6 │ /* \u{2000} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:5:21 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 3 │ /* \u{feff} */ const�foo�=�'thing'; + 4 │ /* \u{a0} */ const␠foo␠=␠'thing'; + > 5 │ /* \u{1680} */ const␠foo␠=␠'thing'; + │ ^ + 6 │ /* \u{2000} */ const␠foo␠=␠'thing'; + 7 │ /* \u{2001} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:5:25 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 3 │ /* \u{feff} */ const�foo�=�'thing'; + 4 │ /* \u{a0} */ const␠foo␠=␠'thing'; + > 5 │ /* \u{1680} */ const␠foo␠=␠'thing'; + │ ^ + 6 │ /* \u{2000} */ const␠foo␠=␠'thing'; + 7 │ /* \u{2001} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:5:27 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 3 │ /* \u{feff} */ const�foo�=�'thing'; + 4 │ /* \u{a0} */ const␠foo␠=␠'thing'; + > 5 │ /* \u{1680} */ const␠foo␠=␠'thing'; + │ ^ + 6 │ /* \u{2000} */ const␠foo␠=␠'thing'; + 7 │ /* \u{2001} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:6:21 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 4 │ /* \u{a0} */ const␠foo␠=␠'thing'; + 5 │ /* \u{1680} */ const␠foo␠=␠'thing'; + > 6 │ /* \u{2000} */ const␠foo␠=␠'thing'; + │ ^ + 7 │ /* \u{2001} */ const␠foo␠=␠'thing'; + 8 │ /* \u{2002} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:6:25 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 4 │ /* \u{a0} */ const␠foo␠=␠'thing'; + 5 │ /* \u{1680} */ const␠foo␠=␠'thing'; + > 6 │ /* \u{2000} */ const␠foo␠=␠'thing'; + │ ^ + 7 │ /* \u{2001} */ const␠foo␠=␠'thing'; + 8 │ /* \u{2002} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:6:27 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 4 │ /* \u{a0} */ const␠foo␠=␠'thing'; + 5 │ /* \u{1680} */ const␠foo␠=␠'thing'; + > 6 │ /* \u{2000} */ const␠foo␠=␠'thing'; + │ ^ + 7 │ /* \u{2001} */ const␠foo␠=␠'thing'; + 8 │ /* \u{2002} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:7:21 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 5 │ /* \u{1680} */ const␠foo␠=␠'thing'; + 6 │ /* \u{2000} */ const␠foo␠=␠'thing'; + > 7 │ /* \u{2001} */ const␠foo␠=␠'thing'; + │ ^ + 8 │ /* \u{2002} */ const␠foo␠=␠'thing'; + 9 │ /* \u{2003} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:7:25 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 5 │ /* \u{1680} */ const␠foo␠=␠'thing'; + 6 │ /* \u{2000} */ const␠foo␠=␠'thing'; + > 7 │ /* \u{2001} */ const␠foo␠=␠'thing'; + │ ^ + 8 │ /* \u{2002} */ const␠foo␠=␠'thing'; + 9 │ /* \u{2003} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:7:27 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 5 │ /* \u{1680} */ const␠foo␠=␠'thing'; + 6 │ /* \u{2000} */ const␠foo␠=␠'thing'; + > 7 │ /* \u{2001} */ const␠foo␠=␠'thing'; + │ ^ + 8 │ /* \u{2002} */ const␠foo␠=␠'thing'; + 9 │ /* \u{2003} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:8:21 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 6 │ /* \u{2000} */ const␠foo␠=␠'thing'; + 7 │ /* \u{2001} */ const␠foo␠=␠'thing'; + > 8 │ /* \u{2002} */ const␠foo␠=␠'thing'; + │ ^ + 9 │ /* \u{2003} */ const␠foo␠=␠'thing'; + 10 │ /* \u{2004} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:8:25 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 6 │ /* \u{2000} */ const␠foo␠=␠'thing'; + 7 │ /* \u{2001} */ const␠foo␠=␠'thing'; + > 8 │ /* \u{2002} */ const␠foo␠=␠'thing'; + │ ^ + 9 │ /* \u{2003} */ const␠foo␠=␠'thing'; + 10 │ /* \u{2004} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:8:27 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 6 │ /* \u{2000} */ const␠foo␠=␠'thing'; + 7 │ /* \u{2001} */ const␠foo␠=␠'thing'; + > 8 │ /* \u{2002} */ const␠foo␠=␠'thing'; + │ ^ + 9 │ /* \u{2003} */ const␠foo␠=␠'thing'; + 10 │ /* \u{2004} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:9:21 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 7 │ /* \u{2001} */ const␠foo␠=␠'thing'; + 8 │ /* \u{2002} */ const␠foo␠=␠'thing'; + > 9 │ /* \u{2003} */ const␠foo␠=␠'thing'; + │ ^ + 10 │ /* \u{2004} */ const␠foo␠=␠'thing'; + 11 │ /* \u{2005} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:9:25 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 7 │ /* \u{2001} */ const␠foo␠=␠'thing'; + 8 │ /* \u{2002} */ const␠foo␠=␠'thing'; + > 9 │ /* \u{2003} */ const␠foo␠=␠'thing'; + │ ^ + 10 │ /* \u{2004} */ const␠foo␠=␠'thing'; + 11 │ /* \u{2005} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:9:27 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 7 │ /* \u{2001} */ const␠foo␠=␠'thing'; + 8 │ /* \u{2002} */ const␠foo␠=␠'thing'; + > 9 │ /* \u{2003} */ const␠foo␠=␠'thing'; + │ ^ + 10 │ /* \u{2004} */ const␠foo␠=␠'thing'; + 11 │ /* \u{2005} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:10:21 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 8 │ /* \u{2002} */ const␠foo␠=␠'thing'; + 9 │ /* \u{2003} */ const␠foo␠=␠'thing'; + > 10 │ /* \u{2004} */ const␠foo␠=␠'thing'; + │ ^ + 11 │ /* \u{2005} */ const␠foo␠=␠'thing'; + 12 │ /* \u{2006} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:10:25 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 8 │ /* \u{2002} */ const␠foo␠=␠'thing'; + 9 │ /* \u{2003} */ const␠foo␠=␠'thing'; + > 10 │ /* \u{2004} */ const␠foo␠=␠'thing'; + │ ^ + 11 │ /* \u{2005} */ const␠foo␠=␠'thing'; + 12 │ /* \u{2006} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:10:27 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 8 │ /* \u{2002} */ const␠foo␠=␠'thing'; + 9 │ /* \u{2003} */ const␠foo␠=␠'thing'; + > 10 │ /* \u{2004} */ const␠foo␠=␠'thing'; + │ ^ + 11 │ /* \u{2005} */ const␠foo␠=␠'thing'; + 12 │ /* \u{2006} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:11:21 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 9 │ /* \u{2003} */ const␠foo␠=␠'thing'; + 10 │ /* \u{2004} */ const␠foo␠=␠'thing'; + > 11 │ /* \u{2005} */ const␠foo␠=␠'thing'; + │ ^ + 12 │ /* \u{2006} */ const␠foo␠=␠'thing'; + 13 │ /* \u{2007} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:11:25 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 9 │ /* \u{2003} */ const␠foo␠=␠'thing'; + 10 │ /* \u{2004} */ const␠foo␠=␠'thing'; + > 11 │ /* \u{2005} */ const␠foo␠=␠'thing'; + │ ^ + 12 │ /* \u{2006} */ const␠foo␠=␠'thing'; + 13 │ /* \u{2007} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:11:27 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 9 │ /* \u{2003} */ const␠foo␠=␠'thing'; + 10 │ /* \u{2004} */ const␠foo␠=␠'thing'; + > 11 │ /* \u{2005} */ const␠foo␠=␠'thing'; + │ ^ + 12 │ /* \u{2006} */ const␠foo␠=␠'thing'; + 13 │ /* \u{2007} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:12:21 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 10 │ /* \u{2004} */ const␠foo␠=␠'thing'; + 11 │ /* \u{2005} */ const␠foo␠=␠'thing'; + > 12 │ /* \u{2006} */ const␠foo␠=␠'thing'; + │ ^ + 13 │ /* \u{2007} */ const␠foo␠=␠'thing'; + 14 │ /* \u{2008} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:12:25 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 10 │ /* \u{2004} */ const␠foo␠=␠'thing'; + 11 │ /* \u{2005} */ const␠foo␠=␠'thing'; + > 12 │ /* \u{2006} */ const␠foo␠=␠'thing'; + │ ^ + 13 │ /* \u{2007} */ const␠foo␠=␠'thing'; + 14 │ /* \u{2008} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:12:27 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 10 │ /* \u{2004} */ const␠foo␠=␠'thing'; + 11 │ /* \u{2005} */ const␠foo␠=␠'thing'; + > 12 │ /* \u{2006} */ const␠foo␠=␠'thing'; + │ ^ + 13 │ /* \u{2007} */ const␠foo␠=␠'thing'; + 14 │ /* \u{2008} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:13:21 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 11 │ /* \u{2005} */ const␠foo␠=␠'thing'; + 12 │ /* \u{2006} */ const␠foo␠=␠'thing'; + > 13 │ /* \u{2007} */ const␠foo␠=␠'thing'; + │ ^ + 14 │ /* \u{2008} */ const␠foo␠=␠'thing'; + 15 │ /* \u{2009} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:13:25 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 11 │ /* \u{2005} */ const␠foo␠=␠'thing'; + 12 │ /* \u{2006} */ const␠foo␠=␠'thing'; + > 13 │ /* \u{2007} */ const␠foo␠=␠'thing'; + │ ^ + 14 │ /* \u{2008} */ const␠foo␠=␠'thing'; + 15 │ /* \u{2009} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:13:27 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 11 │ /* \u{2005} */ const␠foo␠=␠'thing'; + 12 │ /* \u{2006} */ const␠foo␠=␠'thing'; + > 13 │ /* \u{2007} */ const␠foo␠=␠'thing'; + │ ^ + 14 │ /* \u{2008} */ const␠foo␠=␠'thing'; + 15 │ /* \u{2009} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:14:21 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 12 │ /* \u{2006} */ const␠foo␠=␠'thing'; + 13 │ /* \u{2007} */ const␠foo␠=␠'thing'; + > 14 │ /* \u{2008} */ const␠foo␠=␠'thing'; + │ ^ + 15 │ /* \u{2009} */ const␠foo␠=␠'thing'; + 16 │ /* \u{200a} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:14:25 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 12 │ /* \u{2006} */ const␠foo␠=␠'thing'; + 13 │ /* \u{2007} */ const␠foo␠=␠'thing'; + > 14 │ /* \u{2008} */ const␠foo␠=␠'thing'; + │ ^ + 15 │ /* \u{2009} */ const␠foo␠=␠'thing'; + 16 │ /* \u{200a} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:14:27 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 12 │ /* \u{2006} */ const␠foo␠=␠'thing'; + 13 │ /* \u{2007} */ const␠foo␠=␠'thing'; + > 14 │ /* \u{2008} */ const␠foo␠=␠'thing'; + │ ^ + 15 │ /* \u{2009} */ const␠foo␠=␠'thing'; + 16 │ /* \u{200a} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:15:21 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 13 │ /* \u{2007} */ const␠foo␠=␠'thing'; + 14 │ /* \u{2008} */ const␠foo␠=␠'thing'; + > 15 │ /* \u{2009} */ const␠foo␠=␠'thing'; + │ ^ + 16 │ /* \u{200a} */ const␠foo␠=␠'thing'; + 17 │ /* \u{200b} */ const�foo�=�'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:15:25 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 13 │ /* \u{2007} */ const␠foo␠=␠'thing'; + 14 │ /* \u{2008} */ const␠foo␠=␠'thing'; + > 15 │ /* \u{2009} */ const␠foo␠=␠'thing'; + │ ^ + 16 │ /* \u{200a} */ const␠foo␠=␠'thing'; + 17 │ /* \u{200b} */ const�foo�=�'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:15:27 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 13 │ /* \u{2007} */ const␠foo␠=␠'thing'; + 14 │ /* \u{2008} */ const␠foo␠=␠'thing'; + > 15 │ /* \u{2009} */ const␠foo␠=␠'thing'; + │ ^ + 16 │ /* \u{200a} */ const␠foo␠=␠'thing'; + 17 │ /* \u{200b} */ const�foo�=�'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:16:21 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 14 │ /* \u{2008} */ const␠foo␠=␠'thing'; + 15 │ /* \u{2009} */ const␠foo␠=␠'thing'; + > 16 │ /* \u{200a} */ const␠foo␠=␠'thing'; + │ ^ + 17 │ /* \u{200b} */ const�foo�=�'thing'; + 18 │ /* \u{202f} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:16:25 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 14 │ /* \u{2008} */ const␠foo␠=␠'thing'; + 15 │ /* \u{2009} */ const␠foo␠=␠'thing'; + > 16 │ /* \u{200a} */ const␠foo␠=␠'thing'; + │ ^ + 17 │ /* \u{200b} */ const�foo�=�'thing'; + 18 │ /* \u{202f} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:16:27 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 14 │ /* \u{2008} */ const␠foo␠=␠'thing'; + 15 │ /* \u{2009} */ const␠foo␠=␠'thing'; + > 16 │ /* \u{200a} */ const␠foo␠=␠'thing'; + │ ^ + 17 │ /* \u{200b} */ const�foo�=�'thing'; + 18 │ /* \u{202f} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:17:21 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 15 │ /* \u{2009} */ const␠foo␠=␠'thing'; + 16 │ /* \u{200a} */ const␠foo␠=␠'thing'; + > 17 │ /* \u{200b} */ const�foo�=�'thing'; + │ ^ + 18 │ /* \u{202f} */ const␠foo␠=␠'thing'; + 19 │ /* \u{205f} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:17:25 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 15 │ /* \u{2009} */ const␠foo␠=␠'thing'; + 16 │ /* \u{200a} */ const␠foo␠=␠'thing'; + > 17 │ /* \u{200b} */ const�foo�=�'thing'; + │ ^ + 18 │ /* \u{202f} */ const␠foo␠=␠'thing'; + 19 │ /* \u{205f} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:17:27 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 15 │ /* \u{2009} */ const␠foo␠=␠'thing'; + 16 │ /* \u{200a} */ const␠foo␠=␠'thing'; + > 17 │ /* \u{200b} */ const�foo�=�'thing'; + │ ^ + 18 │ /* \u{202f} */ const␠foo␠=␠'thing'; + 19 │ /* \u{205f} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:18:21 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 16 │ /* \u{200a} */ const␠foo␠=␠'thing'; + 17 │ /* \u{200b} */ const�foo�=�'thing'; + > 18 │ /* \u{202f} */ const␠foo␠=␠'thing'; + │ ^ + 19 │ /* \u{205f} */ const␠foo␠=␠'thing'; + 20 │ /* \u{3000} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:18:25 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 16 │ /* \u{200a} */ const␠foo␠=␠'thing'; + 17 │ /* \u{200b} */ const�foo�=�'thing'; + > 18 │ /* \u{202f} */ const␠foo␠=␠'thing'; + │ ^ + 19 │ /* \u{205f} */ const␠foo␠=␠'thing'; + 20 │ /* \u{3000} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:18:27 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 16 │ /* \u{200a} */ const␠foo␠=␠'thing'; + 17 │ /* \u{200b} */ const�foo�=�'thing'; + > 18 │ /* \u{202f} */ const␠foo␠=␠'thing'; + │ ^ + 19 │ /* \u{205f} */ const␠foo␠=␠'thing'; + 20 │ /* \u{3000} */ const␠foo␠=␠'thing'; + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:19:21 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 17 │ /* \u{200b} */ const�foo�=�'thing'; + 18 │ /* \u{202f} */ const␠foo␠=␠'thing'; + > 19 │ /* \u{205f} */ const␠foo␠=␠'thing'; + │ ^ + 20 │ /* \u{3000} */ const␠foo␠=␠'thing'; + 21 │ + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:19:25 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 17 │ /* \u{200b} */ const�foo�=�'thing'; + 18 │ /* \u{202f} */ const␠foo␠=␠'thing'; + > 19 │ /* \u{205f} */ const␠foo␠=␠'thing'; + │ ^ + 20 │ /* \u{3000} */ const␠foo␠=␠'thing'; + 21 │ + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:19:27 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 17 │ /* \u{200b} */ const�foo�=�'thing'; + 18 │ /* \u{202f} */ const␠foo␠=␠'thing'; + > 19 │ /* \u{205f} */ const␠foo␠=␠'thing'; + │ ^ + 20 │ /* \u{3000} */ const␠foo␠=␠'thing'; + 21 │ + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:20:21 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 18 │ /* \u{202f} */ const␠foo␠=␠'thing'; + 19 │ /* \u{205f} */ const␠foo␠=␠'thing'; + > 20 │ /* \u{3000} */ const␠foo␠=␠'thing'; + │ ^ + 21 │ + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:20:25 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 18 │ /* \u{202f} */ const␠foo␠=␠'thing'; + 19 │ /* \u{205f} */ const␠foo␠=␠'thing'; + > 20 │ /* \u{3000} */ const␠foo␠=␠'thing'; + │ ^ + 21 │ + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` + +``` +invalid.js:20:27 lint/nursery/noIrregularWhitespace ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Irregular whitespaces found. + + 18 │ /* \u{202f} */ const␠foo␠=␠'thing'; + 19 │ /* \u{205f} */ const␠foo␠=␠'thing'; + > 20 │ /* \u{3000} */ const␠foo␠=␠'thing'; + │ ^ + 21 │ + + i Replace the irregular whitespaces with normal whitespaces or tabs. + + +``` diff --git a/crates/biome_js_analyze/tests/specs/nursery/noIrregularWhitespace/valid.js b/crates/biome_js_analyze/tests/specs/nursery/noIrregularWhitespace/valid.js new file mode 100644 index 000000000000..316e1c11b9cd --- /dev/null +++ b/crates/biome_js_analyze/tests/specs/nursery/noIrregularWhitespace/valid.js @@ -0,0 +1,46 @@ +const foo = '\\u000B'; +const foo = '\\u000C'; +const foo = '\\u0085'; +const foo = '\\u00A0'; +const foo = '\\u180E'; +const foo = '\\ufeff'; +const foo = '\\u2000'; +const foo = '\\u2001'; +const foo = '\\u2002'; +const foo = '\\u2003'; +const foo = '\\u2004'; +const foo = '\\u2005'; +const foo = '\\u2006'; +const foo = '\\u2007'; +const foo = '\\u2008'; +const foo = '\\u2009'; +const foo = '\\u200A'; +const foo = '\\u200B'; +const foo = '\\u2028'; +const foo = '\\u2029'; +const foo = '\\u202F'; +const foo = '\\u205f'; +const foo = '\\u3000'; +const foo = '\\\u2028'; +const foo = '\\\u2029'; +/* \u{b} */ const foo = ' '; +/* \u{c} */ const foo = ' '; +/* \u{20} */ const foo = ' '; +/* \u{feff} */ const foo = ''; +/* \u{a0} */ const foo = ' '; +/* \u{1680} */ const foo = ' '; +/* \u{2000} */ const foo = ' '; +/* \u{2001} */ const foo = ' '; +/* \u{2002} */ const foo = ' '; +/* \u{2003} */ const foo = ' '; +/* \u{2004} */ const foo = ' '; +/* \u{2005} */ const foo = ' '; +/* \u{2006} */ const foo = ' '; +/* \u{2007} */ const foo = ' '; +/* \u{2008} */ const foo = ' '; +/* \u{2009} */ const foo = ' '; +/* \u{200a} */ const foo = ' '; +/* \u{200b} */ const foo = '​'; +/* \u{202f} */ const foo = ' '; +/* \u{205f} */ const foo = ' '; +/* \u{3000} */ const foo = ' '; diff --git a/crates/biome_js_analyze/tests/specs/nursery/noIrregularWhitespace/valid.js.snap b/crates/biome_js_analyze/tests/specs/nursery/noIrregularWhitespace/valid.js.snap new file mode 100644 index 000000000000..08cb22fda1f3 --- /dev/null +++ b/crates/biome_js_analyze/tests/specs/nursery/noIrregularWhitespace/valid.js.snap @@ -0,0 +1,54 @@ +--- +source: crates/biome_js_analyze/tests/spec_tests.rs +expression: valid.js +--- +# Input +```jsx +const foo = '\\u000B'; +const foo = '\\u000C'; +const foo = '\\u0085'; +const foo = '\\u00A0'; +const foo = '\\u180E'; +const foo = '\\ufeff'; +const foo = '\\u2000'; +const foo = '\\u2001'; +const foo = '\\u2002'; +const foo = '\\u2003'; +const foo = '\\u2004'; +const foo = '\\u2005'; +const foo = '\\u2006'; +const foo = '\\u2007'; +const foo = '\\u2008'; +const foo = '\\u2009'; +const foo = '\\u200A'; +const foo = '\\u200B'; +const foo = '\\u2028'; +const foo = '\\u2029'; +const foo = '\\u202F'; +const foo = '\\u205f'; +const foo = '\\u3000'; +const foo = '\\\u2028'; +const foo = '\\\u2029'; +/* \u{b} */ const foo = ' '; +/* \u{c} */ const foo = ' '; +/* \u{20} */ const foo = ' '; +/* \u{feff} */ const foo = ''; +/* \u{a0} */ const foo = ' '; +/* \u{1680} */ const foo = ' '; +/* \u{2000} */ const foo = ' '; +/* \u{2001} */ const foo = ' '; +/* \u{2002} */ const foo = ' '; +/* \u{2003} */ const foo = ' '; +/* \u{2004} */ const foo = ' '; +/* \u{2005} */ const foo = ' '; +/* \u{2006} */ const foo = ' '; +/* \u{2007} */ const foo = ' '; +/* \u{2008} */ const foo = ' '; +/* \u{2009} */ const foo = ' '; +/* \u{200a} */ const foo = ' '; +/* \u{200b} */ const foo = '​'; +/* \u{202f} */ const foo = ' '; +/* \u{205f} */ const foo = ' '; +/* \u{3000} */ const foo = ' '; + +``` diff --git a/crates/biome_json_parser/tests/json_test_suite/err/array_spaces_vertical_tab_formfeed.json.snap b/crates/biome_json_parser/tests/json_test_suite/err/array_spaces_vertical_tab_formfeed.json.snap index 031e0d1b0fae..1be3a5734148 100644 --- a/crates/biome_json_parser/tests/json_test_suite/err/array_spaces_vertical_tab_formfeed.json.snap +++ b/crates/biome_json_parser/tests/json_test_suite/err/array_spaces_vertical_tab_formfeed.json.snap @@ -70,7 +70,7 @@ array_spaces_vertical_tab_formfeed.json:1:3 parse ━━━━━━━━━━ × Control character '\u000b' is not allowed in string literals. > 1 │ ["␋a"\f] - │ + │ ^ i Use the escape sequence '\u000b' instead. @@ -79,14 +79,14 @@ array_spaces_vertical_tab_formfeed.json:1:6 parse ━━━━━━━━━━ × unexpected character `\` > 1 │ ["␋a"\f] - │ ^ + │ ^ array_spaces_vertical_tab_formfeed.json:1:7 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ × expected `,` but instead found `f` > 1 │ ["␋a"\f] - │ ^ + │ ^ i Remove f diff --git a/crates/biome_json_parser/tests/json_test_suite/err/structure_UTF8_BOM_no_data.json.snap b/crates/biome_json_parser/tests/json_test_suite/err/structure_UTF8_BOM_no_data.json.snap index 42afc8cd01ce..7b93467e5e2f 100644 --- a/crates/biome_json_parser/tests/json_test_suite/err/structure_UTF8_BOM_no_data.json.snap +++ b/crates/biome_json_parser/tests/json_test_suite/err/structure_UTF8_BOM_no_data.json.snap @@ -2,7 +2,6 @@ source: crates/biome_json_parser/tests/spec_test.rs expression: snapshot --- - ## Input ```json @@ -38,13 +37,11 @@ structure_UTF8_BOM_no_data.json:1:2 parse ━━━━━━━━━━━━ × Expected an array, an object, or a literal but instead found the end of the file. > 1 │ � - │ + │ i Expected an array, an object, or a literal here. > 1 │ � - │ + │ ``` - - diff --git a/crates/biome_json_parser/tests/json_test_suite/err/structure_whitespace_formfeed.json.snap b/crates/biome_json_parser/tests/json_test_suite/err/structure_whitespace_formfeed.json.snap index ca558552f3eb..60740002d8a2 100644 --- a/crates/biome_json_parser/tests/json_test_suite/err/structure_whitespace_formfeed.json.snap +++ b/crates/biome_json_parser/tests/json_test_suite/err/structure_whitespace_formfeed.json.snap @@ -2,7 +2,6 @@ source: crates/biome_json_parser/tests/spec_test.rs expression: snapshot --- - ## Input ```json @@ -45,10 +44,8 @@ structure_whitespace_formfeed.json:1:2 parse ━━━━━━━━━━━ × The JSON standard only allows tabs, whitespace, carriage return and line feed whitespace. > 1 │ [↡] - │ + │ ^ i Use a regular whitespace character instead. ``` - - diff --git a/packages/@biomejs/backend-jsonrpc/src/workspace.ts b/packages/@biomejs/backend-jsonrpc/src/workspace.ts index f8b794a9e244..64eeca7595e2 100644 --- a/packages/@biomejs/backend-jsonrpc/src/workspace.ts +++ b/packages/@biomejs/backend-jsonrpc/src/workspace.ts @@ -1109,6 +1109,10 @@ export interface Nursery { * Disallow the use of @import at-rules in invalid positions. */ noInvalidPositionAtImportRule?: RuleConfiguration_for_Null; + /** + * Disallows the use of irregular whitespace characters. + */ + noIrregularWhitespace?: RuleConfiguration_for_Null; /** * Enforce that a label element or component has a text label and an associated input. */ @@ -2512,6 +2516,7 @@ export type Category = | "lint/nursery/noImportantInKeyframe" | "lint/nursery/noInvalidDirectionInLinearGradient" | "lint/nursery/noInvalidPositionAtImportRule" + | "lint/nursery/noIrregularWhitespace" | "lint/nursery/noLabelWithoutControl" | "lint/nursery/noMisplacedAssertion" | "lint/nursery/noMissingGenericFamilyKeyword" diff --git a/packages/@biomejs/biome/configuration_schema.json b/packages/@biomejs/biome/configuration_schema.json index ffd32f75635b..de9a7c44bb4e 100644 --- a/packages/@biomejs/biome/configuration_schema.json +++ b/packages/@biomejs/biome/configuration_schema.json @@ -1863,6 +1863,13 @@ { "type": "null" } ] }, + "noIrregularWhitespace": { + "description": "Disallows the use of irregular whitespace characters.", + "anyOf": [ + { "$ref": "#/definitions/RuleConfiguration" }, + { "type": "null" } + ] + }, "noLabelWithoutControl": { "description": "Enforce that a label element or component has a text label and an associated input.", "anyOf": [