@ttsc/lint 0.14.0-dev.20260529.2 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -23
- package/lib/defaultFormat.d.ts +10 -6
- package/lib/defaultFormat.js +10 -6
- package/lib/defaultFormat.js.map +1 -1
- package/lib/structures/ITtscLintConfig.d.ts +5 -5
- package/lib/structures/TtscLintRuleSetting.d.ts +19 -19
- package/lib/structures/{ITtscLintFormat.d.ts → format/ITtscLintFormat.d.ts} +45 -70
- package/lib/structures/format/ITtscLintFormat.js.map +1 -0
- package/lib/structures/format/ITtscLintFormatJsDoc.d.ts +15 -0
- package/lib/structures/format/ITtscLintFormatJsDoc.js +3 -0
- package/lib/structures/format/ITtscLintFormatJsDoc.js.map +1 -0
- package/lib/structures/format/ITtscLintFormatSortImports.d.ts +54 -0
- package/lib/structures/format/ITtscLintFormatSortImports.js +3 -0
- package/lib/structures/format/ITtscLintFormatSortImports.js.map +1 -0
- package/lib/structures/format/index.d.ts +3 -0
- package/lib/structures/format/index.js +20 -0
- package/lib/structures/format/index.js.map +1 -0
- package/lib/structures/index.d.ts +1 -1
- package/lib/structures/index.js +1 -1
- package/lib/structures/index.js.map +1 -1
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.d.ts +18 -27
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js +4 -5
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js.map +1 -1
- package/lib/structures/rules/ITtscLintBoundariesRules.d.ts +29 -33
- package/lib/structures/rules/ITtscLintContributorRules.d.ts +6 -7
- package/lib/structures/rules/ITtscLintCoreRules.d.ts +380 -408
- package/lib/structures/rules/ITtscLintCypressRuleOptions.d.ts +5 -5
- package/lib/structures/rules/ITtscLintCypressRuleOptions.js +2 -2
- package/lib/structures/rules/ITtscLintCypressRules.d.ts +34 -38
- package/lib/structures/rules/ITtscLintFunctionalRuleOptions.d.ts +21 -24
- package/lib/structures/rules/ITtscLintFunctionalRuleOptions.js +2 -2
- package/lib/structures/rules/ITtscLintFunctionalRules.d.ts +51 -56
- package/lib/structures/rules/ITtscLintJestRules.d.ts +63 -74
- package/lib/structures/rules/ITtscLintJsdocRules.d.ts +47 -54
- package/lib/structures/rules/ITtscLintJsxA11yRules.d.ts +94 -102
- package/lib/structures/rules/ITtscLintNextjsRules.d.ts +50 -55
- package/lib/structures/rules/ITtscLintPlaywrightRules.d.ts +104 -122
- package/lib/structures/rules/ITtscLintPromiseRules.d.ts +62 -71
- package/lib/structures/rules/ITtscLintReactPerfRuleOptions.d.ts +4 -4
- package/lib/structures/rules/ITtscLintReactPerfRules.d.ts +17 -19
- package/lib/structures/rules/ITtscLintReactRuleOptions.d.ts +8 -10
- package/lib/structures/rules/ITtscLintReactRuleOptions.js +1 -2
- package/lib/structures/rules/ITtscLintReactRuleOptions.js.map +1 -1
- package/lib/structures/rules/ITtscLintReactRules.d.ts +91 -104
- package/lib/structures/rules/ITtscLintRegexpRules.d.ts +46 -54
- package/lib/structures/rules/ITtscLintRuleOptionsMap.d.ts +7 -8
- package/lib/structures/rules/ITtscLintSecurityRules.d.ts +45 -52
- package/lib/structures/rules/ITtscLintSolidRules.d.ts +53 -56
- package/lib/structures/rules/ITtscLintStorybookRuleOptions.d.ts +3 -4
- package/lib/structures/rules/ITtscLintStorybookRules.d.ts +60 -69
- package/lib/structures/rules/ITtscLintTanstackQueryRules.d.ts +31 -37
- package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.d.ts +2 -3
- package/lib/structures/rules/ITtscLintTestingLibraryRules.d.ts +102 -119
- package/lib/structures/rules/ITtscLintTypeScriptRules.d.ts +460 -518
- package/lib/structures/rules/ITtscLintVitestRules.d.ts +43 -51
- package/linthost/config.go +89 -72
- package/linthost/config_format.go +265 -99
- package/linthost/directives.go +5 -1
- package/linthost/display_width.go +72 -0
- package/linthost/fix.go +26 -1
- package/linthost/format.go +222 -25
- package/linthost/format_editor_settings.go +262 -0
- package/linthost/lsp.go +8 -4
- package/linthost/print_dispatch.go +3 -0
- package/linthost/print_doc.go +13 -0
- package/linthost/print_engine.go +68 -11
- package/linthost/print_nodes_array.go +108 -5
- package/linthost/print_nodes_call.go +515 -74
- package/linthost/print_nodes_function.go +25 -0
- package/linthost/print_nodes_imports.go +47 -14
- package/linthost/print_nodes_list.go +191 -8
- package/linthost/print_nodes_object.go +12 -6
- package/linthost/print_nodes_ternary.go +106 -0
- package/linthost/rules_boundaries.go +400 -400
- package/linthost/rules_camelcase.go +81 -81
- package/linthost/rules_complexity.go +52 -51
- package/linthost/rules_consistent_return.go +81 -81
- package/linthost/rules_core_extra.go +472 -472
- package/linthost/rules_curly.go +43 -43
- package/linthost/rules_default_case.go +15 -15
- package/linthost/rules_default_case_last.go +22 -22
- package/linthost/rules_format_arrow_parens.go +167 -0
- package/linthost/rules_format_bracket_spacing.go +117 -0
- package/linthost/rules_format_clause_join.go +172 -0
- package/linthost/rules_format_declaration_header.go +664 -0
- package/linthost/rules_format_indent.go +616 -0
- package/linthost/rules_format_jsdoc.go +4 -4
- package/linthost/rules_format_orphan_semi.go +106 -0
- package/linthost/rules_format_parameter_properties.go +175 -0
- package/linthost/rules_format_print_width.go +185 -69
- package/linthost/rules_format_quote_props.go +169 -0
- package/linthost/rules_format_quotes.go +75 -29
- package/linthost/rules_format_semi.go +185 -10
- package/linthost/rules_format_sort_imports.go +456 -121
- package/linthost/rules_format_statement_split.go +368 -0
- package/linthost/rules_format_ternary_nullish_parens.go +77 -0
- package/linthost/rules_format_trailing_comma.go +21 -2
- package/linthost/rules_format_whitespace.go +336 -0
- package/linthost/rules_functional.go +688 -688
- package/linthost/rules_gap.go +146 -11
- package/linthost/rules_grouped_accessor_pairs.go +60 -60
- package/linthost/rules_guard_for_in.go +122 -122
- package/linthost/rules_id_length.go +44 -44
- package/linthost/rules_imports.go +11 -3
- package/linthost/rules_init_declarations.go +25 -25
- package/linthost/rules_jsx_a11y.go +844 -844
- package/linthost/rules_max_classes_per_file.go +24 -24
- package/linthost/rules_max_depth.go +43 -43
- package/linthost/rules_max_lines.go +53 -53
- package/linthost/rules_max_lines_per_function.go +28 -28
- package/linthost/rules_max_nested_callbacks.go +26 -26
- package/linthost/rules_max_params.go +20 -20
- package/linthost/rules_max_statements.go +29 -29
- package/linthost/rules_nextjs.go +5 -5
- package/linthost/rules_no_else_return.go +38 -38
- package/linthost/rules_no_empty_named_blocks.go +45 -45
- package/linthost/rules_no_import_assign.go +96 -96
- package/linthost/rules_no_invalid_this.go +19 -19
- package/linthost/rules_no_loop_func.go +43 -43
- package/linthost/rules_no_magic_numbers.go +60 -60
- package/linthost/rules_no_mixed_operators.go +44 -44
- package/linthost/rules_no_param_reassign.go +64 -64
- package/linthost/rules_no_restricted_imports.go +45 -45
- package/linthost/rules_no_restricted_syntax.go +17 -17
- package/linthost/rules_no_shadow.go +112 -112
- package/linthost/rules_no_unreachable.go +36 -36
- package/linthost/rules_no_useless_assignment.go +79 -79
- package/linthost/rules_no_useless_constructor.go +167 -167
- package/linthost/rules_no_useless_return.go +28 -28
- package/linthost/rules_prefer_arrow_callback.go +74 -74
- package/linthost/rules_prefer_destructuring.go +61 -61
- package/linthost/rules_prefer_named_capture_group.go +87 -87
- package/linthost/rules_prefer_rest_params.go +61 -61
- package/linthost/rules_promise.go +800 -800
- package/linthost/rules_react.go +600 -600
- package/linthost/rules_react_extras.go +162 -162
- package/linthost/rules_react_hooks.go +2 -2
- package/linthost/rules_react_perf.go +231 -231
- package/linthost/rules_regexp.go +293 -293
- package/linthost/rules_security.go +613 -613
- package/linthost/rules_sort_imports.go +37 -37
- package/linthost/rules_sort_keys.go +88 -88
- package/linthost/rules_suggestions.go +13 -0
- package/linthost/rules_ts.go +2 -2
- package/linthost/rules_ts_async.go +247 -247
- package/linthost/rules_ts_class_literal_property_style.go +64 -64
- package/linthost/rules_ts_consistent_type_exports.go +209 -209
- package/linthost/rules_ts_explicit_function_return_type.go +35 -35
- package/linthost/rules_ts_extra.go +6 -2
- package/linthost/rules_ts_no_base_to_string.go +140 -140
- package/linthost/rules_ts_no_confusing_void.go +28 -28
- package/linthost/rules_ts_no_deprecated.go +110 -110
- package/linthost/rules_ts_no_for_in_array.go +45 -45
- package/linthost/rules_ts_no_magic_numbers.go +67 -67
- package/linthost/rules_ts_no_meaningless_void_operator.go +44 -44
- package/linthost/rules_ts_no_misused_spread.go +64 -64
- package/linthost/rules_ts_no_redundant_type_constituents.go +72 -72
- package/linthost/rules_ts_no_restricted_types.go +28 -28
- package/linthost/rules_ts_no_unnecessary_boolean_literal_compare.go +87 -87
- package/linthost/rules_ts_no_unnecessary_condition.go +184 -184
- package/linthost/rules_ts_no_unnecessary_qualifier.go +72 -72
- package/linthost/rules_ts_no_unnecessary_template_expression.go +120 -120
- package/linthost/rules_ts_no_unnecessary_type_arguments.go +171 -171
- package/linthost/rules_ts_no_unnecessary_type_assertion.go +90 -90
- package/linthost/rules_ts_no_unsafe_argument.go +50 -50
- package/linthost/rules_ts_no_unsafe_assignment.go +60 -60
- package/linthost/rules_ts_no_unsafe_call.go +40 -40
- package/linthost/rules_ts_no_unsafe_enum_comparison.go +147 -147
- package/linthost/rules_ts_no_unsafe_member_access.go +29 -29
- package/linthost/rules_ts_no_unsafe_return.go +64 -64
- package/linthost/rules_ts_no_unsafe_unary_minus.go +42 -42
- package/linthost/rules_ts_no_useless_constructor.go +20 -20
- package/linthost/rules_ts_non_nullable_type_assertion_style.go +60 -60
- package/linthost/rules_ts_parameter_properties.go +10 -10
- package/linthost/rules_ts_prefer_find.go +116 -116
- package/linthost/rules_ts_prefer_includes.go +173 -173
- package/linthost/rules_ts_prefer_nullish_coalescing.go +54 -54
- package/linthost/rules_ts_prefer_optional_chain.go +156 -156
- package/linthost/rules_ts_prefer_promise_reject_errors.go +104 -104
- package/linthost/rules_ts_prefer_readonly.go +31 -31
- package/linthost/rules_ts_prefer_reduce_type_parameter.go +74 -74
- package/linthost/rules_ts_prefer_regexp_exec.go +69 -69
- package/linthost/rules_ts_prefer_return_this_type.go +79 -79
- package/linthost/rules_ts_prefer_string_starts_ends_with.go +237 -237
- package/linthost/rules_ts_promise_function_async.go +41 -41
- package/linthost/rules_ts_related_getter_setter_pairs.go +61 -61
- package/linthost/rules_ts_require_array_sort_compare.go +58 -58
- package/linthost/rules_ts_restrict_plus_operands.go +82 -82
- package/linthost/rules_ts_restrict_template_expressions.go +50 -50
- package/linthost/rules_ts_simple.go +249 -249
- package/linthost/rules_ts_sort_type_constituents.go +88 -88
- package/linthost/rules_ts_strict_boolean_expressions.go +103 -103
- package/linthost/rules_ts_switch_exhaustiveness_check.go +90 -90
- package/linthost/rules_ts_unbound_method.go +65 -65
- package/linthost/rules_tsdoc.go +88 -88
- package/linthost/rules_unicorn_better_regex.go +1 -1
- package/linthost/rules_unicorn_catch_error_name.go +19 -19
- package/linthost/rules_unicorn_consistent_assert.go +20 -20
- package/linthost/rules_unicorn_consistent_date_clone.go +27 -27
- package/linthost/rules_unicorn_consistent_destructuring.go +3 -3
- package/linthost/rules_unicorn_consistent_empty_array_spread.go +34 -34
- package/linthost/rules_unicorn_consistent_existence_index_check.go +42 -42
- package/linthost/rules_unicorn_consistent_function_scoping.go +3 -3
- package/linthost/rules_unicorn_consistent_template_literal_escape.go +3 -3
- package/linthost/rules_unicorn_custom_error_definition.go +92 -92
- package/linthost/rules_unicorn_empty_brace_spaces.go +47 -47
- package/linthost/rules_unicorn_error_message.go +34 -34
- package/linthost/rules_unicorn_escape_case.go +14 -14
- package/linthost/rules_unicorn_expiring_todo_comments.go +36 -36
- package/linthost/rules_unicorn_explicit_length_check.go +51 -51
- package/linthost/rules_unicorn_filename_case.go +1 -1
- package/linthost/rules_unicorn_import_style.go +1 -1
- package/linthost/rules_unicorn_isolated_functions.go +2 -2
- package/linthost/rules_unicorn_new_for_builtins.go +49 -49
- package/linthost/rules_unicorn_no_abusive_eslint_disable.go +31 -31
- package/linthost/rules_unicorn_no_accessor_recursion.go +69 -69
- package/linthost/rules_unicorn_no_anonymous_default_export.go +40 -40
- package/linthost/rules_unicorn_no_array_callback_reference.go +33 -33
- package/linthost/rules_unicorn_no_array_for_each.go +14 -14
- package/linthost/rules_unicorn_no_array_method_this_argument.go +29 -29
- package/linthost/rules_unicorn_no_array_reduce.go +15 -15
- package/linthost/rules_unicorn_no_array_reverse.go +17 -17
- package/linthost/rules_unicorn_no_array_sort.go +17 -17
- package/linthost/rules_unicorn_no_await_expression_member.go +12 -12
- package/linthost/rules_unicorn_no_await_in_promise_methods.go +38 -38
- package/linthost/rules_unicorn_no_console_spaces.go +30 -30
- package/linthost/rules_unicorn_no_document_cookie.go +13 -13
- package/linthost/rules_unicorn_no_empty_file.go +16 -16
- package/linthost/rules_unicorn_no_for_loop.go +58 -58
- package/linthost/rules_unicorn_no_hex_escape.go +11 -11
- package/linthost/rules_unicorn_no_immediate_mutation.go +55 -55
- package/linthost/rules_unicorn_no_instanceof_builtins.go +34 -34
- package/linthost/rules_unicorn_no_invalid_fetch_options.go +52 -52
- package/linthost/rules_unicorn_no_invalid_remove_event_listener.go +25 -25
- package/linthost/rules_unicorn_no_keyword_prefix.go +56 -56
- package/linthost/rules_unicorn_no_lonely_if.go +21 -21
- package/linthost/rules_unicorn_no_magic_array_flat_depth.go +22 -22
- package/linthost/rules_unicorn_no_named_default.go +25 -25
- package/linthost/rules_unicorn_no_negated_condition.go +54 -54
- package/linthost/rules_unicorn_no_negation_in_equality_check.go +23 -23
- package/linthost/rules_unicorn_no_nested_ternary.go +15 -15
- package/linthost/rules_unicorn_no_new_array.go +5 -5
- package/linthost/rules_unicorn_no_new_buffer.go +5 -5
- package/linthost/rules_unicorn_no_null.go +2 -2
- package/linthost/rules_unicorn_no_object_as_default_parameter.go +19 -19
- package/linthost/rules_unicorn_no_process_exit.go +17 -17
- package/linthost/rules_unicorn_no_single_promise_in_promise_methods.go +29 -29
- package/linthost/rules_unicorn_no_static_only_class.go +27 -27
- package/linthost/rules_unicorn_no_thenable.go +47 -47
- package/linthost/rules_unicorn_no_this_assignment.go +10 -10
- package/linthost/rules_unicorn_no_typeof_undefined.go +31 -31
- package/linthost/rules_unicorn_no_unnecessary_array_flat_depth.go +23 -23
- package/linthost/rules_unicorn_no_unnecessary_array_splice_count.go +37 -37
- package/linthost/rules_unicorn_no_unnecessary_await.go +24 -24
- package/linthost/rules_unicorn_no_unnecessary_slice_end.go +22 -22
- package/linthost/rules_unicorn_no_unreadable_array_destructuring.go +67 -67
- package/linthost/rules_unicorn_no_unreadable_iife.go +22 -22
- package/linthost/rules_unicorn_no_useless_collection_argument.go +34 -34
- package/linthost/rules_unicorn_no_useless_error_capture_stack_trace.go +18 -18
- package/linthost/rules_unicorn_no_useless_fallback_in_spread.go +49 -49
- package/linthost/rules_unicorn_no_useless_iterator_to_array.go +41 -41
- package/linthost/rules_unicorn_no_useless_length_check.go +82 -82
- package/linthost/rules_unicorn_no_useless_promise_resolve_reject.go +42 -42
- package/linthost/rules_unicorn_no_useless_spread.go +38 -38
- package/linthost/rules_unicorn_no_useless_switch_case.go +29 -29
- package/linthost/rules_unicorn_no_useless_undefined.go +25 -25
- package/linthost/rules_unicorn_no_zero_fractions.go +17 -17
- package/linthost/rules_unicorn_number_literal_case.go +33 -33
- package/linthost/rules_unicorn_numeric_separators_style.go +36 -36
- package/linthost/rules_unicorn_prefer_add_event_listener.go +30 -30
- package/linthost/rules_unicorn_prefer_array_find.go +27 -27
- package/linthost/rules_unicorn_prefer_array_flat.go +25 -25
- package/linthost/rules_unicorn_prefer_array_flat_map.go +37 -37
- package/linthost/rules_unicorn_prefer_array_index_of.go +108 -108
- package/linthost/rules_unicorn_prefer_array_some.go +43 -43
- package/linthost/rules_unicorn_prefer_at.go +42 -42
- package/linthost/rules_unicorn_prefer_bigint_literals.go +42 -42
- package/linthost/rules_unicorn_prefer_blob_reading_methods.go +15 -15
- package/linthost/rules_unicorn_prefer_class_fields.go +57 -57
- package/linthost/rules_unicorn_prefer_classlist_toggle.go +76 -76
- package/linthost/rules_unicorn_prefer_code_point.go +21 -21
- package/linthost/rules_unicorn_prefer_date_now.go +47 -47
- package/linthost/rules_unicorn_prefer_default_parameters.go +96 -96
- package/linthost/rules_unicorn_prefer_dom_node_append.go +14 -14
- package/linthost/rules_unicorn_prefer_dom_node_dataset.go +27 -27
- package/linthost/rules_unicorn_prefer_dom_node_remove.go +17 -17
- package/linthost/rules_unicorn_prefer_dom_node_text_content.go +11 -11
- package/linthost/rules_unicorn_prefer_event_target.go +10 -10
- package/linthost/rules_unicorn_prefer_export_from.go +99 -99
- package/linthost/rules_unicorn_prefer_global_this.go +91 -91
- package/linthost/rules_unicorn_prefer_import_meta_properties.go +38 -38
- package/linthost/rules_unicorn_prefer_includes.go +108 -108
- package/linthost/rules_unicorn_prefer_json_parse_buffer.go +37 -37
- package/linthost/rules_unicorn_prefer_keyboard_event_key.go +10 -10
- package/linthost/rules_unicorn_prefer_logical_operator_over_ternary.go +20 -20
- package/linthost/rules_unicorn_prefer_math_min_max.go +33 -33
- package/linthost/rules_unicorn_prefer_math_trunc.go +32 -32
- package/linthost/rules_unicorn_prefer_modern_dom_apis.go +18 -18
- package/linthost/rules_unicorn_prefer_modern_math_apis.go +38 -38
- package/linthost/rules_unicorn_prefer_module.go +22 -22
- package/linthost/rules_unicorn_prefer_native_coercion_functions.go +73 -73
- package/linthost/rules_unicorn_prefer_negative_index.go +46 -46
- package/linthost/rules_unicorn_prefer_node_protocol.go +90 -90
- package/linthost/rules_unicorn_prefer_number_properties.go +57 -57
- package/linthost/rules_unicorn_prefer_object_from_entries.go +26 -26
- package/linthost/rules_unicorn_prefer_optional_catch_binding.go +24 -24
- package/linthost/rules_unicorn_prefer_prototype_methods.go +25 -25
- package/linthost/rules_unicorn_prefer_query_selector.go +25 -25
- package/linthost/rules_unicorn_prefer_reflect_apply.go +10 -10
- package/linthost/rules_unicorn_prefer_regexp_test_rule.go +47 -47
- package/linthost/rules_unicorn_prefer_response_static_json.go +26 -26
- package/linthost/rules_unicorn_prefer_set_has.go +16 -16
- package/linthost/rules_unicorn_prefer_set_size.go +22 -22
- package/linthost/rules_unicorn_prefer_simple_condition_first.go +3 -3
- package/linthost/rules_unicorn_prefer_single_call.go +59 -59
- package/linthost/rules_unicorn_prefer_spread.go +24 -24
- package/linthost/rules_unicorn_prefer_string_raw.go +12 -12
- package/linthost/rules_unicorn_prefer_string_replace_all.go +46 -46
- package/linthost/rules_unicorn_prefer_string_slice.go +17 -17
- package/linthost/rules_unicorn_prefer_string_starts_ends_with.go +104 -104
- package/linthost/rules_unicorn_prefer_string_trim_start_end.go +21 -21
- package/linthost/rules_unicorn_prefer_structured_clone.go +36 -36
- package/linthost/rules_unicorn_prefer_switch.go +65 -65
- package/linthost/rules_unicorn_prefer_ternary.go +35 -35
- package/linthost/rules_unicorn_prefer_top_level_await.go +34 -34
- package/linthost/rules_unicorn_prefer_type_error.go +84 -84
- package/linthost/rules_unicorn_prevent_abbreviations.go +68 -68
- package/linthost/rules_unicorn_relative_url_style.go +19 -19
- package/linthost/rules_unicorn_require_array_join_separator.go +18 -18
- package/linthost/rules_unicorn_require_module_attributes.go +25 -25
- package/linthost/rules_unicorn_require_module_specifiers.go +28 -28
- package/linthost/rules_unicorn_require_number_to_fixed_digits_argument.go +18 -18
- package/linthost/rules_unicorn_require_post_message_target_origin.go +18 -18
- package/linthost/rules_unicorn_string_content.go +1 -1
- package/linthost/rules_unicorn_switch_case_braces.go +16 -16
- package/linthost/rules_unicorn_switch_case_break_position.go +3 -3
- package/linthost/rules_unicorn_template_indent.go +1 -1
- package/linthost/rules_unicorn_text_encoding_identifier_case.go +36 -36
- package/linthost/rules_unicorn_throw_new_error.go +30 -30
- package/linthost/rules_var.go +273 -3
- package/package.json +3 -3
- package/src/defaultFormat.ts +11 -7
- package/src/structures/ITtscLintConfig.ts +5 -5
- package/src/structures/TtscLintRuleSetting.ts +19 -19
- package/src/structures/{ITtscLintFormat.ts → format/ITtscLintFormat.ts} +48 -75
- package/src/structures/format/ITtscLintFormatJsDoc.ts +16 -0
- package/src/structures/format/ITtscLintFormatSortImports.ts +62 -0
- package/src/structures/format/index.ts +3 -0
- package/src/structures/index.ts +1 -1
- package/src/structures/rules/ITtscLintBoundariesRuleOptions.ts +20 -31
- package/src/structures/rules/ITtscLintBoundariesRules.ts +32 -36
- package/src/structures/rules/ITtscLintContributorRules.ts +6 -7
- package/src/structures/rules/ITtscLintCoreRules.ts +380 -408
- package/src/structures/rules/ITtscLintCypressRuleOptions.ts +5 -5
- package/src/structures/rules/ITtscLintCypressRules.ts +34 -38
- package/src/structures/rules/ITtscLintFunctionalRuleOptions.ts +28 -41
- package/src/structures/rules/ITtscLintFunctionalRules.ts +51 -56
- package/src/structures/rules/ITtscLintJestRules.ts +63 -74
- package/src/structures/rules/ITtscLintJsdocRules.ts +47 -54
- package/src/structures/rules/ITtscLintJsxA11yRules.ts +94 -102
- package/src/structures/rules/ITtscLintNextjsRules.ts +50 -55
- package/src/structures/rules/ITtscLintPlaywrightRules.ts +104 -122
- package/src/structures/rules/ITtscLintPromiseRules.ts +62 -71
- package/src/structures/rules/ITtscLintReactPerfRuleOptions.ts +4 -4
- package/src/structures/rules/ITtscLintReactPerfRules.ts +17 -19
- package/src/structures/rules/ITtscLintReactRuleOptions.ts +8 -10
- package/src/structures/rules/ITtscLintReactRules.ts +91 -104
- package/src/structures/rules/ITtscLintRegexpRules.ts +46 -54
- package/src/structures/rules/ITtscLintRuleOptionsMap.ts +7 -8
- package/src/structures/rules/ITtscLintSecurityRules.ts +45 -52
- package/src/structures/rules/ITtscLintSolidRules.ts +53 -56
- package/src/structures/rules/ITtscLintStorybookRuleOptions.ts +3 -4
- package/src/structures/rules/ITtscLintStorybookRules.ts +60 -69
- package/src/structures/rules/ITtscLintTanstackQueryRules.ts +31 -37
- package/src/structures/rules/ITtscLintTestingLibraryRuleOptions.ts +2 -3
- package/src/structures/rules/ITtscLintTestingLibraryRules.ts +102 -119
- package/src/structures/rules/ITtscLintTypeScriptRules.ts +460 -518
- package/src/structures/rules/ITtscLintVitestRules.ts +43 -51
- package/lib/structures/ITtscLintFormat.js.map +0 -1
- /package/lib/structures/{ITtscLintFormat.js → format/ITtscLintFormat.js} +0 -0
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
package linthost
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"strings"
|
|
5
|
+
|
|
6
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
7
|
+
shimscanner "github.com/microsoft/typescript-go/shim/scanner"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
// formatStatementSplit puts every statement in a statement list on its
|
|
11
|
+
// own physical line, mirroring Prettier's "one statement per line"
|
|
12
|
+
// layout. Prettier never leaves two statements sharing a source line,
|
|
13
|
+
// `const a = 1; let b = 2;` becomes two lines, and this rule is the
|
|
14
|
+
// always-on equivalent.
|
|
15
|
+
//
|
|
16
|
+
// Scope is every statement list the language produces: the SourceFile
|
|
17
|
+
// body, every Block and ModuleBlock, and the statement lists of `case`
|
|
18
|
+
// and `default` clauses. The rule registers for KindSourceFile and
|
|
19
|
+
// walks the subtree itself (like `format/sort-imports` and
|
|
20
|
+
// `format/jsdoc`), emitting one finding that may carry many TextEdits.
|
|
21
|
+
//
|
|
22
|
+
// Per-statement decision:
|
|
23
|
+
//
|
|
24
|
+
// 1. Find the statement's first non-trivia byte.
|
|
25
|
+
// 2. If it is the first non-whitespace byte on its physical line, the
|
|
26
|
+
// statement already starts its own line, abstain (that is
|
|
27
|
+
// `format/indent`'s surface).
|
|
28
|
+
// 3. Otherwise another statement precedes it on the same line. Replace
|
|
29
|
+
// the whitespace run immediately before the statement (back to the
|
|
30
|
+
// previous non-whitespace char) with EOL + indent(depth).
|
|
31
|
+
//
|
|
32
|
+
// Safety: abstain for a statement whose inter-statement gap holds a
|
|
33
|
+
// `//` or `/*` comment. Re-emitting EOL + indent over that gap would
|
|
34
|
+
// delete the comment, so the rule leaves the bytes untouched and a
|
|
35
|
+
// later pass (or the user) handles it.
|
|
36
|
+
//
|
|
37
|
+
// Idempotent: once each statement is alone on its line, step 2 abstains
|
|
38
|
+
// for all of them and the rule emits nothing.
|
|
39
|
+
type formatStatementSplit struct{}
|
|
40
|
+
|
|
41
|
+
// formatStatementSplitOptions carries the indentation + EOL settings the
|
|
42
|
+
// rule needs to synthesize the inserted line break. The JSON tags match
|
|
43
|
+
// the `format` block keys the config layer mirrors in (see
|
|
44
|
+
// `expandFormatBlock` in config_format.go).
|
|
45
|
+
type formatStatementSplitOptions struct {
|
|
46
|
+
TabWidth *int `json:"tabWidth"`
|
|
47
|
+
UseTabs *bool `json:"useTabs"`
|
|
48
|
+
EndOfLine *string `json:"endOfLine"`
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
func (formatStatementSplit) Name() string { return "format/statement-split" }
|
|
52
|
+
func (formatStatementSplit) IsFormat() bool { return true }
|
|
53
|
+
func (formatStatementSplit) Visits() []shimast.Kind {
|
|
54
|
+
return []shimast.Kind{shimast.KindSourceFile}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
func (formatStatementSplit) Check(ctx *Context, node *shimast.Node) {
|
|
58
|
+
if ctx == nil || ctx.File == nil {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
layout := loadFormatLayout(ctx)
|
|
62
|
+
src := ctx.File.Text()
|
|
63
|
+
var edits []TextEdit
|
|
64
|
+
forEachStatementInList(ctx.File, func(stmt *shimast.Node, depth int) {
|
|
65
|
+
// Empty statements (`;`) carry no content. Splitting each one onto
|
|
66
|
+
// its own line only multiplies blank-ish noise, so abstain.
|
|
67
|
+
if stmt.Kind == shimast.KindEmptyStatement {
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
start := shimscanner.SkipTrivia(src, stmt.Pos())
|
|
71
|
+
if start <= 0 || start > len(src) {
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
// Walk back over the whitespace run that precedes the statement.
|
|
75
|
+
ws := start
|
|
76
|
+
for ws > 0 && (src[ws-1] == ' ' || src[ws-1] == '\t') {
|
|
77
|
+
ws--
|
|
78
|
+
}
|
|
79
|
+
if ws == 0 || src[ws-1] == '\n' {
|
|
80
|
+
// First non-whitespace byte on its line already; that is
|
|
81
|
+
// `format/indent`'s job, not this rule's.
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
// Do not split a statement off a leading-semicolon ASI guard
|
|
85
|
+
// (`;(expr)`): the lone `;` before it is an empty-statement guard
|
|
86
|
+
// that format/orphan-semi intentionally merged onto this line, and
|
|
87
|
+
// re-splitting it would oscillate against that rule. The `;` is a
|
|
88
|
+
// guard (not a terminator like `foo();bar()`) when only whitespace
|
|
89
|
+
// precedes it back to the start of its line.
|
|
90
|
+
if src[ws-1] == ';' {
|
|
91
|
+
k := ws - 1
|
|
92
|
+
for k > 0 && (src[k-1] == ' ' || src[k-1] == '\t') {
|
|
93
|
+
k--
|
|
94
|
+
}
|
|
95
|
+
if k == 0 || src[k-1] == '\n' {
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// A block that opens right after its own `case`/`default` label
|
|
100
|
+
// (`case 2: {`) is not sharing a line with a preceding statement;
|
|
101
|
+
// the only thing before it is the clause label, and Prettier keeps
|
|
102
|
+
// the brace on the label line. Abstain so the rule does not break
|
|
103
|
+
// the block off into `case 2:\n{`.
|
|
104
|
+
if stmt.Kind == shimast.KindBlock && firstStatementAfterCaseLabel(stmt) {
|
|
105
|
+
return
|
|
106
|
+
}
|
|
107
|
+
// The gap between the previous statement and this one must be pure
|
|
108
|
+
// whitespace. A `//` or `/*` anywhere from the previous statement's
|
|
109
|
+
// end to this one would be eaten by the replacement, so abstain. The
|
|
110
|
+
// scan starts at the previous statement boundary, not at `ws`: a
|
|
111
|
+
// comment is non-whitespace, so a scan that begins at `ws` (the end
|
|
112
|
+
// of the immediate whitespace run) can never see it.
|
|
113
|
+
if gapHasComment(src, prevStatementEnd(src, ws), start) {
|
|
114
|
+
return
|
|
115
|
+
}
|
|
116
|
+
edits = append(edits, TextEdit{
|
|
117
|
+
Pos: ws,
|
|
118
|
+
End: start,
|
|
119
|
+
Text: layout.eol + layout.indent(depth),
|
|
120
|
+
})
|
|
121
|
+
})
|
|
122
|
+
if len(edits) == 0 {
|
|
123
|
+
return
|
|
124
|
+
}
|
|
125
|
+
ctx.ReportRangeFix(
|
|
126
|
+
edits[0].Pos,
|
|
127
|
+
edits[0].End,
|
|
128
|
+
"Each statement must begin on its own line.",
|
|
129
|
+
edits...,
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// gapHasComment reports whether the byte range [start, end) contains the
|
|
134
|
+
// opening bytes of a `//` or `/*` comment. The split rule abstains when
|
|
135
|
+
// the inter-statement gap carries a comment so its line-break insertion
|
|
136
|
+
// never deletes the comment.
|
|
137
|
+
func gapHasComment(src string, start, end int) bool {
|
|
138
|
+
if start < 0 {
|
|
139
|
+
start = 0
|
|
140
|
+
}
|
|
141
|
+
for i := start; i+1 < end && i+1 < len(src); i++ {
|
|
142
|
+
if src[i] == '/' && (src[i+1] == '/' || src[i+1] == '*') {
|
|
143
|
+
return true
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return false
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// prevStatementEnd returns the offset where the content preceding `stmt`
|
|
150
|
+
// on its line ends, used as the lower bound of the inter-statement gap
|
|
151
|
+
// scanned for comments. It locates `stmt` in its parent statement list
|
|
152
|
+
// and returns the previous sibling's end; for the first statement of a
|
|
153
|
+
// list it returns the parent owner's start (the `{`/`case:` boundary).
|
|
154
|
+
// The fallback walks back from `floor` to the previous non-whitespace
|
|
155
|
+
// byte so a comment-free caller still gets a sane lower bound.
|
|
156
|
+
func prevStatementEnd(src string, floor int) int {
|
|
157
|
+
// floor sits just past the whitespace run before the statement, i.e.
|
|
158
|
+
// immediately after the previous content's last byte. Walking back one
|
|
159
|
+
// byte lands inside that content; the gap to scan is everything from
|
|
160
|
+
// the start of the current line up to floor, but a comment belongs to
|
|
161
|
+
// this gap only when it follows the previous statement's terminator on
|
|
162
|
+
// the same line. Scanning from the line start would also catch a
|
|
163
|
+
// comment that belongs to an earlier statement, so bound the scan at
|
|
164
|
+
// the nearest preceding statement terminator (`;`, `}`) or label
|
|
165
|
+
// (`:`), or the line start, whichever comes first.
|
|
166
|
+
i := floor - 1
|
|
167
|
+
for i >= 0 {
|
|
168
|
+
c := src[i]
|
|
169
|
+
if c == '\n' {
|
|
170
|
+
return i + 1
|
|
171
|
+
}
|
|
172
|
+
if c == ';' || c == '}' || c == '{' || c == ':' {
|
|
173
|
+
return i + 1
|
|
174
|
+
}
|
|
175
|
+
i--
|
|
176
|
+
}
|
|
177
|
+
return 0
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// firstStatementAfterCaseLabel reports whether `stmt` is the first
|
|
181
|
+
// statement of a `case`/`default` clause. Such a statement follows only
|
|
182
|
+
// the clause label on its line, not a preceding statement, so the split
|
|
183
|
+
// rule must not break a block off its label (`case 2: {` stays intact).
|
|
184
|
+
func firstStatementAfterCaseLabel(stmt *shimast.Node) bool {
|
|
185
|
+
if stmt == nil || stmt.Parent == nil {
|
|
186
|
+
return false
|
|
187
|
+
}
|
|
188
|
+
parent := stmt.Parent
|
|
189
|
+
if parent.Kind != shimast.KindCaseClause && parent.Kind != shimast.KindDefaultClause {
|
|
190
|
+
return false
|
|
191
|
+
}
|
|
192
|
+
clause := parent.AsCaseOrDefaultClause()
|
|
193
|
+
if clause == nil || clause.Statements == nil || len(clause.Statements.Nodes) == 0 {
|
|
194
|
+
return false
|
|
195
|
+
}
|
|
196
|
+
return clause.Statements.Nodes[0] == stmt
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// formatLayout is the resolved indentation + EOL snapshot the structural
|
|
200
|
+
// format rules share. Defaults match Prettier: 2-space indent, spaces
|
|
201
|
+
// (not tabs), LF newlines.
|
|
202
|
+
type formatLayout struct {
|
|
203
|
+
tabWidth int
|
|
204
|
+
useTabs bool
|
|
205
|
+
eol string
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// indent returns the indentation string for `depth` nesting levels:
|
|
209
|
+
// `depth` tab characters when useTabs, otherwise `depth * tabWidth`
|
|
210
|
+
// spaces.
|
|
211
|
+
func (l formatLayout) indent(depth int) string {
|
|
212
|
+
if depth <= 0 {
|
|
213
|
+
return ""
|
|
214
|
+
}
|
|
215
|
+
if l.useTabs {
|
|
216
|
+
return strings.Repeat("\t", depth)
|
|
217
|
+
}
|
|
218
|
+
return strings.Repeat(" ", depth*l.tabWidth)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// loadFormatLayout decodes the shared tabWidth/useTabs/endOfLine options
|
|
222
|
+
// used by `format/statement-split` and `format/indent` and applies the
|
|
223
|
+
// Prettier defaults. Both rules carry the identical option struct shape,
|
|
224
|
+
// so the decode is funneled through the statement-split option struct.
|
|
225
|
+
func loadFormatLayout(ctx *Context) formatLayout {
|
|
226
|
+
var opts formatStatementSplitOptions
|
|
227
|
+
_ = ctx.DecodeOptions(&opts)
|
|
228
|
+
layout := formatLayout{tabWidth: 2, useTabs: false, eol: "\n"}
|
|
229
|
+
if opts.TabWidth != nil && *opts.TabWidth > 0 {
|
|
230
|
+
layout.tabWidth = *opts.TabWidth
|
|
231
|
+
}
|
|
232
|
+
if opts.UseTabs != nil {
|
|
233
|
+
layout.useTabs = *opts.UseTabs
|
|
234
|
+
}
|
|
235
|
+
if opts.EndOfLine != nil && *opts.EndOfLine == "crlf" {
|
|
236
|
+
layout.eol = "\r\n"
|
|
237
|
+
}
|
|
238
|
+
return layout
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// forEachStatementInList walks the file's AST and invokes `fn` once for
|
|
242
|
+
// every statement that lives directly inside a statement list, the
|
|
243
|
+
// SourceFile body, a Block, a ModuleBlock, or a case/default clause.
|
|
244
|
+
// `depth` is the nesting level used to compute indentation: one level
|
|
245
|
+
// per enclosing Block or ModuleBlock plus one per enclosing case/default
|
|
246
|
+
// clause. Top-level statements are depth 0.
|
|
247
|
+
//
|
|
248
|
+
// The SourceFile body's statements are visited at depth 0, then the walk
|
|
249
|
+
// recurses through the whole subtree via `ForEachChild`, bumping the
|
|
250
|
+
// depth on each statement-list owner it descends into. The rule's
|
|
251
|
+
// KindSourceFile registration therefore sees every nested statement
|
|
252
|
+
// without the engine dispatching one node kind at a time.
|
|
253
|
+
func forEachStatementInList(file *shimast.SourceFile, fn func(stmt *shimast.Node, depth int)) {
|
|
254
|
+
if file == nil || file.Statements == nil {
|
|
255
|
+
return
|
|
256
|
+
}
|
|
257
|
+
for _, stmt := range file.Statements.Nodes {
|
|
258
|
+
if stmt == nil {
|
|
259
|
+
continue
|
|
260
|
+
}
|
|
261
|
+
fn(stmt, 0)
|
|
262
|
+
}
|
|
263
|
+
walkStatementLists(file.AsNode(), file.Text(), 0, fn)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// blockStartsOwnLine reports whether a brace block opens on its own line, the
|
|
267
|
+
// `{` being the first non-whitespace byte of its physical line. A case/default
|
|
268
|
+
// body block written as `case X: {` shares the label's line (false); one
|
|
269
|
+
// written as `case X:` then `{` on the next line starts its own line (true).
|
|
270
|
+
// Prettier indents the former like a braceless `case X: stmt` (no extra level)
|
|
271
|
+
// but the latter like an ordinary nested block (one level deeper).
|
|
272
|
+
func blockStartsOwnLine(src string, block *shimast.Node) bool {
|
|
273
|
+
if block == nil {
|
|
274
|
+
return false
|
|
275
|
+
}
|
|
276
|
+
pos := shimscanner.SkipTrivia(src, block.Pos())
|
|
277
|
+
if pos < 0 || pos > len(src) {
|
|
278
|
+
return false
|
|
279
|
+
}
|
|
280
|
+
lineStart := lineStartOffset(src, pos)
|
|
281
|
+
for i := lineStart; i < pos; i++ {
|
|
282
|
+
if src[i] != ' ' && src[i] != '\t' {
|
|
283
|
+
return false
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return true
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// walkStatementLists recurses through `node`'s children. When it
|
|
290
|
+
// descends into a statement-list owner (Block, ModuleBlock, case/default
|
|
291
|
+
// clause) it bumps `depth` and invokes `fn` for each statement that
|
|
292
|
+
// owner directly holds, so a statement is always reported at the depth
|
|
293
|
+
// of the list it belongs to. The SourceFile body is visited by the
|
|
294
|
+
// caller, so this function only handles the nested owners.
|
|
295
|
+
//
|
|
296
|
+
// Some nodes are descend-only +1 frames: they are not statement lists
|
|
297
|
+
// themselves but their child statement lists nest one column deeper than
|
|
298
|
+
// the node. Two cases need this:
|
|
299
|
+
//
|
|
300
|
+
// - KindCaseBlock wraps a switch's clauses
|
|
301
|
+
// (SwitchStatement -> CaseBlock -> CaseClause -> statements). The
|
|
302
|
+
// braces sit one level under `switch`, and the clause body sits one
|
|
303
|
+
// level under `case:`, so a case-body statement is switchDepth+2.
|
|
304
|
+
// The clause's own +1 stacks on top of the CaseBlock's +1.
|
|
305
|
+
// - A class/interface/object-type-literal/object-literal body is not a
|
|
306
|
+
// statement list, but a member's method/constructor Block nests
|
|
307
|
+
// inside it. Without counting the body frame a method-body statement
|
|
308
|
+
// would land one column short (the member Block's +1 only), so
|
|
309
|
+
// already-correct 4-space class bodies would be rewritten to 2.
|
|
310
|
+
func walkStatementLists(node *shimast.Node, src string, depth int, fn func(stmt *shimast.Node, depth int)) {
|
|
311
|
+
if node == nil {
|
|
312
|
+
return
|
|
313
|
+
}
|
|
314
|
+
node.ForEachChild(func(child *shimast.Node) bool {
|
|
315
|
+
if child == nil {
|
|
316
|
+
return false
|
|
317
|
+
}
|
|
318
|
+
childDepth := depth
|
|
319
|
+
switch child.Kind {
|
|
320
|
+
case shimast.KindBlock, shimast.KindModuleBlock:
|
|
321
|
+
childDepth = depth + 1
|
|
322
|
+
// A same-line `case X: { stmt }` block does not add an indent level:
|
|
323
|
+
// Prettier indents it exactly like a braceless `case X: stmt`, the
|
|
324
|
+
// clause having already contributed the level. A block written on its
|
|
325
|
+
// OWN line under the clause (`case X:` then `{` on the next line) is an
|
|
326
|
+
// ordinary nested block and keeps its extra level, so only collapse the
|
|
327
|
+
// same-line form.
|
|
328
|
+
if child.Kind == shimast.KindBlock && child.Parent != nil &&
|
|
329
|
+
(child.Parent.Kind == shimast.KindCaseClause ||
|
|
330
|
+
child.Parent.Kind == shimast.KindDefaultClause) &&
|
|
331
|
+
!blockStartsOwnLine(src, child) {
|
|
332
|
+
childDepth = depth
|
|
333
|
+
}
|
|
334
|
+
for _, stmt := range child.Statements() {
|
|
335
|
+
if stmt == nil {
|
|
336
|
+
continue
|
|
337
|
+
}
|
|
338
|
+
fn(stmt, childDepth)
|
|
339
|
+
}
|
|
340
|
+
case shimast.KindCaseClause, shimast.KindDefaultClause:
|
|
341
|
+
childDepth = depth + 1
|
|
342
|
+
clause := child.AsCaseOrDefaultClause()
|
|
343
|
+
if clause != nil && clause.Statements != nil {
|
|
344
|
+
for _, stmt := range clause.Statements.Nodes {
|
|
345
|
+
if stmt == nil {
|
|
346
|
+
continue
|
|
347
|
+
}
|
|
348
|
+
fn(stmt, childDepth)
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
case shimast.KindCaseBlock,
|
|
352
|
+
shimast.KindClassDeclaration,
|
|
353
|
+
shimast.KindClassExpression,
|
|
354
|
+
shimast.KindInterfaceDeclaration,
|
|
355
|
+
shimast.KindTypeLiteral,
|
|
356
|
+
shimast.KindObjectLiteralExpression:
|
|
357
|
+
// Descend-only +1 frame: not a visited statement list, but its
|
|
358
|
+
// nested statement lists sit one column deeper.
|
|
359
|
+
childDepth = depth + 1
|
|
360
|
+
}
|
|
361
|
+
walkStatementLists(child, src, childDepth, fn)
|
|
362
|
+
return false
|
|
363
|
+
})
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
func init() {
|
|
367
|
+
Register(formatStatementSplit{})
|
|
368
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
package linthost
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
5
|
+
shimscanner "github.com/microsoft/typescript-go/shim/scanner"
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
// formatTernaryNullishParens parenthesizes a `??` expression used as the
|
|
9
|
+
// condition, consequent, or alternate of a conditional expression,
|
|
10
|
+
// matching Prettier 3. TypeScript permits an unparenthesized `??` in
|
|
11
|
+
// those positions (unlike `??` mixed with `||`/`&&`), but Prettier 3
|
|
12
|
+
// always adds the parens for clarity:
|
|
13
|
+
//
|
|
14
|
+
// cond ? a ?? b : c -> cond ? (a ?? b) : c
|
|
15
|
+
// a ?? b ? c : d -> (a ?? b) ? c : d
|
|
16
|
+
//
|
|
17
|
+
// Only `??` is wrapped; `||` and `&&` operands are left bare. The wrap is
|
|
18
|
+
// width-independent (it applies even when the ternary fits on one line),
|
|
19
|
+
// so it is a normalization rule rather than part of the print-width
|
|
20
|
+
// reflow. Idempotent: a wrapped operand parses as a parenthesized
|
|
21
|
+
// expression, not a bare `??`, so the next pass leaves it alone.
|
|
22
|
+
type formatTernaryNullishParens struct{}
|
|
23
|
+
|
|
24
|
+
func (formatTernaryNullishParens) Name() string { return "format/ternary-nullish-parens" }
|
|
25
|
+
func (formatTernaryNullishParens) IsFormat() bool { return true }
|
|
26
|
+
|
|
27
|
+
func (formatTernaryNullishParens) Visits() []shimast.Kind {
|
|
28
|
+
return []shimast.Kind{shimast.KindConditionalExpression}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
func (formatTernaryNullishParens) Check(ctx *Context, node *shimast.Node) {
|
|
32
|
+
if ctx == nil || ctx.File == nil || node == nil {
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
cond := node.AsConditionalExpression()
|
|
36
|
+
if cond == nil {
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
src := ctx.File.Text()
|
|
40
|
+
var edits []TextEdit
|
|
41
|
+
for _, operand := range []*shimast.Node{cond.Condition, cond.WhenTrue, cond.WhenFalse} {
|
|
42
|
+
if !isBareNullishCoalescing(operand) {
|
|
43
|
+
continue
|
|
44
|
+
}
|
|
45
|
+
start := shimscanner.SkipTrivia(src, operand.Pos())
|
|
46
|
+
end := operand.End()
|
|
47
|
+
if start < 0 || end < start || end > len(src) {
|
|
48
|
+
continue
|
|
49
|
+
}
|
|
50
|
+
edits = append(edits, TextEdit{Pos: start, End: end, Text: "(" + src[start:end] + ")"})
|
|
51
|
+
}
|
|
52
|
+
if len(edits) == 0 {
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
ctx.ReportRangeFix(
|
|
56
|
+
edits[0].Pos,
|
|
57
|
+
edits[0].End,
|
|
58
|
+
"Parenthesize a nullish-coalescing operand of a conditional expression.",
|
|
59
|
+
edits...,
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// isBareNullishCoalescing reports whether `node` is an unparenthesized
|
|
64
|
+
// `a ?? b` binary expression.
|
|
65
|
+
func isBareNullishCoalescing(node *shimast.Node) bool {
|
|
66
|
+
if node == nil || node.Kind != shimast.KindBinaryExpression {
|
|
67
|
+
return false
|
|
68
|
+
}
|
|
69
|
+
bin := node.AsBinaryExpression()
|
|
70
|
+
return bin != nil &&
|
|
71
|
+
bin.OperatorToken != nil &&
|
|
72
|
+
bin.OperatorToken.Kind == shimast.KindQuestionQuestionToken
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
func init() {
|
|
76
|
+
Register(formatTernaryNullishParens{})
|
|
77
|
+
}
|
|
@@ -5,7 +5,7 @@ import (
|
|
|
5
5
|
)
|
|
6
6
|
|
|
7
7
|
// formatTrailingComma adds trailing commas to multi-line lists. Mirrors
|
|
8
|
-
// prettier's `trailingComma: "all"` default
|
|
8
|
+
// prettier's `trailingComma: "all"` default, *not* a tunable.
|
|
9
9
|
//
|
|
10
10
|
// Scope (intentionally narrower than the closing-brace surface of TS):
|
|
11
11
|
//
|
|
@@ -109,6 +109,14 @@ func (formatTrailingComma) Check(ctx *Context, node *shimast.Node) {
|
|
|
109
109
|
if call == nil {
|
|
110
110
|
return
|
|
111
111
|
}
|
|
112
|
+
if isDynamicImportCall(call) {
|
|
113
|
+
// Prettier never emits a trailing comma inside a dynamic
|
|
114
|
+
// `import(...)` argument list, even under trailingComma:"all", a
|
|
115
|
+
// documented exception because the import() spec historically
|
|
116
|
+
// rejected one. The printer half (print_nodes_call.go) honors the
|
|
117
|
+
// same exception so the two rules agree on the reflowed shape.
|
|
118
|
+
return
|
|
119
|
+
}
|
|
112
120
|
considerTrailingComma(ctx, call.Arguments, node.End()-1)
|
|
113
121
|
case shimast.KindNewExpression:
|
|
114
122
|
if mode == "es5" {
|
|
@@ -268,12 +276,23 @@ func (formatTrailingComma) Check(ctx *Context, node *shimast.Node) {
|
|
|
268
276
|
}
|
|
269
277
|
}
|
|
270
278
|
|
|
279
|
+
// isDynamicImportCall reports whether a CallExpression is a dynamic
|
|
280
|
+
// `import(...)`: its callee is the `import` keyword itself, mirroring
|
|
281
|
+
// typescript-go's ast.IsImportCall. Prettier never emits a trailing
|
|
282
|
+
// comma inside a dynamic-import argument list, even under
|
|
283
|
+
// trailingComma:"all".
|
|
284
|
+
func isDynamicImportCall(call *shimast.CallExpression) bool {
|
|
285
|
+
return call != nil &&
|
|
286
|
+
call.Expression != nil &&
|
|
287
|
+
call.Expression.Kind == shimast.KindImportKeyword
|
|
288
|
+
}
|
|
289
|
+
|
|
271
290
|
// considerTrailingComma reports a fix when the bracket-delimited list is
|
|
272
291
|
// multi-line and missing its trailing comma. `closeBracketPos` points at
|
|
273
292
|
// the closing punctuation byte itself (e.g. the `]` of an array literal).
|
|
274
293
|
//
|
|
275
294
|
// "Multi-line" means the close bracket sits on a different line from the
|
|
276
|
-
// last element's end
|
|
295
|
+
// last element's end, not just "the list contains a newline somewhere".
|
|
277
296
|
// Prettier's `trailingComma: "all"` omits the comma whenever the close
|
|
278
297
|
// bracket is adjacent to the last element on the same line, even if the
|
|
279
298
|
// element itself is internally multi-line. The canonical shape is
|