@ttsc/lint 0.14.0-dev.20260529.2 → 0.14.1
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 +23 -25
- 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 +167 -5
- package/linthost/print_nodes_call.go +786 -77
- package/linthost/print_nodes_function.go +43 -0
- package/linthost/print_nodes_imports.go +64 -14
- package/linthost/print_nodes_list.go +214 -8
- package/linthost/print_nodes_object.go +14 -6
- package/linthost/print_nodes_ternary.go +147 -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 +213 -0
- package/linthost/rules_format_bracket_spacing.go +117 -0
- package/linthost/rules_format_clause_join.go +179 -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 +180 -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 +517 -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
|
@@ -113,6 +113,16 @@ func printParenthesizedExpression(ctx *PrintContext, node *shimast.Node) (Doc, b
|
|
|
113
113
|
if paren == nil || paren.Expression == nil {
|
|
114
114
|
return verbatim(ctx, node), !nodeSpansMultipleLines(ctx, node)
|
|
115
115
|
}
|
|
116
|
+
// A comment around the parens (`(/* c */ x)`, `(x /* c */)`) would be dropped
|
|
117
|
+
// by the minted `(`/`)` — the parens are not AST children, so a nested
|
|
118
|
+
// ParenthesizedExpression's gap comment slips past the top-level print-width
|
|
119
|
+
// scan and is lost on reflow. Bail to verbatim and report UNCOVERED (hard
|
|
120
|
+
// `false`, not `!nodeSpansMultipleLines`) so an enclosing reflow abstains
|
|
121
|
+
// instead of breaking around this single-line verbatim paren, like the
|
|
122
|
+
// object/array/call printers.
|
|
123
|
+
if listHasInterItemComments(ctx, node) {
|
|
124
|
+
return verbatim(ctx, node), false
|
|
125
|
+
}
|
|
116
126
|
inner, covered := PrintNode(ctx, paren.Expression)
|
|
117
127
|
return Concat(Text("("), inner, Text(")")), covered
|
|
118
128
|
}
|
|
@@ -180,6 +190,16 @@ func printBlock(ctx *PrintContext, node *shimast.Node) (Doc, bool) {
|
|
|
180
190
|
bodyParts := make([]Doc, 0, len(items)*2)
|
|
181
191
|
for i, item := range items {
|
|
182
192
|
if i > 0 {
|
|
193
|
+
// A lone leading-semicolon ASI guard stays glued to the statement
|
|
194
|
+
// it protects (`;(expr)`): when the previous statement is an empty
|
|
195
|
+
// `;` sitting directly against this one in the source, emit no line
|
|
196
|
+
// break, so the reflow agrees with format/orphan-semi instead of
|
|
197
|
+
// ping-ponging it back onto two lines every cascade pass.
|
|
198
|
+
if stmts[i-1].Kind == shimast.KindEmptyStatement &&
|
|
199
|
+
!rangeHasNewline(ctx.Source, stmts[i-1].End(), shimscanner.SkipTrivia(ctx.Source, stmts[i].Pos())) {
|
|
200
|
+
bodyParts = append(bodyParts, item)
|
|
201
|
+
continue
|
|
202
|
+
}
|
|
183
203
|
if blankLineBetweenStatements(ctx.Source, stmts[i-1].End(), stmts[i].Pos()) {
|
|
184
204
|
bodyParts = append(bodyParts, Literalline())
|
|
185
205
|
}
|
|
@@ -196,6 +216,21 @@ func printBlock(ctx *PrintContext, node *shimast.Node) (Doc, bool) {
|
|
|
196
216
|
return doc, covered
|
|
197
217
|
}
|
|
198
218
|
|
|
219
|
+
// rangeHasNewline reports whether src[start:end) contains a newline. Used
|
|
220
|
+
// to detect whether a leading-semicolon guard sits on the same line as
|
|
221
|
+
// the statement it protects.
|
|
222
|
+
func rangeHasNewline(src string, start, end int) bool {
|
|
223
|
+
if start < 0 || end > len(src) || end <= start {
|
|
224
|
+
return false
|
|
225
|
+
}
|
|
226
|
+
for i := start; i < end; i++ {
|
|
227
|
+
if src[i] == '\n' {
|
|
228
|
+
return true
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return false
|
|
232
|
+
}
|
|
233
|
+
|
|
199
234
|
// blankLineBetweenStatements reports whether the source gap between the
|
|
200
235
|
// end of one block statement and the start of the next contains a blank
|
|
201
236
|
// line — two or more newlines. printBlock uses it to keep a single
|
|
@@ -319,6 +354,14 @@ func printReturnStatement(ctx *PrintContext, node *shimast.Node) (Doc, bool) {
|
|
|
319
354
|
if !tailIsCleanTerminator(ctx.Source, stmt.Expression.End(), node.End()) {
|
|
320
355
|
return verbatim(ctx, node), !nodeSpansMultipleLines(ctx, node)
|
|
321
356
|
}
|
|
357
|
+
// A comment between `return` and its argument (`return /* c */ x`) lives in
|
|
358
|
+
// the argument's leading trivia and would be dropped by the minted
|
|
359
|
+
// `Text("return ")` — the gap is not an AST child, and a return statement is
|
|
360
|
+
// only reached as a nested child of a block, so the outer print-width and
|
|
361
|
+
// block scans mask it. Bail to verbatim (uncovered) like the round-7 printers.
|
|
362
|
+
if gapHasComment(ctx.Source, stmt.Expression.Pos(), shimscanner.SkipTrivia(ctx.Source, stmt.Expression.Pos())) {
|
|
363
|
+
return verbatim(ctx, node), !nodeSpansMultipleLines(ctx, node)
|
|
364
|
+
}
|
|
322
365
|
exprDoc, covered := PrintNode(ctx, stmt.Expression)
|
|
323
366
|
parts := []Doc{Text("return "), exprDoc}
|
|
324
367
|
if sourceHasStatementTerminator(ctx.Source, node.End()) {
|
|
@@ -2,6 +2,7 @@ package linthost
|
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
4
|
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
5
|
+
shimscanner "github.com/microsoft/typescript-go/shim/scanner"
|
|
5
6
|
)
|
|
6
7
|
|
|
7
8
|
// printNamedImports renders `{ a, b, c }` inside an import declaration.
|
|
@@ -115,39 +116,88 @@ func printImportDeclaration(ctx *PrintContext, node *shimast.Node) (Doc, bool) {
|
|
|
115
116
|
if clauseData == nil || clauseData.NamedBindings == nil {
|
|
116
117
|
return verbatim(ctx, node), !nodeSpansMultipleLines(ctx, node)
|
|
117
118
|
}
|
|
118
|
-
|
|
119
|
+
nb := clauseData.NamedBindings
|
|
120
|
+
if nb.Kind != shimast.KindNamedImports {
|
|
119
121
|
// Namespace imports (`import * as ns from "x"`) have no
|
|
120
122
|
// reflow surface; leave them alone.
|
|
121
123
|
return verbatim(ctx, node), !nodeSpansMultipleLines(ctx, node)
|
|
122
124
|
}
|
|
123
|
-
if clause.Name() != nil {
|
|
124
|
-
// `import Default, { … } from "x"` — keep verbatim for v1.
|
|
125
|
-
return verbatim(ctx, node), !nodeSpansMultipleLines(ctx, node)
|
|
126
|
-
}
|
|
127
125
|
// AttributeClause (`with { ... }` / `assert { ... }`) lives after
|
|
128
126
|
// the module specifier. Fall back to verbatim when present so we
|
|
129
127
|
// don't drop attributes silently.
|
|
130
128
|
if imp.Attributes != nil {
|
|
131
129
|
return verbatim(ctx, node), !nodeSpansMultipleLines(ctx, node)
|
|
132
130
|
}
|
|
131
|
+
// A comment between specifiers would be dropped by the fresh separators.
|
|
132
|
+
if listHasInterItemComments(ctx, nb) {
|
|
133
|
+
return verbatim(ctx, node), !nodeSpansMultipleLines(ctx, node)
|
|
134
|
+
}
|
|
135
|
+
ni := nb.AsNamedImports()
|
|
136
|
+
if ni == nil || ni.Elements == nil {
|
|
137
|
+
return verbatim(ctx, node), !nodeSpansMultipleLines(ctx, node)
|
|
138
|
+
}
|
|
133
139
|
|
|
134
|
-
// Bracketed clause prefix: `import `
|
|
140
|
+
// Bracketed clause prefix: `import `, `import type `, or — when a default
|
|
141
|
+
// binding precedes the named clause — `import Default, `. A default never
|
|
142
|
+
// combines with `type` (TS forbids `import type D, { … }`), so the two
|
|
143
|
+
// prefix forms are exclusive.
|
|
135
144
|
prefix := "import "
|
|
136
145
|
if clause.IsTypeOnly() {
|
|
146
|
+
// A comment in the `type`->`{` gap (`import type /* c */ { … }`) would be
|
|
147
|
+
// dropped by the minted prefix. The `type` keyword is a clause modifier
|
|
148
|
+
// flag, not a child node, so the top-level scan masks it (it sits inside the
|
|
149
|
+
// ImportClause span) and the `nb`-scoped guard starts at `{`. Bail to
|
|
150
|
+
// verbatim, like the default-binding gap below.
|
|
151
|
+
if gapHasComment(ctx.Source, shimscanner.SkipTrivia(ctx.Source, clause.Pos()), shimscanner.SkipTrivia(ctx.Source, nb.Pos())) {
|
|
152
|
+
return verbatim(ctx, node), !nodeSpansMultipleLines(ctx, node)
|
|
153
|
+
}
|
|
137
154
|
prefix = "import type "
|
|
138
155
|
}
|
|
139
|
-
|
|
156
|
+
if name := clause.Name(); name != nil {
|
|
157
|
+
// A comment in the default-binding-to-brace gap (`import D /* c */, { … }`)
|
|
158
|
+
// would be dropped by the minted `, ` prefix. That gap is not a direct child
|
|
159
|
+
// of the import node, so the top-level scan masks it and the `nb`-scoped
|
|
160
|
+
// guard above starts at `{` — same class as printReturnStatement's leading
|
|
161
|
+
// gap. Bail to verbatim.
|
|
162
|
+
if gapHasComment(ctx.Source, name.End(), shimscanner.SkipTrivia(ctx.Source, nb.Pos())) {
|
|
163
|
+
return verbatim(ctx, node), !nodeSpansMultipleLines(ctx, node)
|
|
164
|
+
}
|
|
165
|
+
prefix = "import " + identifierText(name) + ", "
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
items := make([]Doc, 0, len(ni.Elements.Nodes))
|
|
169
|
+
covered := true
|
|
170
|
+
for _, spec := range ni.Elements.Nodes {
|
|
171
|
+
if spec == nil {
|
|
172
|
+
return verbatim(ctx, node), !nodeSpansMultipleLines(ctx, node)
|
|
173
|
+
}
|
|
174
|
+
doc, childCovered := PrintNode(ctx, spec)
|
|
175
|
+
covered = covered && childCovered
|
|
176
|
+
items = append(items, doc)
|
|
177
|
+
}
|
|
178
|
+
|
|
140
179
|
moduleSpec := verbatim(ctx, imp.ModuleSpecifier)
|
|
141
180
|
covered = covered && !nodeSpansMultipleLines(ctx, imp.ModuleSpecifier)
|
|
142
|
-
|
|
181
|
+
suffixParts := []Doc{Text(" from "), moduleSpec}
|
|
143
182
|
if sourceHasStatementTerminator(ctx.Source, node.End()) {
|
|
144
|
-
// Preserve the user's terminator decision. Emitting `;`
|
|
145
|
-
//
|
|
146
|
-
|
|
147
|
-
// `;;` — `format/semi` owns terminator placement.
|
|
148
|
-
parts = append(parts, Text(";"))
|
|
183
|
+
// Preserve the user's terminator decision. Emitting `;` unconditionally
|
|
184
|
+
// would collide with `format/semi`'s zero-width insert and produce `;;`.
|
|
185
|
+
suffixParts = append(suffixParts, Text(";"))
|
|
149
186
|
}
|
|
150
|
-
|
|
187
|
+
|
|
188
|
+
// The whole declaration renders as one Group via Prefix/Suffix, so the
|
|
189
|
+
// named-brace break decision counts the ` from "..."` tail: a brace that
|
|
190
|
+
// fits but whose declaration line overflows still breaks, and a
|
|
191
|
+
// default-combined import breaks its brace too.
|
|
192
|
+
return printList(ctx, listShape{
|
|
193
|
+
Prefix: Text(prefix),
|
|
194
|
+
OpenTok: "{",
|
|
195
|
+
CloseTok: "}",
|
|
196
|
+
Items: items,
|
|
197
|
+
Space: true,
|
|
198
|
+
AddComma: ctx.allowsEs5TrailingComma(),
|
|
199
|
+
Suffix: Concat(suffixParts...),
|
|
200
|
+
}), covered
|
|
151
201
|
}
|
|
152
202
|
|
|
153
203
|
// sourceHasStatementTerminator reports whether the last non-trivia
|
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
package linthost
|
|
2
2
|
|
|
3
|
+
import (
|
|
4
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
5
|
+
shimscanner "github.com/microsoft/typescript-go/shim/scanner"
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
// listHasInterItemComments reports whether `node` (an object / array literal)
|
|
9
|
+
// carries a comment in a gap between its items or brackets. The list printers
|
|
10
|
+
// mint fresh comma/line separators that have no slot for such trivia, so a
|
|
11
|
+
// reflow would silently delete the comment. When a node nested inside a
|
|
12
|
+
// reflowing parent (an array argument of a call) carries one, the parent's
|
|
13
|
+
// own top-level comment guard cannot see it (it lives inside a child range),
|
|
14
|
+
// so each list printer must check itself and bail to verbatim — reporting the
|
|
15
|
+
// span uncovered so the enclosing reflow abstains and the source round-trips.
|
|
16
|
+
func listHasInterItemComments(ctx *PrintContext, node *shimast.Node) bool {
|
|
17
|
+
if node == nil {
|
|
18
|
+
return false
|
|
19
|
+
}
|
|
20
|
+
start := shimscanner.SkipTrivia(ctx.Source, node.Pos())
|
|
21
|
+
end := node.End()
|
|
22
|
+
if start < 0 || end < start || end > len(ctx.Source) {
|
|
23
|
+
return false
|
|
24
|
+
}
|
|
25
|
+
return hasNonChildComments(node, ctx.Source, start, end)
|
|
26
|
+
}
|
|
27
|
+
|
|
3
28
|
// Shared helpers for comma-separated list printers.
|
|
4
29
|
//
|
|
5
30
|
// Object literals, array literals, call arguments, parameter lists,
|
|
@@ -35,11 +60,87 @@ type listShape struct {
|
|
|
35
60
|
// multi-line callback body does not force every preceding argument
|
|
36
61
|
// onto its own line.
|
|
37
62
|
HugLast bool
|
|
63
|
+
// HugFirst keeps the FIRST item attached to the open paren and flows
|
|
64
|
+
// the remaining simple items after it, the mirror of HugLast. The
|
|
65
|
+
// call-argument printer sets it for the two-argument
|
|
66
|
+
// `callback, simpleArg` shape Prettier hugs (`foo(() => { … }, x)`).
|
|
67
|
+
// HugLast and HugFirst are mutually exclusive.
|
|
68
|
+
HugFirst bool
|
|
69
|
+
// HugFirstTrailingBreaks tells printListHuggingFirst NOT to flatten the
|
|
70
|
+
// trailing item, letting it render through its own breakable group. The
|
|
71
|
+
// call-argument printer sets it for the React-hook deps shape
|
|
72
|
+
// (`useEffect(() => { … }, [deps])`), whose deps array Prettier breaks
|
|
73
|
+
// one-element-per-line when it overflows rather than pinning it flat on the
|
|
74
|
+
// close line. The short leaf/call trailing args of every other first-arg-hug
|
|
75
|
+
// case still flatten (they ride the close line flat, per Prettier).
|
|
76
|
+
HugFirstTrailingBreaks bool
|
|
77
|
+
// HugFirstForce drops the exploded fallback from a HugFirst list, the mirror
|
|
78
|
+
// of HugLastForce. The call-argument printer sets it for a genuine React-hook
|
|
79
|
+
// deps call (`useEffect(() => { … }, [deps])`: a zero-parameter block-bodied
|
|
80
|
+
// arrow plus an array literal), which Prettier's isReactHookCallWithDepsArray
|
|
81
|
+
// path never explodes — it keeps the callback hugged and lets the open line
|
|
82
|
+
// overflow. Distinct from HugFirstTrailingBreaks, which also fires for a
|
|
83
|
+
// parameterized callback whose empty-array second arg DOES keep the fallback.
|
|
84
|
+
HugFirstForce bool
|
|
85
|
+
// HugLastForce drops the exploded fallback from a HugLast list: the hugged
|
|
86
|
+
// shape is chosen even when its opening line overflows printWidth. The
|
|
87
|
+
// call-argument printer sets it for a test-framework call
|
|
88
|
+
// (`test("very long description", () => { … })`), which Prettier never
|
|
89
|
+
// explodes — the callback always rides the open paren. Requires HugLast.
|
|
90
|
+
HugLastForce bool
|
|
38
91
|
// ForceBreak commits the list to its broken, one-item-per-line shape
|
|
39
92
|
// even when it would fit flat. The object-literal printer sets it to
|
|
40
93
|
// mirror Prettier's objectWrap:"preserve" — an object the source
|
|
41
94
|
// wrote with a newline after `{` stays expanded.
|
|
42
95
|
ForceBreak bool
|
|
96
|
+
// Fill packs the items with Prettier's fill layout — as many per line as
|
|
97
|
+
// fit — instead of one item per line when the list breaks. The array
|
|
98
|
+
// printer sets it for a concisely-printed numeric array. Mutually
|
|
99
|
+
// exclusive with HugLast / HugFirst.
|
|
100
|
+
Fill bool
|
|
101
|
+
// Prefix and Suffix are emitted inside the list's Group, before OpEN and
|
|
102
|
+
// after CLOSE respectively. They let a caller fold surrounding tokens into
|
|
103
|
+
// the same fit-or-break decision: an import declaration sets Prefix to
|
|
104
|
+
// `import ` (or `import D, `) and Suffix to ` from "..."` so the named-brace
|
|
105
|
+
// group's flat-fit check counts the whole declaration line — Prettier never
|
|
106
|
+
// breaks a brace that fits but whose `from` tail overflows is measured here,
|
|
107
|
+
// not in a separate group. Only used on the plain (non-hugging) path.
|
|
108
|
+
Prefix Doc
|
|
109
|
+
Suffix Doc
|
|
110
|
+
// BlankBefore[i] reports whether the source had a blank line before item i
|
|
111
|
+
// (i.e. between item i-1 and item i). When any entry is set the list is
|
|
112
|
+
// forced broken and a single blank line is preserved before that item,
|
|
113
|
+
// mirroring Prettier. Length, when non-nil, equals len(Items); index 0 is
|
|
114
|
+
// ignored (no item precedes the first).
|
|
115
|
+
BlankBefore []bool
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// blankBeforeItems computes BlankBefore for a node list: entry i is true when
|
|
119
|
+
// the source had a blank line (two or more newlines) between item i-1 and
|
|
120
|
+
// item i. Returns nil for a list too short to carry one, so callers pass it
|
|
121
|
+
// through unconditionally.
|
|
122
|
+
func blankBeforeItems(src string, elems []*shimast.Node) []bool {
|
|
123
|
+
if len(elems) < 2 {
|
|
124
|
+
return nil
|
|
125
|
+
}
|
|
126
|
+
out := make([]bool, len(elems))
|
|
127
|
+
for i := 1; i < len(elems); i++ {
|
|
128
|
+
if elems[i-1] == nil || elems[i] == nil {
|
|
129
|
+
continue
|
|
130
|
+
}
|
|
131
|
+
out[i] = blankLineBetweenStatements(src, elems[i-1].End(), elems[i].Pos())
|
|
132
|
+
}
|
|
133
|
+
return out
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// hasBlankBefore reports whether any item carries a preserved blank line.
|
|
137
|
+
func (s listShape) hasBlankBefore() bool {
|
|
138
|
+
for _, b := range s.BlankBefore {
|
|
139
|
+
if b {
|
|
140
|
+
return true
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return false
|
|
43
144
|
}
|
|
44
145
|
|
|
45
146
|
// printList renders the list shape as a Doc tree. Empty lists collapse
|
|
@@ -50,19 +151,35 @@ func printList(ctx *PrintContext, shape listShape) Doc {
|
|
|
50
151
|
return Text(shape.OpenTok + shape.CloseTok)
|
|
51
152
|
}
|
|
52
153
|
plain := printListPlain(ctx, shape)
|
|
53
|
-
|
|
154
|
+
// A source blank line forces the plain broken layout (Prettier never hugs or
|
|
155
|
+
// packs flat across a blank line), so skip the hugging ConditionalGroup.
|
|
156
|
+
if (!shape.HugLast && !shape.HugFirst) || shape.hasBlankBefore() {
|
|
54
157
|
return plain
|
|
55
158
|
}
|
|
56
|
-
// A
|
|
159
|
+
// A hugging list offers the engine up to three shapes, in preference
|
|
57
160
|
// order:
|
|
58
161
|
// 1. allFlat — every item on one line, chosen when it fits;
|
|
59
|
-
// 2. hugged —
|
|
60
|
-
// committed to its multi-line shape
|
|
61
|
-
// line fits but the all-flat form does not;
|
|
162
|
+
// 2. hugged — the callback (last for HugLast, first for HugFirst)
|
|
163
|
+
// committed to its multi-line shape with the other items inline,
|
|
164
|
+
// chosen when its opening line fits but the all-flat form does not;
|
|
62
165
|
// 3. plain — every item exploded onto its own indented line.
|
|
63
166
|
// The all-flat option is dropped when the list cannot render flat
|
|
64
167
|
// (a block-bodied callback argument carries hard line breaks).
|
|
65
168
|
hugged := printListHuggingLast(ctx, shape)
|
|
169
|
+
if shape.HugFirst {
|
|
170
|
+
hugged = printListHuggingFirst(ctx, shape)
|
|
171
|
+
}
|
|
172
|
+
// A test-framework call (HugLastForce) and a genuine React-hook deps call
|
|
173
|
+
// (HugFirstForce, `useEffect(() => { … }, [deps])`) hug their callback
|
|
174
|
+
// unconditionally — Prettier never explodes their arguments, it lets the open
|
|
175
|
+
// line overflow — so drop the exploded fallback. The all-flat option still
|
|
176
|
+
// wins when the whole call fits (an empty-body callback).
|
|
177
|
+
if shape.HugLastForce || shape.HugFirstForce {
|
|
178
|
+
if allFlat, ok := flatten(plain); ok {
|
|
179
|
+
return ConditionalGroup(allFlat, hugged)
|
|
180
|
+
}
|
|
181
|
+
return hugged
|
|
182
|
+
}
|
|
66
183
|
if allFlat, ok := flatten(plain); ok {
|
|
67
184
|
return ConditionalGroup(allFlat, hugged, plain)
|
|
68
185
|
}
|
|
@@ -75,7 +192,6 @@ func printList(ctx *PrintContext, shape listShape) Doc {
|
|
|
75
192
|
// comma — when it does not.
|
|
76
193
|
func printListPlain(ctx *PrintContext, shape listShape) Doc {
|
|
77
194
|
sep := Concat(Text(","), Line())
|
|
78
|
-
body := Join(sep, shape.Items)
|
|
79
195
|
|
|
80
196
|
flatPad := Doc{Kind: docNil}
|
|
81
197
|
if shape.Space {
|
|
@@ -87,6 +203,50 @@ func printListPlain(ctx *PrintContext, shape listShape) Doc {
|
|
|
87
203
|
trailing = IfBreak(Text(","), Doc{Kind: docNil})
|
|
88
204
|
}
|
|
89
205
|
|
|
206
|
+
hasBlank := shape.hasBlankBefore()
|
|
207
|
+
|
|
208
|
+
var body Doc
|
|
209
|
+
if hasBlank {
|
|
210
|
+
// Per-item body that preserves a single source blank line before an item:
|
|
211
|
+
// `,` then a Literalline (the empty line, no indent, mirroring printBlock)
|
|
212
|
+
// then the normal Line. A blank line forces the group broken.
|
|
213
|
+
parts := make([]Doc, 0, len(shape.Items)*3)
|
|
214
|
+
for i, it := range shape.Items {
|
|
215
|
+
if i > 0 {
|
|
216
|
+
parts = append(parts, Text(","))
|
|
217
|
+
if i < len(shape.BlankBefore) && shape.BlankBefore[i] {
|
|
218
|
+
parts = append(parts, Literalline())
|
|
219
|
+
}
|
|
220
|
+
parts = append(parts, Line())
|
|
221
|
+
}
|
|
222
|
+
parts = append(parts, it)
|
|
223
|
+
}
|
|
224
|
+
body = Concat(parts...)
|
|
225
|
+
} else if shape.Fill {
|
|
226
|
+
// Each non-last fill content carries its own comma — `[el, ","]` — and the
|
|
227
|
+
// separator is just a Line. Prettier measures the pack/break decision on
|
|
228
|
+
// `[content_i, line, content_{i+1}]`, so the next element's comma must be
|
|
229
|
+
// part of its content or the line would pack one element too many. The
|
|
230
|
+
// last element carries no comma here; the trailing comma is the shared
|
|
231
|
+
// ifBreak appended after the body so it tracks the GROUP's break mode (a
|
|
232
|
+
// fill-mode ifBreak would drop the comma when the last item packs flat,
|
|
233
|
+
// making the format non-idempotent).
|
|
234
|
+
parts := make([]Doc, 0, len(shape.Items)*2-1)
|
|
235
|
+
for i, it := range shape.Items {
|
|
236
|
+
if i > 0 {
|
|
237
|
+
parts = append(parts, Line())
|
|
238
|
+
}
|
|
239
|
+
if i < len(shape.Items)-1 {
|
|
240
|
+
parts = append(parts, Concat(it, Text(",")))
|
|
241
|
+
} else {
|
|
242
|
+
parts = append(parts, it)
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
body = Fill(parts...)
|
|
246
|
+
} else {
|
|
247
|
+
body = Join(sep, shape.Items)
|
|
248
|
+
}
|
|
249
|
+
|
|
90
250
|
openTok := Text(shape.OpenTok)
|
|
91
251
|
closeTok := Text(shape.CloseTok)
|
|
92
252
|
|
|
@@ -96,11 +256,19 @@ func printListPlain(ctx *PrintContext, shape listShape) Doc {
|
|
|
96
256
|
trailingSep := IfBreak(Hardline(), flatPad)
|
|
97
257
|
|
|
98
258
|
bodyBlock := Indent(ctx.indentUnit(), leadingSep, body, trailing)
|
|
99
|
-
|
|
259
|
+
prefix := shape.Prefix
|
|
260
|
+
if prefix.Kind == 0 {
|
|
261
|
+
prefix = Doc{Kind: docNil}
|
|
262
|
+
}
|
|
263
|
+
suffix := shape.Suffix
|
|
264
|
+
if suffix.Kind == 0 {
|
|
265
|
+
suffix = Doc{Kind: docNil}
|
|
266
|
+
}
|
|
267
|
+
doc := Concat(prefix, openTok, bodyBlock, trailingSep, closeTok, suffix)
|
|
100
268
|
group := Group(doc)
|
|
101
269
|
// ForceBreak (object-literal newline preservation) commits the group
|
|
102
270
|
// to its broken shape regardless of fit.
|
|
103
|
-
group.Break = shape.ForceBreak
|
|
271
|
+
group.Break = shape.ForceBreak || hasBlank
|
|
104
272
|
return group
|
|
105
273
|
}
|
|
106
274
|
|
|
@@ -143,3 +311,41 @@ func printListHuggingLast(ctx *PrintContext, shape listShape) Doc {
|
|
|
143
311
|
parts = append(parts, last, Text(shape.CloseTok))
|
|
144
312
|
return Concat(parts...)
|
|
145
313
|
}
|
|
314
|
+
|
|
315
|
+
// printListHuggingFirst renders the "first-argument hugging" shape
|
|
316
|
+
// Prettier uses for `foo(() => { … }, target)`: the first item stays
|
|
317
|
+
// attached to the open paren and the remaining simple items flow inline
|
|
318
|
+
// after it, so a multi-line callback body does not explode the trailing
|
|
319
|
+
// arguments onto their own lines.
|
|
320
|
+
//
|
|
321
|
+
// hugged: OPEN OPEN-of-first … CLOSE-of-first, b, c CLOSE
|
|
322
|
+
//
|
|
323
|
+
// Like printListHuggingLast it returns a plain Concat (the callback's own
|
|
324
|
+
// printer owns its body's break) and forces the hugged item's first Group
|
|
325
|
+
// broken when the item has no hard line breaks of its own, so the hugged
|
|
326
|
+
// option stays distinct from the all-flat option.
|
|
327
|
+
func printListHuggingFirst(ctx *PrintContext, shape listShape) Doc {
|
|
328
|
+
first := shape.Items[0]
|
|
329
|
+
rest := shape.Items[1:]
|
|
330
|
+
if _, flat := flatten(first); flat {
|
|
331
|
+
first, _ = forceBreakFirstGroup(first)
|
|
332
|
+
}
|
|
333
|
+
parts := []Doc{Text(shape.OpenTok), first}
|
|
334
|
+
for _, item := range rest {
|
|
335
|
+
// The trailing simple arguments ride the close line flat — Prettier keeps
|
|
336
|
+
// them on one line even when that line overflows (a long zero/one-argument
|
|
337
|
+
// trailing call `}, makeAccumulator(single))` is not broken). Force each
|
|
338
|
+
// flat so its own Group does not break against the close-line width. The
|
|
339
|
+
// React-hook deps array is the exception (HugFirstTrailingBreaks): Prettier
|
|
340
|
+
// renders it through a breakable group, so leave it unflattened to break
|
|
341
|
+
// one-element-per-line when the close line overflows.
|
|
342
|
+
if !shape.HugFirstTrailingBreaks {
|
|
343
|
+
if flat, ok := flatten(item); ok {
|
|
344
|
+
item = flat
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
parts = append(parts, Text(", "), item)
|
|
348
|
+
}
|
|
349
|
+
parts = append(parts, Text(shape.CloseTok))
|
|
350
|
+
return Concat(parts...)
|
|
351
|
+
}
|
|
@@ -35,6 +35,13 @@ func printObjectLiteral(ctx *PrintContext, node *shimast.Node) (Doc, bool) {
|
|
|
35
35
|
if obj == nil || obj.Properties == nil {
|
|
36
36
|
return verbatim(ctx, node), !nodeSpansMultipleLines(ctx, node)
|
|
37
37
|
}
|
|
38
|
+
// A comment between properties (or after `{`) would be dropped by the fresh
|
|
39
|
+
// separators; bail to verbatim and report UNCOVERED (hard `false`, not
|
|
40
|
+
// `!nodeSpansMultipleLines`) so an enclosing reflow abstains instead of
|
|
41
|
+
// breaking around this single-line verbatim object and moving it off its line.
|
|
42
|
+
if listHasInterItemComments(ctx, node) {
|
|
43
|
+
return verbatim(ctx, node), false
|
|
44
|
+
}
|
|
38
45
|
items := make([]Doc, 0, len(obj.Properties.Nodes))
|
|
39
46
|
covered := true
|
|
40
47
|
for _, prop := range obj.Properties.Nodes {
|
|
@@ -60,12 +67,13 @@ func printObjectLiteral(ctx *PrintContext, node *shimast.Node) (Doc, bool) {
|
|
|
60
67
|
// "none" suppresses. Pairs with the call/array branches so the printer
|
|
61
68
|
// never disagrees with the trailing-comma rule on the same setting.
|
|
62
69
|
return printList(ctx, listShape{
|
|
63
|
-
OpenTok:
|
|
64
|
-
CloseTok:
|
|
65
|
-
Items:
|
|
66
|
-
Space:
|
|
67
|
-
AddComma:
|
|
68
|
-
ForceBreak:
|
|
70
|
+
OpenTok: "{",
|
|
71
|
+
CloseTok: "}",
|
|
72
|
+
Items: items,
|
|
73
|
+
Space: true,
|
|
74
|
+
AddComma: ctx.allowsEs5TrailingComma(),
|
|
75
|
+
ForceBreak: forceBreak,
|
|
76
|
+
BlankBefore: blankBeforeItems(ctx.Source, obj.Properties.Nodes),
|
|
69
77
|
}), covered
|
|
70
78
|
}
|
|
71
79
|
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
package linthost
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
// printConditionalExpression renders a (possibly chained) ternary with
|
|
8
|
+
// Prettier 3's "indent nested ternaries" staircase. A conditional whose
|
|
9
|
+
// consequent or alternate is itself a conditional is printed inline
|
|
10
|
+
// under the same break group, but its arms indent one extra level:
|
|
11
|
+
//
|
|
12
|
+
// aaaaaaaaaa
|
|
13
|
+
// ? bbbbbbbbbb
|
|
14
|
+
// : cccccccccc
|
|
15
|
+
// ? dddddddddd
|
|
16
|
+
// : eeeeeeeeee
|
|
17
|
+
//
|
|
18
|
+
// The whole chain shares one fit-or-break decision (a single outer
|
|
19
|
+
// Group), matching Prettier: either the entire chain fits flat
|
|
20
|
+
// (`a ? b : c ? d : e`) or every rung breaks onto its own line. Nesting
|
|
21
|
+
// is expressed by recursing the chain builder without wrapping the
|
|
22
|
+
// nested conditional in its own Group. The outermost chain indents its arms
|
|
23
|
+
// by `tabWidth`. A nested chain in the ALTERNATE (`: `) position indents by a
|
|
24
|
+
// fixed 2 columns; a nested chain in the CONSEQUENT (`? `) position indents by
|
|
25
|
+
// `max(2, tabWidth)` (Prettier's extra `align(tabWidth-2)` on the consequent).
|
|
26
|
+
// So at tabWidth 4 the outer arms sit at column 4, an alternate-nested arm at
|
|
27
|
+
// column 6, and a consequent-nested arm at column 8; they coincide at tabWidth 2.
|
|
28
|
+
//
|
|
29
|
+
// The second return value is the coverage flag (see PrintNode): the AND
|
|
30
|
+
// of the test and both branches, so a multi-line verbatim node anywhere
|
|
31
|
+
// in the chain makes formatPrintWidth abstain rather than emit a
|
|
32
|
+
// half-reflowed shape.
|
|
33
|
+
func printConditionalExpression(ctx *PrintContext, node *shimast.Node) (Doc, bool) {
|
|
34
|
+
body, covered := buildConditionalChain(ctx, node, ctx.indentUnit())
|
|
35
|
+
if body.IsNil() {
|
|
36
|
+
return verbatim(ctx, node), !nodeSpansMultipleLines(ctx, node)
|
|
37
|
+
}
|
|
38
|
+
return Group(body), covered
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// buildConditionalChain returns the chain body for `node` WITHOUT a
|
|
42
|
+
// surrounding Group, so a nested conditional recursed from here shares
|
|
43
|
+
// the caller's group and its arms indent one level deeper. The top-level
|
|
44
|
+
// printConditionalExpression wraps the outermost body in the single
|
|
45
|
+
// Group that owns the break decision.
|
|
46
|
+
func buildConditionalChain(ctx *PrintContext, node *shimast.Node, indentCols int) (Doc, bool) {
|
|
47
|
+
cond := node.AsConditionalExpression()
|
|
48
|
+
if cond == nil || cond.Condition == nil || cond.WhenTrue == nil || cond.WhenFalse == nil {
|
|
49
|
+
return Doc{}, true
|
|
50
|
+
}
|
|
51
|
+
// A comment around the `?`/`:` markers (`a ? /* c */ b : c`) would be dropped
|
|
52
|
+
// by the minted "? "/": " text — the markers are not AST children, so a
|
|
53
|
+
// nested conditional's gap comment slips past the top-level print-width scan
|
|
54
|
+
// and is lost on reflow. Bail to verbatim and report UNCOVERED (hard `false`,
|
|
55
|
+
// not `!nodeSpansMultipleLines`) so an enclosing reflow abstains instead of
|
|
56
|
+
// breaking around this single-line verbatim conditional and moving it off its
|
|
57
|
+
// line; the bytes survive.
|
|
58
|
+
if listHasInterItemComments(ctx, node) {
|
|
59
|
+
return verbatim(ctx, node), false
|
|
60
|
+
}
|
|
61
|
+
testDoc, c1 := PrintNode(ctx, cond.Condition)
|
|
62
|
+
consDoc, c2 := ternaryArm(ctx, cond.WhenTrue, true)
|
|
63
|
+
altDoc, c3 := ternaryArm(ctx, cond.WhenFalse, false)
|
|
64
|
+
doc := Concat(
|
|
65
|
+
testDoc,
|
|
66
|
+
Indent(indentCols,
|
|
67
|
+
Line(), Text("? "), consDoc,
|
|
68
|
+
Line(), Text(": "), altDoc,
|
|
69
|
+
),
|
|
70
|
+
)
|
|
71
|
+
return doc, c1 && c2 && c3
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ternaryArm prints a ternary consequent/alternate. A nested conditional
|
|
75
|
+
// continues the chain inline (no new Group) so the staircase
|
|
76
|
+
// accumulates; every other arm prints through the normal dispatcher (an
|
|
77
|
+
// arm that is a `??` expression is already parenthesized in valid
|
|
78
|
+
// source, so it round-trips its parens via the ParenthesizedExpression
|
|
79
|
+
// printer).
|
|
80
|
+
//
|
|
81
|
+
// A non-conditional arm is wrapped in Align so that, when it breaks
|
|
82
|
+
// internally, its continuation hangs under the arm expression's own
|
|
83
|
+
// column (one level past the `? `/`: ` marker) rather than under the
|
|
84
|
+
// chain's rung indent. Prettier hangs a broken call/object arm there:
|
|
85
|
+
//
|
|
86
|
+
// cond
|
|
87
|
+
// ? foo(
|
|
88
|
+
// arg, // arm-column + one level, not rung + one level
|
|
89
|
+
// )
|
|
90
|
+
// : bar
|
|
91
|
+
//
|
|
92
|
+
// Align is a no-op for an arm that stays flat, and a nested conditional
|
|
93
|
+
// is deliberately NOT aligned — it keeps the Indent-based staircase.
|
|
94
|
+
//
|
|
95
|
+
// A nested conditional in the CONSEQUENT (`? `) position is wrapped in
|
|
96
|
+
// parentheses, but only when the chain renders flat: Prettier's ternary-old
|
|
97
|
+
// printer emits `consequent.type === node.type ? ifBreak("", "(") : ""` around
|
|
98
|
+
// the consequent (`a ? (b ? c : d) : e` on one line), and drops the parens for
|
|
99
|
+
// the broken staircase. A nested conditional in the ALTERNATE (`: `) position
|
|
100
|
+
// is never wrapped — it chains. `isConsequent` selects between the two.
|
|
101
|
+
func ternaryArm(ctx *PrintContext, node *shimast.Node, isConsequent bool) (Doc, bool) {
|
|
102
|
+
inner := node
|
|
103
|
+
// A nested ternary written with explicit source parentheses — `a ? (b ? c : d)
|
|
104
|
+
// : e` — is the same chain link as a bare nested ternary: Prettier's AST has no
|
|
105
|
+
// ParenthesizedExpression node, so its `printTernary` sees the consequent as a
|
|
106
|
+
// ConditionalExpression and joins the staircase (re-adding the parens only in
|
|
107
|
+
// flat mode via ifBreak). Unwrap a parenthesized conditional so it chains too,
|
|
108
|
+
// instead of printing flat inside kept parens. Only a ConditionalExpression
|
|
109
|
+
// inner is unwrapped; `(a ?? b)` and other parenthesized expressions keep their
|
|
110
|
+
// parens through the normal printer.
|
|
111
|
+
// Do NOT unwrap when a comment sits between the parens and the inner
|
|
112
|
+
// conditional (`(/* keep */ b ? c : d)`): dropping the ParenExpr wrapper would
|
|
113
|
+
// delete that comment. Leaving `inner` as the ParenExpr routes it through the
|
|
114
|
+
// normal printer, whose own self-guard bails to verbatim and preserves it.
|
|
115
|
+
if inner != nil && inner.Kind == shimast.KindParenthesizedExpression &&
|
|
116
|
+
!listHasInterItemComments(ctx, inner) {
|
|
117
|
+
if p := inner.AsParenthesizedExpression(); p != nil && p.Expression != nil &&
|
|
118
|
+
p.Expression.Kind == shimast.KindConditionalExpression {
|
|
119
|
+
inner = p.Expression
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if inner != nil && inner.Kind == shimast.KindConditionalExpression {
|
|
123
|
+
// A nested chain's arms align at 2 past their parent rung. Prettier's
|
|
124
|
+
// ternary-old.js uses that as-is for an ALTERNATE-position nested chain
|
|
125
|
+
// (`align(2)`), but a CONSEQUENT-position one gets an extra
|
|
126
|
+
// `align(Math.max(0, tabWidth - 2))`, for a total of `max(2, tabWidth)`.
|
|
127
|
+
// The two coincide at the default tabWidth 2; they diverge at tabWidth > 2.
|
|
128
|
+
indentCols := 2
|
|
129
|
+
if isConsequent {
|
|
130
|
+
if u := ctx.indentUnit(); u > indentCols {
|
|
131
|
+
indentCols = u
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
chain, covered := buildConditionalChain(ctx, inner, indentCols)
|
|
135
|
+
if isConsequent {
|
|
136
|
+
// `ifBreak("", "(")` … `ifBreak("", ")")`: parens in flat mode only.
|
|
137
|
+
chain = Concat(
|
|
138
|
+
IfBreak(Doc{Kind: docNil}, Text("(")),
|
|
139
|
+
chain,
|
|
140
|
+
IfBreak(Doc{Kind: docNil}, Text(")")),
|
|
141
|
+
)
|
|
142
|
+
}
|
|
143
|
+
return chain, covered
|
|
144
|
+
}
|
|
145
|
+
doc, covered := PrintNode(ctx, node)
|
|
146
|
+
return Align(doc), covered
|
|
147
|
+
}
|