diff --git a/crates/oxc_linter/src/rules.rs b/crates/oxc_linter/src/rules.rs index d82bb40cb6908..a58d924ad6694 100644 --- a/crates/oxc_linter/src/rules.rs +++ b/crates/oxc_linter/src/rules.rs @@ -7,21 +7,21 @@ /// mod import { + // pub mod no_deprecated; + // pub mod no_unused_modules; pub mod default; pub mod export; + pub mod max_dependencies; pub mod named; pub mod namespace; pub mod no_amd; pub mod no_cycle; pub mod no_default_export; - // pub mod no_deprecated; - pub mod max_dependencies; pub mod no_duplicates; pub mod no_dynamic_require; pub mod no_named_as_default; pub mod no_named_as_default_member; pub mod no_self_import; - // pub mod no_unused_modules; pub mod no_webpack_loader_syntax; } @@ -127,6 +127,7 @@ mod eslint { pub mod require_await; pub mod require_yield; pub mod sort_imports; + pub mod sort_keys; pub mod sort_vars; pub mod symbol_description; pub mod unicode_bom; @@ -481,6 +482,8 @@ mod node { } oxc_macros::declare_all_lint_rules! { + // import::no_deprecated, + // import::no_unused_modules, eslint::array_callback_return, eslint::constructor_super, eslint::default_case, @@ -582,47 +585,26 @@ oxc_macros::declare_all_lint_rules! { eslint::require_await, eslint::require_yield, eslint::sort_imports, + eslint::sort_keys, eslint::sort_vars, eslint::symbol_description, eslint::unicode_bom, eslint::use_isnan, eslint::valid_typeof, - typescript::adjacent_overload_signatures, - typescript::array_type, - typescript::ban_ts_comment, - typescript::ban_tslint_comment, - typescript::prefer_enum_initializers, - typescript::ban_types, - typescript::consistent_type_definitions, - typescript::consistent_type_imports, - typescript::consistent_indexed_object_style, - typescript::no_duplicate_enum_values, - typescript::no_empty_interface, - typescript::no_explicit_any, - typescript::no_extra_non_null_assertion, - typescript::no_import_type_side_effects, - typescript::no_misused_new, - typescript::no_namespace, - typescript::no_non_null_asserted_optional_chain, - typescript::no_this_alias, - typescript::no_unnecessary_type_constraint, - typescript::no_unsafe_declaration_merging, - typescript::no_useless_empty_export, - typescript::no_var_requires, - typescript::no_wrapper_object_types, - typescript::prefer_as_const, - typescript::prefer_for_of, - typescript::prefer_function_type, - typescript::prefer_namespace_keyword, - typescript::prefer_ts_expect_error, - typescript::triple_slash_reference, - typescript::prefer_literal_enum_member, - typescript::explicit_function_return_type, - typescript::no_non_null_assertion, - typescript::no_non_null_asserted_nullish_coalescing, - typescript::no_confusing_non_null_assertion, - typescript::no_dynamic_delete, - typescript::no_extraneous_class, + import::default, + import::export, + import::max_dependencies, + import::named, + import::namespace, + import::no_amd, + import::no_cycle, + import::no_default_export, + import::no_duplicates, + import::no_dynamic_require, + import::no_named_as_default, + import::no_named_as_default_member, + import::no_self_import, + import::no_webpack_loader_syntax, jest::consistent_test_it, jest::expect_expect, jest::max_expects, @@ -671,6 +653,171 @@ oxc_macros::declare_all_lint_rules! { jest::valid_describe_callback, jest::valid_expect, jest::valid_title, + jsdoc::check_access, + jsdoc::check_property_names, + jsdoc::check_tag_names, + jsdoc::empty_tags, + jsdoc::implements_on_classes, + jsdoc::no_defaults, + jsdoc::require_param, + jsdoc::require_param_description, + jsdoc::require_param_name, + jsdoc::require_param_type, + jsdoc::require_property, + jsdoc::require_property_description, + jsdoc::require_property_name, + jsdoc::require_property_type, + jsdoc::require_returns, + jsdoc::require_returns_description, + jsdoc::require_returns_type, + jsdoc::require_yields, + jsx_a11y::alt_text, + jsx_a11y::anchor_has_content, + jsx_a11y::anchor_is_valid, + jsx_a11y::aria_activedescendant_has_tabindex, + jsx_a11y::aria_props, + jsx_a11y::aria_role, + jsx_a11y::aria_unsupported_elements, + jsx_a11y::autocomplete_valid, + jsx_a11y::click_events_have_key_events, + jsx_a11y::heading_has_content, + jsx_a11y::html_has_lang, + jsx_a11y::iframe_has_title, + jsx_a11y::img_redundant_alt, + jsx_a11y::label_has_associated_control, + jsx_a11y::lang, + jsx_a11y::media_has_caption, + jsx_a11y::mouse_events_have_key_events, + jsx_a11y::no_access_key, + jsx_a11y::no_aria_hidden_on_focusable, + jsx_a11y::no_autofocus, + jsx_a11y::no_distracting_elements, + jsx_a11y::no_redundant_roles, + jsx_a11y::prefer_tag_over_role, + jsx_a11y::role_has_required_aria_props, + jsx_a11y::role_supports_aria_props, + jsx_a11y::scope, + jsx_a11y::tabindex_no_positive, + nextjs::google_font_display, + nextjs::google_font_preconnect, + nextjs::inline_script_id, + nextjs::next_script_for_ga, + nextjs::no_assign_module_variable, + nextjs::no_async_client_component, + nextjs::no_before_interactive_script_outside_document, + nextjs::no_css_tags, + nextjs::no_document_import_in_page, + nextjs::no_duplicate_head, + nextjs::no_head_element, + nextjs::no_head_import_in_document, + nextjs::no_img_element, + nextjs::no_page_custom_font, + nextjs::no_script_component_in_head, + nextjs::no_styled_jsx_in_document, + nextjs::no_sync_scripts, + nextjs::no_title_in_document_head, + nextjs::no_typos, + nextjs::no_unwanted_polyfillio, + node::no_exports_assign, + oxc::approx_constant, + oxc::bad_array_method_on_arguments, + oxc::bad_bitwise_operator, + oxc::bad_char_at_comparison, + oxc::bad_comparison_sequence, + oxc::bad_min_max_func, + oxc::bad_object_literal_comparison, + oxc::bad_replace_all_arg, + oxc::const_comparisons, + oxc::double_comparisons, + oxc::erasing_op, + oxc::misrefactored_assign_op, + oxc::missing_throw, + oxc::no_accumulating_spread, + oxc::no_async_await, + oxc::no_async_endpoint_handlers, + oxc::no_barrel_file, + oxc::no_const_enum, + oxc::no_optional_chaining, + oxc::no_rest_spread_properties, + oxc::number_arg_out_of_range, + oxc::only_used_in_recursion, + oxc::uninvoked_array_callback, + promise::avoid_new, + promise::catch_or_return, + promise::no_new_statics, + promise::no_return_in_finally, + promise::param_names, + promise::prefer_await_to_then, + promise::spec_only, + promise::valid_params, + react::button_has_type, + react::checked_requires_onchange_or_readonly, + react::jsx_boolean_value, + react::jsx_curly_brace_presence, + react::jsx_key, + react::jsx_no_comment_textnodes, + react::jsx_no_duplicate_props, + react::jsx_no_target_blank, + react::jsx_no_undef, + react::jsx_no_useless_fragment, + react::jsx_props_no_spread_multi, + react::no_children_prop, + react::no_danger, + react::no_direct_mutation_state, + react::no_find_dom_node, + react::no_is_mounted, + react::no_render_return_value, + react::no_set_state, + react::no_string_refs, + react::no_unescaped_entities, + react::no_unknown_property, + react::prefer_es6_class, + react::react_in_jsx_scope, + react::require_render_return, + react::rules_of_hooks, + react::self_closing_comp, + react::void_dom_elements_no_children, + react_perf::jsx_no_jsx_as_prop, + react_perf::jsx_no_new_array_as_prop, + react_perf::jsx_no_new_function_as_prop, + react_perf::jsx_no_new_object_as_prop, + tree_shaking::no_side_effects_in_initialization, + typescript::adjacent_overload_signatures, + typescript::array_type, + typescript::ban_ts_comment, + typescript::ban_tslint_comment, + typescript::ban_types, + typescript::consistent_indexed_object_style, + typescript::consistent_type_definitions, + typescript::consistent_type_imports, + typescript::explicit_function_return_type, + typescript::no_confusing_non_null_assertion, + typescript::no_duplicate_enum_values, + typescript::no_dynamic_delete, + typescript::no_empty_interface, + typescript::no_explicit_any, + typescript::no_extra_non_null_assertion, + typescript::no_extraneous_class, + typescript::no_import_type_side_effects, + typescript::no_misused_new, + typescript::no_namespace, + typescript::no_non_null_asserted_nullish_coalescing, + typescript::no_non_null_asserted_optional_chain, + typescript::no_non_null_assertion, + typescript::no_this_alias, + typescript::no_unnecessary_type_constraint, + typescript::no_unsafe_declaration_merging, + typescript::no_useless_empty_export, + typescript::no_var_requires, + typescript::no_wrapper_object_types, + typescript::prefer_as_const, + typescript::prefer_enum_initializers, + typescript::prefer_for_of, + typescript::prefer_function_type, + typescript::prefer_literal_enum_member, + typescript::prefer_namespace_keyword, + typescript::prefer_ts_expect_error, + typescript::triple_slash_reference, unicorn::catch_error_name, unicorn::consistent_function_scoping, unicorn::empty_brace_spaces, @@ -720,13 +867,12 @@ oxc_macros::declare_all_lint_rules! { unicorn::number_literal_case, unicorn::numeric_separators_style, unicorn::prefer_add_event_listener, - unicorn::prefer_array_flat_map, unicorn::prefer_array_flat, + unicorn::prefer_array_flat_map, unicorn::prefer_array_some, unicorn::prefer_blob_reading_methods, unicorn::prefer_code_point, unicorn::prefer_date_now, - unicorn::prefer_node_protocol, unicorn::prefer_dom_node_append, unicorn::prefer_dom_node_dataset, unicorn::prefer_dom_node_remove, @@ -738,6 +884,7 @@ oxc_macros::declare_all_lint_rules! { unicorn::prefer_modern_dom_apis, unicorn::prefer_modern_math_apis, unicorn::prefer_native_coercion_functions, + unicorn::prefer_node_protocol, unicorn::prefer_number_properties, unicorn::prefer_optional_catch_binding, unicorn::prefer_prototype_methods, @@ -757,156 +904,11 @@ oxc_macros::declare_all_lint_rules! { unicorn::switch_case_braces, unicorn::text_encoding_identifier_case, unicorn::throw_new_error, - react::button_has_type, - react::checked_requires_onchange_or_readonly, - react::jsx_no_target_blank, - react::jsx_curly_brace_presence, - react::jsx_boolean_value, - react::jsx_key, - react::jsx_no_comment_textnodes, - react::jsx_no_duplicate_props, - react::jsx_no_useless_fragment, - react::jsx_props_no_spread_multi, - react::jsx_no_undef, - react::react_in_jsx_scope, - react::no_children_prop, - react::no_danger, - react::no_direct_mutation_state, - react::no_find_dom_node, - react::no_render_return_value, - react::no_set_state, - react::no_string_refs, - react::no_unescaped_entities, - react::no_is_mounted, - react::no_unknown_property, - react::prefer_es6_class, - react::require_render_return, - react::rules_of_hooks, - react::self_closing_comp, - react::void_dom_elements_no_children, - react_perf::jsx_no_jsx_as_prop, - react_perf::jsx_no_new_array_as_prop, - react_perf::jsx_no_new_function_as_prop, - react_perf::jsx_no_new_object_as_prop, - import::default, - import::export, - import::max_dependencies, - import::named, - import::namespace, - import::no_amd, - import::no_cycle, - // import::no_deprecated, - import::no_named_as_default, - import::no_named_as_default_member, - import::no_self_import, - // import::no_unused_modules, - import::no_dynamic_require, - import::no_duplicates, - import::no_default_export, - import::no_webpack_loader_syntax, - jsx_a11y::alt_text, - jsx_a11y::anchor_has_content, - jsx_a11y::anchor_is_valid, - jsx_a11y::aria_activedescendant_has_tabindex, - jsx_a11y::aria_props, - jsx_a11y::aria_unsupported_elements, - jsx_a11y::click_events_have_key_events, - jsx_a11y::heading_has_content, - jsx_a11y::html_has_lang, - jsx_a11y::lang, - jsx_a11y::iframe_has_title, - jsx_a11y::img_redundant_alt, - jsx_a11y::label_has_associated_control, - jsx_a11y::media_has_caption, - jsx_a11y::mouse_events_have_key_events, - jsx_a11y::no_access_key, - jsx_a11y::no_aria_hidden_on_focusable, - jsx_a11y::no_autofocus, - jsx_a11y::no_redundant_roles, - jsx_a11y::prefer_tag_over_role, - jsx_a11y::role_has_required_aria_props, - jsx_a11y::scope, - jsx_a11y::tabindex_no_positive, - jsx_a11y::aria_role, - jsx_a11y::no_distracting_elements, - jsx_a11y::role_supports_aria_props, - jsx_a11y::autocomplete_valid, - oxc::approx_constant, - oxc::bad_array_method_on_arguments, - oxc::bad_bitwise_operator, - oxc::bad_char_at_comparison, - oxc::bad_comparison_sequence, - oxc::bad_min_max_func, - oxc::bad_object_literal_comparison, - oxc::bad_replace_all_arg, - oxc::const_comparisons, - oxc::double_comparisons, - oxc::erasing_op, - oxc::no_optional_chaining, - oxc::no_rest_spread_properties, - oxc::misrefactored_assign_op, - oxc::missing_throw, - oxc::no_accumulating_spread, - oxc::no_barrel_file, - oxc::no_const_enum, - oxc::number_arg_out_of_range, - oxc::only_used_in_recursion, - oxc::no_async_await, - oxc::no_async_endpoint_handlers, - oxc::uninvoked_array_callback, - nextjs::google_font_display, - nextjs::google_font_preconnect, - nextjs::inline_script_id, - nextjs::next_script_for_ga, - nextjs::no_assign_module_variable, - nextjs::no_async_client_component, - nextjs::no_css_tags, - nextjs::no_head_element, - nextjs::no_head_import_in_document, - nextjs::no_duplicate_head, - nextjs::no_img_element, - nextjs::no_script_component_in_head, - nextjs::no_sync_scripts, - nextjs::no_title_in_document_head, - nextjs::no_typos, - nextjs::no_document_import_in_page, - nextjs::no_unwanted_polyfillio, - nextjs::no_before_interactive_script_outside_document, - nextjs::no_page_custom_font, - nextjs::no_styled_jsx_in_document, - jsdoc::check_access, - jsdoc::check_property_names, - jsdoc::check_tag_names, - jsdoc::empty_tags, - jsdoc::implements_on_classes, - jsdoc::no_defaults, - jsdoc::require_param, - jsdoc::require_param_description, - jsdoc::require_param_name, - jsdoc::require_param_type, - jsdoc::require_property, - jsdoc::require_property_type, - jsdoc::require_property_name, - jsdoc::require_property_description, - jsdoc::require_returns, - jsdoc::require_returns_description, - jsdoc::require_returns_type, - jsdoc::require_yields, - tree_shaking::no_side_effects_in_initialization, - promise::avoid_new, - promise::no_new_statics, - promise::param_names, - promise::valid_params, - promise::no_return_in_finally, - promise::prefer_await_to_then, - promise::catch_or_return, - promise::spec_only, + vitest::no_conditional_tests, vitest::no_import_node_test, vitest::prefer_each, vitest::prefer_to_be_falsy, vitest::prefer_to_be_object, vitest::prefer_to_be_truthy, - vitest::no_conditional_tests, vitest::require_local_test_context_for_concurrent_snapshots, - node::no_exports_assign, } diff --git a/crates/oxc_linter/src/rules/eslint/sort_keys.rs b/crates/oxc_linter/src/rules/eslint/sort_keys.rs new file mode 100644 index 0000000000000..429600d86e5d5 --- /dev/null +++ b/crates/oxc_linter/src/rules/eslint/sort_keys.rs @@ -0,0 +1,1088 @@ +#![allow(clippy::print_stdout, clippy::disallowed_methods)] +use crate::{context::LintContext, rule::Rule, AstNode}; +use itertools::all; +use oxc_ast::ast::ObjectPropertyKind; +use oxc_ast::syntax_directed_operations::PropName; +use oxc_ast::AstKind; +use oxc_diagnostics::OxcDiagnostic; +use oxc_macros::declare_oxc_lint; +use oxc_span::{GetSpan, Span}; +use std::cmp::Ordering; +use std::str::Chars; + +#[derive(Debug, Default, Clone)] +pub struct SortKeys(Box); + +#[derive(Debug, Default, Clone, Eq, PartialEq)] +pub enum SortOrder { + Desc, + #[default] + Asc, +} + +#[derive(Debug, Clone)] +pub struct SortKeysOptions { + sort_order: SortOrder, + case_sensitive: bool, + natural: bool, + min_keys: usize, + allow_line_separated_groups: bool, +} + +impl Default for SortKeysOptions { + fn default() -> Self { + // we follow the eslint defaults + Self { + sort_order: SortOrder::Asc, + case_sensitive: true, + natural: false, + min_keys: 2, + allow_line_separated_groups: false, + } + } +} + +impl std::ops::Deref for SortKeys { + type Target = SortKeysOptions; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +fn sort_properties_diagnostic(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::warn("Object keys should be sorted").with_label(span0) +} + +declare_oxc_lint!( + /// ### What it does + /// + /// When declaring multiple properties, sorting property names alphabetically makes it easier + /// to find and/or diff necessary properties at a later time. + /// + /// ### Why is this bad? + /// + /// Unsorted property keys can make the code harder to read and maintain. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```js + /// let myObj = { + /// c: 1, + /// a: 2, + /// }; + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```js + /// let myObj = { + /// a: 2, + /// c: 1, + /// }; + /// ``` + SortKeys, + pedantic, + pending +); + +impl Rule for SortKeys { + fn from_configuration(value: serde_json::Value) -> Self { + let Some(config_array) = value.as_array() else { + return Self::default(); + }; + + let sort_order = if config_array.is_empty() { + SortOrder::Asc + } else { + config_array[0].as_str().map_or(SortOrder::Asc, |s| match s { + "desc" => SortOrder::Desc, + _ => SortOrder::Asc, + }) + }; + + let config = if config_array.len() > 1 { + config_array[1].as_object().unwrap() + } else { + &serde_json::Map::new() + }; + + let case_sensitive = + config.get("caseSensitive").and_then(serde_json::Value::as_bool).unwrap_or(true); + let natural = config.get("natural").and_then(serde_json::Value::as_bool).unwrap_or(false); + let min_keys = config + .get("minKeys") + .and_then(serde_json::Value::as_u64) + .map_or(2, |n| n.try_into().unwrap_or(2)); + let allow_line_separated_groups = config + .get("allowLineSeparatedGroups") + .and_then(serde_json::Value::as_bool) + .unwrap_or(false); + + Self(Box::new(SortKeysOptions { + sort_order, + case_sensitive, + natural, + min_keys, + allow_line_separated_groups, + })) + } + fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { + if let AstKind::ObjectExpression(dec) = node.kind() { + if dec.properties.len() < self.min_keys { + return; + } + + let mut property_groups: Vec> = vec![vec![]]; + + let source_text = ctx.semantic().source_text(); + + for (i, prop) in dec.properties.iter().enumerate() { + if let ObjectPropertyKind::SpreadProperty(_) = prop { + property_groups.push(vec!["".into()]); + property_groups.push(vec![]); + continue; + } + let key = match prop.prop_name() { + Some((name, _)) => name, + // FIXME: prop_name is currently unset for computed properties, short hand properties, and function declarations. + None => extract_property_key(prop.span().source_text(source_text)), + }; + + if i != dec.properties.len() - 1 && self.allow_line_separated_groups { + let text_between = extract_text_between_spans( + source_text, + prop.span(), + dec.properties[i + 1].span(), + ); + if text_between.contains("\n\n") { + property_groups.last_mut().unwrap().push(key.into()); + property_groups.push(vec!["".into()]); + property_groups.push(vec![]); + continue; + } + } + property_groups.last_mut().unwrap().push(key.into()); + } + + if !self.case_sensitive { + for group in &mut property_groups { + *group = group.iter().map(|s| s.to_lowercase()).collect::>(); + } + } + + let mut sorted_property_groups = property_groups.clone(); + for group in &mut sorted_property_groups { + if self.natural { + natural_sort(group); + } else { + alphanumeric_sort(group); + } + + if self.sort_order == SortOrder::Desc { + group.reverse(); + } + } + + let is_sorted = + all(property_groups.iter().zip(&sorted_property_groups), |(a, b)| a == b); + + if !is_sorted { + ctx.diagnostic(sort_properties_diagnostic(node.span())); + } + } + } +} + +fn alphanumeric_cmp(a: &str, b: &str) -> Ordering { + /* regex key special case */ + if a.starts_with('/') && a.ends_with('/') { + if b.starts_with('/') && b.ends_with('/') { + return a.cmp(b); + } + return Ordering::Greater; + } + + if b.starts_with('/') && b.ends_with('/') { + return Ordering::Less; + } + + /* empty keys special case */ + if a.is_empty() && b.starts_with('[') || b.is_empty() && a.starts_with('[') { + return Ordering::Equal; + } + + let len = a.len().min(b.len()); + + for (a_char, b_char) in a.chars().take(len).zip(b.chars().take(len)) { + if a_char == b_char { + continue; + } + /* JS sorting apparently places _ after uppercase alphanumerics and before lowercase ones */ + if a_char.is_uppercase() && b_char == '_' { + return Ordering::Less; + } + + if a_char == '_' && b_char.is_uppercase() { + return Ordering::Greater; + } + + /* computed properties should come before alpha numeric chars */ + if a_char == '[' && b_char.is_alphanumeric() { + return Ordering::Less; + } + + if a_char.is_alphanumeric() && b_char == '[' { + return Ordering::Greater; + } + + if a_char.is_alphanumeric() && !b_char.is_alphanumeric() { + return Ordering::Greater; + } + + if !a_char.is_alphanumeric() && b_char.is_alphanumeric() { + return Ordering::Less; + } + + return a_char.cmp(&b_char); + } + + a.cmp(b) +} + +fn alphanumeric_sort(arr: &mut [String]) { + arr.sort_by(|a, b| alphanumeric_cmp(a, b)); +} + +fn natural_sort(arr: &mut [String]) { + arr.sort_by(|a, b| { + let mut a_chars = a.chars(); + let mut b_chars = b.chars(); + + loop { + match (a_chars.next(), b_chars.next()) { + (Some(a_char), Some(b_char)) if a_char == b_char => continue, + (Some(a_char), Some(b_char)) if a_char.is_numeric() && b_char.is_numeric() => { + let n1 = take_numeric(&mut a_chars, a_char); + let n2 = take_numeric(&mut b_chars, b_char); + match n1.cmp(&n2) { + Ordering::Equal => continue, + ord => return ord, + } + } + (Some(a_char), Some(b_char)) + if a_char.is_alphanumeric() && !b_char.is_alphanumeric() => + { + return Ordering::Greater + } + (Some(a_char), Some(b_char)) + if !a_char.is_alphanumeric() && b_char.is_alphanumeric() => + { + return Ordering::Less + } + (Some(a_char), Some(b_char)) if a_char == '[' && b_char.is_alphanumeric() => { + return Ordering::Greater + } + (Some(a_char), Some(b_char)) if a_char.is_alphanumeric() && b_char == '[' => { + return Ordering::Less + } + (Some(a_char), Some(b_char)) => return a_char.cmp(&b_char), + (None, None) => return Ordering::Equal, + (Some(_), None) => return Ordering::Greater, + (None, Some(_)) => return Ordering::Less, + } + } + }); +} + +fn take_numeric(iter: &mut Chars, first: char) -> u32 { + let mut sum = first.to_digit(10).unwrap(); + for c in iter.by_ref() { + if let Some(digit) = c.to_digit(10) { + sum = sum * 10 + digit; + } else { + break; + } + } + sum +} + +fn extract_text_between_spans(source_text: &str, current_span: Span, next_span: Span) -> &str { + let cur_span_end = current_span.end as usize; + let next_span_start = next_span.start as usize; + &source_text[cur_span_end..next_span_start] +} + +fn extract_property_key(prop_text: &str) -> &str { + let trimmed = prop_text.trim(); + let before_colon = trimmed.split(':').next().unwrap_or(trimmed); + let without_quotes = before_colon.split('"').next().unwrap_or(before_colon); + without_quotes.split('(').next().unwrap_or(before_colon) +} + +#[test] +fn test() { + use crate::tester::Tester; + + let pass = vec![ + ("var obj = {'':1, [``]:2}", Some(serde_json::json!([]))), // { "ecmaVersion": 6 }, + ("var obj = {[``]:1, '':2}", Some(serde_json::json!([]))), // { "ecmaVersion": 6 }, + ("var obj = {'':1, a:2}", Some(serde_json::json!([]))), + ("var obj = {[``]:1, a:2}", Some(serde_json::json!([]))), // { "ecmaVersion": 6 }, + ("var obj = {_:2, a:1, b:3} // default", Some(serde_json::json!([]))), + ("var obj = {a:1, b:3, c:2}", Some(serde_json::json!([]))), + ("var obj = {a:2, b:3, b_:1}", Some(serde_json::json!([]))), + ("var obj = {C:3, b_:1, c:2}", Some(serde_json::json!([]))), + ("var obj = {$:1, A:3, _:2, a:4}", Some(serde_json::json!([]))), + ("var obj = {1:1, '11':2, 2:4, A:3}", Some(serde_json::json!([]))), + ("var obj = {'#':1, 'Z':2, À:3, è:4}", Some(serde_json::json!([]))), + ("var obj = { [/(?0)/]: 1, '/(?0)/': 2 }", Some(serde_json::json!([]))), // { "ecmaVersion": 2018 }, + // ("var obj = {a:1, b:3, [a + b]: -1, c:2}", Some(serde_json::json!([]))), // { "ecmaVersion": 6 }, + ("var obj = {'':1, [f()]:2, a:3}", Some(serde_json::json!([]))), // { "ecmaVersion": 6 }, + // ("var obj = {a:1, [b++]:2, '':3}", Some(serde_json::json!(["desc"]))), // { "ecmaVersion": 6 }, + ("var obj = {a:1, ...z, b:1}", Some(serde_json::json!([]))), // { "ecmaVersion": 2018 }, + ("var obj = {b:1, ...z, a:1}", Some(serde_json::json!([]))), // { "ecmaVersion": 2018 }, + ("var obj = {...a, b:1, ...c, d:1}", Some(serde_json::json!([]))), // { "ecmaVersion": 2018 }, + ("var obj = {...a, b:1, ...d, ...c, e:2, z:5}", Some(serde_json::json!([]))), // { "ecmaVersion": 2018 }, + ("var obj = {b:1, ...c, ...d, e:2}", Some(serde_json::json!([]))), // { "ecmaVersion": 2018 }, + ("var obj = {a:1, ...z, '':2}", Some(serde_json::json!([]))), // { "ecmaVersion": 2018 }, + ("var obj = {'':1, ...z, 'a':2}", Some(serde_json::json!(["desc"]))), // { "ecmaVersion": 2018 }, + ("var obj = {...z, a:1, b:1}", Some(serde_json::json!([]))), // { "ecmaVersion": 2018 }, + ("var obj = {...z, ...c, a:1, b:1}", Some(serde_json::json!([]))), // { "ecmaVersion": 2018 }, + ("var obj = {a:1, b:1, ...z}", Some(serde_json::json!([]))), // { "ecmaVersion": 2018 }, + ("var obj = {...z, ...x, a:1, ...c, ...d, f:5, e:4}", Some(serde_json::json!(["desc"]))), // { "ecmaVersion": 2018 }, + ("function fn(...args) { return [...args].length; }", Some(serde_json::json!([]))), // { "ecmaVersion": 2018 }, + ( + "function g() {}; function f(...args) { return g(...args); }", + Some(serde_json::json!([])), + ), // { "ecmaVersion": 2018 }, + ("let {a, b} = {}", Some(serde_json::json!([]))), // { "ecmaVersion": 6 }, + ("var obj = {a:1, b:{x:1, y:1}, c:1}", Some(serde_json::json!([]))), + ("var obj = {_:2, a:1, b:3} // asc", Some(serde_json::json!(["asc"]))), + ("var obj = {a:1, b:3, c:2}", Some(serde_json::json!(["asc"]))), + ("var obj = {a:2, b:3, b_:1}", Some(serde_json::json!(["asc"]))), + ("var obj = {C:3, b_:1, c:2}", Some(serde_json::json!(["asc"]))), + ("var obj = {$:1, A:3, _:2, a:4}", Some(serde_json::json!(["asc"]))), + ("var obj = {1:1, '11':2, 2:4, A:3}", Some(serde_json::json!(["asc"]))), + ("var obj = {'#':1, 'Z':2, À:3, è:4}", Some(serde_json::json!(["asc"]))), + ("var obj = {a:1, c:2, b:3}", Some(serde_json::json!(["asc", { "minKeys": 4 }]))), + ( + "var obj = {_:2, a:1, b:3} // asc, insensitive", + Some(serde_json::json!(["asc", { "caseSensitive": false }])), + ), + ("var obj = {a:1, b:3, c:2}", Some(serde_json::json!(["asc", { "caseSensitive": false }]))), + ( + "var obj = {a:2, b:3, b_:1}", + Some(serde_json::json!(["asc", { "caseSensitive": false }])), + ), + ( + "var obj = {b_:1, C:3, c:2}", + Some(serde_json::json!(["asc", { "caseSensitive": false }])), + ), + ( + "var obj = {b_:1, c:3, C:2}", + Some(serde_json::json!(["asc", { "caseSensitive": false }])), + ), + ( + "var obj = {$:1, _:2, A:3, a:4}", + Some(serde_json::json!(["asc", { "caseSensitive": false }])), + ), + ( + "var obj = {1:1, '11':2, 2:4, A:3}", + Some(serde_json::json!(["asc", { "caseSensitive": false }])), + ), + ( + "var obj = {'#':1, 'Z':2, À:3, è:4}", + Some(serde_json::json!(["asc", { "caseSensitive": false }])), + ), + ( + "var obj = {$:1, A:3, _:2, a:4}", + Some(serde_json::json!(["asc", { "caseSensitive": false, "minKeys": 5 }])), + ), + ( + "var obj = {_:2, a:1, b:3} // asc, natural", + Some(serde_json::json!(["asc", { "natural": true }])), + ), + ("var obj = {a:1, b:3, c:2}", Some(serde_json::json!(["asc", { "natural": true }]))), + ("var obj = {a:2, b:3, b_:1}", Some(serde_json::json!(["asc", { "natural": true }]))), + ("var obj = {C:3, b_:1, c:2}", Some(serde_json::json!(["asc", { "natural": true }]))), + ("var obj = {$:1, _:2, A:3, a:4}", Some(serde_json::json!(["asc", { "natural": true }]))), + ( + "var obj = {1:1, 2:4, '11':2, A:3}", + Some(serde_json::json!(["asc", { "natural": true }])), + ), + ( + "var obj = {'#':1, 'Z':2, À:3, è:4}", + Some(serde_json::json!(["asc", { "natural": true }])), + ), + ( + "var obj = {b_:1, a:2, b:3}", + Some(serde_json::json!(["asc", { "natural": true, "minKeys": 4 }])), + ), + ( + "var obj = {_:2, a:1, b:3} // asc, natural, insensitive", + Some(serde_json::json!(["asc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {a:1, b:3, c:2}", + Some(serde_json::json!(["asc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {a:2, b:3, b_:1}", + Some(serde_json::json!(["asc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {b_:1, C:3, c:2}", + Some(serde_json::json!(["asc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {b_:1, c:3, C:2}", + Some(serde_json::json!(["asc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {$:1, _:2, A:3, a:4}", + Some(serde_json::json!(["asc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {1:1, 2:4, '11':2, A:3}", + Some(serde_json::json!(["asc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {'#':1, 'Z':2, À:3, è:4}", + Some(serde_json::json!(["asc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {a:1, _:2, b:3}", + Some( + serde_json::json!(["asc", { "natural": true, "caseSensitive": false, "minKeys": 4 }]), + ), + ), + ("var obj = {b:3, a:1, _:2} // desc", Some(serde_json::json!(["desc"]))), + ("var obj = {c:2, b:3, a:1}", Some(serde_json::json!(["desc"]))), + ("var obj = {b_:1, b:3, a:2}", Some(serde_json::json!(["desc"]))), + ("var obj = {c:2, b_:1, C:3}", Some(serde_json::json!(["desc"]))), + ("var obj = {a:4, _:2, A:3, $:1}", Some(serde_json::json!(["desc"]))), + ("var obj = {A:3, 2:4, '11':2, 1:1}", Some(serde_json::json!(["desc"]))), + ("var obj = {è:4, À:3, 'Z':2, '#':1}", Some(serde_json::json!(["desc"]))), + ("var obj = {a:1, c:2, b:3}", Some(serde_json::json!(["desc", { "minKeys": 4 }]))), + ( + "var obj = {b:3, a:1, _:2} // desc, insensitive", + Some(serde_json::json!(["desc", { "caseSensitive": false }])), + ), + ( + "var obj = {c:2, b:3, a:1}", + Some(serde_json::json!(["desc", { "caseSensitive": false }])), + ), + ( + "var obj = {b_:1, b:3, a:2}", + Some(serde_json::json!(["desc", { "caseSensitive": false }])), + ), + ( + "var obj = {c:2, C:3, b_:1}", + Some(serde_json::json!(["desc", { "caseSensitive": false }])), + ), + ( + "var obj = {C:2, c:3, b_:1}", + Some(serde_json::json!(["desc", { "caseSensitive": false }])), + ), + ( + "var obj = {a:4, A:3, _:2, $:1}", + Some(serde_json::json!(["desc", { "caseSensitive": false }])), + ), + ( + "var obj = {A:3, 2:4, '11':2, 1:1}", + Some(serde_json::json!(["desc", { "caseSensitive": false }])), + ), + ( + "var obj = {è:4, À:3, 'Z':2, '#':1}", + Some(serde_json::json!(["desc", { "caseSensitive": false }])), + ), + ( + "var obj = {$:1, _:2, A:3, a:4}", + Some(serde_json::json!(["desc", { "caseSensitive": false, "minKeys": 5 }])), + ), + ( + "var obj = {b:3, a:1, _:2} // desc, natural", + Some(serde_json::json!(["desc", { "natural": true }])), + ), + ("var obj = {c:2, b:3, a:1}", Some(serde_json::json!(["desc", { "natural": true }]))), + ("var obj = {b_:1, b:3, a:2}", Some(serde_json::json!(["desc", { "natural": true }]))), + ("var obj = {c:2, b_:1, C:3}", Some(serde_json::json!(["desc", { "natural": true }]))), + ("var obj = {a:4, A:3, _:2, $:1}", Some(serde_json::json!(["desc", { "natural": true }]))), + ( + "var obj = {A:3, '11':2, 2:4, 1:1}", + Some(serde_json::json!(["desc", { "natural": true }])), + ), + ( + "var obj = {è:4, À:3, 'Z':2, '#':1}", + Some(serde_json::json!(["desc", { "natural": true }])), + ), + ( + "var obj = {b_:1, a:2, b:3}", + Some(serde_json::json!(["desc", { "natural": true, "minKeys": 4 }])), + ), + ( + "var obj = {b:3, a:1, _:2} // desc, natural, insensitive", + Some(serde_json::json!(["desc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {c:2, b:3, a:1}", + Some(serde_json::json!(["desc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {b_:1, b:3, a:2}", + Some(serde_json::json!(["desc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {c:2, C:3, b_:1}", + Some(serde_json::json!(["desc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {C:2, c:3, b_:1}", + Some(serde_json::json!(["desc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {a:4, A:3, _:2, $:1}", + Some(serde_json::json!(["desc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {A:3, '11':2, 2:4, 1:1}", + Some(serde_json::json!(["desc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {è:4, À:3, 'Z':2, '#':1}", + Some(serde_json::json!(["desc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {a:1, _:2, b:3}", + Some( + serde_json::json!(["desc", { "natural": true, "caseSensitive": false, "minKeys": 4 }]), + ), + ), + ( + " + var obj = { + e: 1, + f: 2, + g: 3, + + a: 4, + b: 5, + c: 6 + } + ", + Some(serde_json::json!(["asc", { "allowLineSeparatedGroups": true }])), + ), + ( + " + var obj = { + b: 1, + + // comment + a: 2, + c: 3 + } + ", + Some(serde_json::json!(["asc", { "allowLineSeparatedGroups": true }])), + ), + ( + " + var obj = { + b: 1 + + , + + // comment + a: 2, + c: 3 + } + ", + Some(serde_json::json!(["asc", { "allowLineSeparatedGroups": true }])), + ), + ( + " + var obj = { + c: 1, + d: 2, + + b() { + }, + e: 4 + } + ", + Some(serde_json::json!(["asc", { "allowLineSeparatedGroups": true }])), + ), // { "ecmaVersion": 6 }, + ( + " + var obj = { + c: 1, + d: 2, + // comment + + // comment + b() { + }, + e: 4 + } + ", + Some(serde_json::json!(["asc", { "allowLineSeparatedGroups": true }])), + ), // { "ecmaVersion": 6 }, + ( + " + var obj = { + b, + + [a+b]: 1, + a + } + ", + Some(serde_json::json!(["asc", { "allowLineSeparatedGroups": true }])), + ), // { "ecmaVersion": 6 }, + ( + " + var obj = { + c: 1, + d: 2, + + a() { + + }, + + // abce + f: 3, + + /* + + */ + [a+b]: 1, + cc: 1, + e: 2 + } + ", + Some(serde_json::json!(["asc", { "allowLineSeparatedGroups": true }])), + ), // { "ecmaVersion": 6 }, + ( + r#" + var obj = { + b: "/*", + + a: "*/", + } + "#, + Some(serde_json::json!(["asc", { "allowLineSeparatedGroups": true }])), + ), + ( + " + var obj = { + b, + /* + */ // + + a + } + ", + Some(serde_json::json!(["asc", { "allowLineSeparatedGroups": true }])), + ), // { "ecmaVersion": 6 }, + ( + " + var obj = { + b, + + /* + */ // + a + } + ", + Some(serde_json::json!(["asc", { "allowLineSeparatedGroups": true }])), + ), // { "ecmaVersion": 6 }, + ( + " + var obj = { + b: 1 + + ,a: 2 + }; + ", + Some(serde_json::json!(["asc", { "allowLineSeparatedGroups": true }])), + ), // { "ecmaVersion": 6 }, + ( + " + var obj = { + b: 1 + // comment before comma + + , + a: 2 + }; + ", + Some(serde_json::json!(["asc", { "allowLineSeparatedGroups": true }])), + ), // { "ecmaVersion": 6 }, + ( + " + var obj = { + b, + + a, + ...z, + c + } + ", + Some(serde_json::json!(["asc", { "allowLineSeparatedGroups": true }])), + ), // { "ecmaVersion": 2018 }, + ( + " + var obj = { + b, + + [foo()]: [ + + ], + a + } + ", + Some(serde_json::json!(["asc", { "allowLineSeparatedGroups": true }])), + ), // { "ecmaVersion": 2018 } + ]; + + let fail = vec![ + ("var obj = {a:1, '':2} // default", None), + ("var obj = {a:1, [``]:2} // default", None), // { "ecmaVersion": 6 }, + ("var obj = {a:1, _:2, b:3} // default", None), + ("var obj = {a:1, c:2, b:3}", None), + ("var obj = {b_:1, a:2, b:3}", None), + ("var obj = {b_:1, c:2, C:3}", None), + ("var obj = {$:1, _:2, A:3, a:4}", None), + ("var obj = {1:1, 2:4, A:3, '11':2}", None), + ("var obj = {'#':1, À:3, 'Z':2, è:4}", None), + ("var obj = { null: 1, [/(?0)/]: 2 }", None), // { "ecmaVersion": 2018 }, + ("var obj = {...z, c:1, b:1}", Some(serde_json::json!([]))), // { "ecmaVersion": 2018 }, + ("var obj = {...z, ...c, d:4, b:1, ...y, ...f, e:2, a:1}", Some(serde_json::json!([]))), // { "ecmaVersion": 2018 }, + ("var obj = {c:1, b:1, ...a}", Some(serde_json::json!([]))), // { "ecmaVersion": 2018 }, + ("var obj = {...z, ...a, c:1, b:1}", Some(serde_json::json!([]))), // { "ecmaVersion": 2018 }, + ("var obj = {...z, b:1, a:1, ...d, ...c}", Some(serde_json::json!([]))), // { "ecmaVersion": 2018 }, + ("var obj = {...z, a:2, b:0, ...x, ...c}", Some(serde_json::json!(["desc"]))), // { "ecmaVersion": 2018 }, + ("var obj = {...z, a:2, b:0, ...x}", Some(serde_json::json!(["desc"]))), // { "ecmaVersion": 2018 }, + ("var obj = {...z, '':1, a:2}", Some(serde_json::json!(["desc"]))), // { "ecmaVersion": 2018 }, + ("var obj = {a:1, [b+c]:2, '':3}", None), // { "ecmaVersion": 6 }, + ("var obj = {'':1, [b+c]:2, a:3}", Some(serde_json::json!(["desc"]))), // { "ecmaVersion": 6 }, + ("var obj = {b:1, [f()]:2, '':3, a:4}", Some(serde_json::json!(["desc"]))), // { "ecmaVersion": 6 }, + ("var obj = {a:1, b:3, [a]: -1, c:2}", None), // { "ecmaVersion": 6 }, + ("var obj = {a:1, c:{y:1, x:1}, b:1}", None), + ("var obj = {a:1, _:2, b:3} // asc", Some(serde_json::json!(["asc"]))), + ("var obj = {a:1, c:2, b:3}", Some(serde_json::json!(["asc"]))), + ("var obj = {b_:1, a:2, b:3}", Some(serde_json::json!(["asc"]))), + ("var obj = {b_:1, c:2, C:3}", Some(serde_json::json!(["asc"]))), + ("var obj = {$:1, _:2, A:3, a:4}", Some(serde_json::json!(["asc"]))), + ("var obj = {1:1, 2:4, A:3, '11':2}", Some(serde_json::json!(["asc"]))), + ("var obj = {'#':1, À:3, 'Z':2, è:4}", Some(serde_json::json!(["asc"]))), + ("var obj = {a:1, _:2, b:3}", Some(serde_json::json!(["asc", { "minKeys": 3 }]))), + ( + "var obj = {a:1, _:2, b:3} // asc, insensitive", + Some(serde_json::json!(["asc", { "caseSensitive": false }])), + ), + ("var obj = {a:1, c:2, b:3}", Some(serde_json::json!(["asc", { "caseSensitive": false }]))), + ( + "var obj = {b_:1, a:2, b:3}", + Some(serde_json::json!(["asc", { "caseSensitive": false }])), + ), + ( + "var obj = {$:1, A:3, _:2, a:4}", + Some(serde_json::json!(["asc", { "caseSensitive": false }])), + ), + ( + "var obj = {1:1, 2:4, A:3, '11':2}", + Some(serde_json::json!(["asc", { "caseSensitive": false }])), + ), + ( + "var obj = {'#':1, À:3, 'Z':2, è:4}", + Some(serde_json::json!(["asc", { "caseSensitive": false }])), + ), + ( + "var obj = {a:1, _:2, b:3}", + Some(serde_json::json!(["asc", { "caseSensitive": false, "minKeys": 3 }])), + ), + ( + "var obj = {a:1, _:2, b:3} // asc, natural", + Some(serde_json::json!(["asc", { "natural": true }])), + ), + ("var obj = {a:1, c:2, b:3}", Some(serde_json::json!(["asc", { "natural": true }]))), + ("var obj = {b_:1, a:2, b:3}", Some(serde_json::json!(["asc", { "natural": true }]))), + ("var obj = {b_:1, c:2, C:3}", Some(serde_json::json!(["asc", { "natural": true }]))), + ("var obj = {$:1, A:3, _:2, a:4}", Some(serde_json::json!(["asc", { "natural": true }]))), + ( + "var obj = {1:1, 2:4, A:3, '11':2}", + Some(serde_json::json!(["asc", { "natural": true }])), + ), + ( + "var obj = {'#':1, À:3, 'Z':2, è:4}", + Some(serde_json::json!(["asc", { "natural": true }])), + ), + ( + "var obj = {a:1, _:2, b:3}", + Some(serde_json::json!(["asc", { "natural": true, "minKeys": 2 }])), + ), + ( + "var obj = {a:1, _:2, b:3} // asc, natural, insensitive", + Some(serde_json::json!(["asc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {a:1, c:2, b:3}", + Some(serde_json::json!(["asc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {b_:1, a:2, b:3}", + Some(serde_json::json!(["asc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {$:1, A:3, _:2, a:4}", + Some(serde_json::json!(["asc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {1:1, '11':2, 2:4, A:3}", + Some(serde_json::json!(["asc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {'#':1, À:3, 'Z':2, è:4}", + Some(serde_json::json!(["asc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {a:1, _:2, b:3}", + Some( + serde_json::json!(["asc", { "natural": true, "caseSensitive": false, "minKeys": 3 }]), + ), + ), + ("var obj = {'':1, a:'2'} // desc", Some(serde_json::json!(["desc"]))), + ("var obj = {[``]:1, a:'2'} // desc", Some(serde_json::json!(["desc"]))), // { "ecmaVersion": 6 }, + ("var obj = {a:1, _:2, b:3} // desc", Some(serde_json::json!(["desc"]))), + ("var obj = {a:1, c:2, b:3}", Some(serde_json::json!(["desc"]))), + ("var obj = {b_:1, a:2, b:3}", Some(serde_json::json!(["desc"]))), + ("var obj = {b_:1, c:2, C:3}", Some(serde_json::json!(["desc"]))), + ("var obj = {$:1, _:2, A:3, a:4}", Some(serde_json::json!(["desc"]))), + ("var obj = {1:1, 2:4, A:3, '11':2}", Some(serde_json::json!(["desc"]))), + ("var obj = {'#':1, À:3, 'Z':2, è:4}", Some(serde_json::json!(["desc"]))), + ("var obj = {a:1, _:2, b:3}", Some(serde_json::json!(["desc", { "minKeys": 3 }]))), + ( + "var obj = {a:1, _:2, b:3} // desc, insensitive", + Some(serde_json::json!(["desc", { "caseSensitive": false }])), + ), + ( + "var obj = {a:1, c:2, b:3}", + Some(serde_json::json!(["desc", { "caseSensitive": false }])), + ), + ( + "var obj = {b_:1, a:2, b:3}", + Some(serde_json::json!(["desc", { "caseSensitive": false }])), + ), + ( + "var obj = {b_:1, c:2, C:3}", + Some(serde_json::json!(["desc", { "caseSensitive": false }])), + ), + ( + "var obj = {$:1, _:2, A:3, a:4}", + Some(serde_json::json!(["desc", { "caseSensitive": false }])), + ), + ( + "var obj = {1:1, 2:4, A:3, '11':2}", + Some(serde_json::json!(["desc", { "caseSensitive": false }])), + ), + ( + "var obj = {'#':1, À:3, 'Z':2, è:4}", + Some(serde_json::json!(["desc", { "caseSensitive": false }])), + ), + ( + "var obj = {a:1, _:2, b:3}", + Some(serde_json::json!(["desc", { "caseSensitive": false, "minKeys": 2 }])), + ), + ( + "var obj = {a:1, _:2, b:3} // desc, natural", + Some(serde_json::json!(["desc", { "natural": true }])), + ), + ("var obj = {a:1, c:2, b:3}", Some(serde_json::json!(["desc", { "natural": true }]))), + ("var obj = {b_:1, a:2, b:3}", Some(serde_json::json!(["desc", { "natural": true }]))), + ("var obj = {b_:1, c:2, C:3}", Some(serde_json::json!(["desc", { "natural": true }]))), + ("var obj = {$:1, _:2, A:3, a:4}", Some(serde_json::json!(["desc", { "natural": true }]))), + ( + "var obj = {1:1, 2:4, A:3, '11':2}", + Some(serde_json::json!(["desc", { "natural": true }])), + ), + ( + "var obj = {'#':1, À:3, 'Z':2, è:4}", + Some(serde_json::json!(["desc", { "natural": true }])), + ), + ( + "var obj = {a:1, _:2, b:3}", + Some(serde_json::json!(["desc", { "natural": true, "minKeys": 3 }])), + ), + ( + "var obj = {a:1, _:2, b:3} // desc, natural, insensitive", + Some(serde_json::json!(["desc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {a:1, c:2, b:3}", + Some(serde_json::json!(["desc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {b_:1, a:2, b:3}", + Some(serde_json::json!(["desc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {b_:1, c:2, C:3}", + Some(serde_json::json!(["desc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {$:1, _:2, A:3, a:4}", + Some(serde_json::json!(["desc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {1:1, 2:4, '11':2, A:3}", + Some(serde_json::json!(["desc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {'#':1, À:3, 'Z':2, è:4}", + Some(serde_json::json!(["desc", { "natural": true, "caseSensitive": false }])), + ), + ( + "var obj = {a:1, _:2, b:3}", + Some( + serde_json::json!(["desc", { "natural": true, "caseSensitive": false, "minKeys": 2 }]), + ), + ), + ( + " + var obj = { + b: 1, + c: 2, + a: 3 + } + ", + Some(serde_json::json!(["asc", { "allowLineSeparatedGroups": false }])), + ), + ( + " + let obj = { + b + + ,a + } + ", + Some(serde_json::json!(["asc", { "allowLineSeparatedGroups": false }])), + ), // { "ecmaVersion": 6 }, + ( + " + var obj = { + b: 1, + c () { + + }, + a: 3 + } + ", + Some(serde_json::json!(["asc", { "allowLineSeparatedGroups": true }])), + ), // { "ecmaVersion": 6 }, + ( + " + var obj = { + a: 1, + b: 2, + + z () { + + }, + y: 3 + } + ", + Some(serde_json::json!(["asc", { "allowLineSeparatedGroups": true }])), + ), // { "ecmaVersion": 6 }, + ( + " + var obj = { + b: 1, + c () { + }, + // comment + a: 3 + } + ", + Some(serde_json::json!(["asc", { "allowLineSeparatedGroups": true }])), + ), // { "ecmaVersion": 6 }, + ( + " + var obj = { + b, + [a+b]: 1, + a // sort-keys: 'a' should be before 'b' + } + ", + Some(serde_json::json!(["asc", { "allowLineSeparatedGroups": true }])), + ), // { "ecmaVersion": 6 }, + ( + " + var obj = { + c: 1, + d: 2, + // comment + // comment + b() { + }, + e: 4 + } + ", + Some(serde_json::json!(["asc", { "allowLineSeparatedGroups": true }])), + ), // { "ecmaVersion": 6 }, + ( + " + var obj = { + c: 1, + d: 2, + + z() { + + }, + f: 3, + /* + + + */ + [a+b]: 1, + b: 1, + e: 2 + } + ", + Some(serde_json::json!(["asc", { "allowLineSeparatedGroups": true }])), + ), // { "ecmaVersion": 6 }, + ( + r#" + var obj = { + b: "/*", + a: "*/", + } + "#, + Some(serde_json::json!(["asc", { "allowLineSeparatedGroups": true }])), + ), + ( + " + var obj = { + b: 1 + // comment before comma + , a: 2 + }; + ", + Some(serde_json::json!(["asc", { "allowLineSeparatedGroups": true }])), + ), // { "ecmaVersion": 6 }, + ( + " + let obj = { + b, + [foo()]: [ + // ↓ this blank is inside a property and therefore should not count + + ], + a + } + ", + Some(serde_json::json!(["asc", { "allowLineSeparatedGroups": true }])), + ), // { "ecmaVersion": 2018 } + ]; + + Tester::new(SortKeys::NAME, pass, fail).test_and_snapshot(); +} diff --git a/crates/oxc_linter/src/snapshots/sort_keys.snap b/crates/oxc_linter/src/snapshots/sort_keys.snap new file mode 100644 index 0000000000000..4826535de1e16 --- /dev/null +++ b/crates/oxc_linter/src/snapshots/sort_keys.snap @@ -0,0 +1,676 @@ +--- +source: crates/oxc_linter/src/tester.rs +--- + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, '':2} // default + · ─────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, [``]:2} // default + · ───────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, _:2, b:3} // default + · ─────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, c:2, b:3} + · ─────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {b_:1, a:2, b:3} + · ──────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {b_:1, c:2, C:3} + · ──────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {$:1, _:2, A:3, a:4} + · ──────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {1:1, 2:4, A:3, '11':2} + · ─────────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {'#':1, À:3, 'Z':2, è:4} + · ──────────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = { null: 1, [/(?0)/]: 2 } + · ────────────────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {...z, c:1, b:1} + · ──────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {...z, ...c, d:4, b:1, ...y, ...f, e:2, a:1} + · ──────────────────────────────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {c:1, b:1, ...a} + · ──────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {...z, ...a, c:1, b:1} + · ────────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {...z, b:1, a:1, ...d, ...c} + · ──────────────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {...z, a:2, b:0, ...x, ...c} + · ──────────────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {...z, a:2, b:0, ...x} + · ────────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {...z, '':1, a:2} + · ───────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, [b+c]:2, '':3} + · ──────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {'':1, [b+c]:2, a:3} + · ──────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {b:1, [f()]:2, '':3, a:4} + · ───────────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, b:3, [a]: -1, c:2} + · ──────────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, c:{y:1, x:1}, b:1} + · ──────────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:19] + 1 │ var obj = {a:1, c:{y:1, x:1}, b:1} + · ────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, _:2, b:3} // asc + · ─────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, c:2, b:3} + · ─────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {b_:1, a:2, b:3} + · ──────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {b_:1, c:2, C:3} + · ──────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {$:1, _:2, A:3, a:4} + · ──────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {1:1, 2:4, A:3, '11':2} + · ─────────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {'#':1, À:3, 'Z':2, è:4} + · ──────────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, _:2, b:3} + · ─────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, _:2, b:3} // asc, insensitive + · ─────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, c:2, b:3} + · ─────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {b_:1, a:2, b:3} + · ──────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {$:1, A:3, _:2, a:4} + · ──────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {1:1, 2:4, A:3, '11':2} + · ─────────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {'#':1, À:3, 'Z':2, è:4} + · ──────────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, _:2, b:3} + · ─────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, _:2, b:3} // asc, natural + · ─────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, c:2, b:3} + · ─────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {b_:1, a:2, b:3} + · ──────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {b_:1, c:2, C:3} + · ──────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {$:1, A:3, _:2, a:4} + · ──────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {1:1, 2:4, A:3, '11':2} + · ─────────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {'#':1, À:3, 'Z':2, è:4} + · ──────────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, _:2, b:3} + · ─────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, _:2, b:3} // asc, natural, insensitive + · ─────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, c:2, b:3} + · ─────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {b_:1, a:2, b:3} + · ──────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {$:1, A:3, _:2, a:4} + · ──────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {1:1, '11':2, 2:4, A:3} + · ─────────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {'#':1, À:3, 'Z':2, è:4} + · ──────────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, _:2, b:3} + · ─────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {'':1, a:'2'} // desc + · ───────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {[``]:1, a:'2'} // desc + · ─────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, _:2, b:3} // desc + · ─────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, c:2, b:3} + · ─────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {b_:1, a:2, b:3} + · ──────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {b_:1, c:2, C:3} + · ──────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {$:1, _:2, A:3, a:4} + · ──────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {1:1, 2:4, A:3, '11':2} + · ─────────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {'#':1, À:3, 'Z':2, è:4} + · ──────────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, _:2, b:3} + · ─────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, _:2, b:3} // desc, insensitive + · ─────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, c:2, b:3} + · ─────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {b_:1, a:2, b:3} + · ──────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {b_:1, c:2, C:3} + · ──────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {$:1, _:2, A:3, a:4} + · ──────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {1:1, 2:4, A:3, '11':2} + · ─────────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {'#':1, À:3, 'Z':2, è:4} + · ──────────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, _:2, b:3} + · ─────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, _:2, b:3} // desc, natural + · ─────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, c:2, b:3} + · ─────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {b_:1, a:2, b:3} + · ──────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {b_:1, c:2, C:3} + · ──────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {$:1, _:2, A:3, a:4} + · ──────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {1:1, 2:4, A:3, '11':2} + · ─────────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {'#':1, À:3, 'Z':2, è:4} + · ──────────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, _:2, b:3} + · ─────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, _:2, b:3} // desc, natural, insensitive + · ─────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, c:2, b:3} + · ─────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {b_:1, a:2, b:3} + · ──────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {b_:1, c:2, C:3} + · ──────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {$:1, _:2, A:3, a:4} + · ──────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {1:1, 2:4, '11':2, A:3} + · ─────────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {'#':1, À:3, 'Z':2, è:4} + · ──────────────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:1:11] + 1 │ var obj = {a:1, _:2, b:3} + · ─────────────── + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:2:36] + 1 │ + 2 │ ╭─▶ var obj = { + 3 │ │ b: 1, + 4 │ │ c: 2, + 5 │ │ a: 3 + 6 │ ╰─▶ } + 7 │ + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:2:36] + 1 │ + 2 │ ╭─▶ let obj = { + 3 │ │ b + 4 │ │ + 5 │ │ ,a + 6 │ ╰─▶ } + 7 │ + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:2:37] + 1 │ + 2 │ ╭─▶ var obj = { + 3 │ │ b: 1, + 4 │ │ c () { + 5 │ │ + 6 │ │ }, + 7 │ │ a: 3 + 8 │ ╰─▶ } + 9 │ + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:2:37] + 1 │ + 2 │ ╭─▶ var obj = { + 3 │ │ a: 1, + 4 │ │ b: 2, + 5 │ │ + 6 │ │ z () { + 7 │ │ + 8 │ │ }, + 9 │ │ y: 3 + 10 │ ╰─▶ } + 11 │ + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:2:31] + 1 │ + 2 │ ╭─▶ var obj = { + 3 │ │ b: 1, + 4 │ │ c () { + 5 │ │ }, + 6 │ │ // comment + 7 │ │ a: 3 + 8 │ ╰─▶ } + 9 │ + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:2:30] + 1 │ + 2 │ ╭─▶ var obj = { + 3 │ │ b, + 4 │ │ [a+b]: 1, + 5 │ │ a // sort-keys: 'a' should be before 'b' + 6 │ ╰─▶ } + 7 │ + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:2:30] + 1 │ + 2 │ ╭─▶ var obj = { + 3 │ │ c: 1, + 4 │ │ d: 2, + 5 │ │ // comment + 6 │ │ // comment + 7 │ │ b() { + 8 │ │ }, + 9 │ │ e: 4 + 10 │ ╰─▶ } + 11 │ + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:2:30] + 1 │ + 2 │ ╭─▶ var obj = { + 3 │ │ c: 1, + 4 │ │ d: 2, + 5 │ │ + 6 │ │ z() { + 7 │ │ + 8 │ │ }, + 9 │ │ f: 3, + 10 │ │ /* + 11 │ │ + 12 │ │ + 13 │ │ */ + 14 │ │ [a+b]: 1, + 15 │ │ b: 1, + 16 │ │ e: 2 + 17 │ ╰─▶ } + 18 │ + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:2:30] + 1 │ + 2 │ ╭─▶ var obj = { + 3 │ │ b: "/*", + 4 │ │ a: "*/", + 5 │ ╰─▶ } + 6 │ + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:2:30] + 1 │ + 2 │ ╭─▶ var obj = { + 3 │ │ b: 1 + 4 │ │ // comment before comma + 5 │ │ , a: 2 + 6 │ ╰─▶ }; + 7 │ + ╰──── + + ⚠ eslint(sort-keys): Object keys should be sorted + ╭─[sort_keys.tsx:2:30] + 1 │ + 2 │ ╭─▶ let obj = { + 3 │ │ b, + 4 │ │ [foo()]: [ + 5 │ │ // ↓ this blank is inside a property and therefore should not count + 6 │ │ + 7 │ │ ], + 8 │ │ a + 9 │ ╰─▶ } + 10 │ + ╰────