@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
package/linthost/rules_curly.go
CHANGED
|
@@ -7,64 +7,64 @@
|
|
|
7
7
|
package linthost
|
|
8
8
|
|
|
9
9
|
import (
|
|
10
|
-
|
|
10
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
11
11
|
)
|
|
12
12
|
|
|
13
13
|
type curly struct{}
|
|
14
14
|
|
|
15
15
|
func (curly) Name() string { return "curly" }
|
|
16
16
|
func (curly) Visits() []shimast.Kind {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
return []shimast.Kind{
|
|
18
|
+
shimast.KindIfStatement,
|
|
19
|
+
shimast.KindWhileStatement,
|
|
20
|
+
shimast.KindDoStatement,
|
|
21
|
+
shimast.KindForStatement,
|
|
22
|
+
shimast.KindForInStatement,
|
|
23
|
+
shimast.KindForOfStatement,
|
|
24
|
+
}
|
|
25
25
|
}
|
|
26
26
|
func (curly) Check(ctx *Context, node *shimast.Node) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
27
|
+
switch node.Kind {
|
|
28
|
+
case shimast.KindIfStatement:
|
|
29
|
+
stmt := node.AsIfStatement()
|
|
30
|
+
if stmt == nil {
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
curlyReportNonBlock(ctx, stmt.ThenStatement, "if")
|
|
34
|
+
// Allow `else if (...)` — the else branch carries another
|
|
35
|
+
// IfStatement that is itself visited and reported separately.
|
|
36
|
+
if stmt.ElseStatement != nil && stmt.ElseStatement.Kind != shimast.KindIfStatement {
|
|
37
|
+
curlyReportNonBlock(ctx, stmt.ElseStatement, "else")
|
|
38
|
+
}
|
|
39
|
+
case shimast.KindWhileStatement:
|
|
40
|
+
if stmt := node.AsWhileStatement(); stmt != nil {
|
|
41
|
+
curlyReportNonBlock(ctx, stmt.Statement, "while")
|
|
42
|
+
}
|
|
43
|
+
case shimast.KindDoStatement:
|
|
44
|
+
if stmt := node.AsDoStatement(); stmt != nil {
|
|
45
|
+
curlyReportNonBlock(ctx, stmt.Statement, "do")
|
|
46
|
+
}
|
|
47
|
+
case shimast.KindForStatement:
|
|
48
|
+
if stmt := node.AsForStatement(); stmt != nil {
|
|
49
|
+
curlyReportNonBlock(ctx, stmt.Statement, "for")
|
|
50
|
+
}
|
|
51
|
+
case shimast.KindForInStatement, shimast.KindForOfStatement:
|
|
52
|
+
if stmt := node.AsForInOrOfStatement(); stmt != nil {
|
|
53
|
+
curlyReportNonBlock(ctx, stmt.Statement, "for")
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
// curlyReportNonBlock reports `body` when it is a single bare statement
|
|
59
59
|
// instead of a Block. A nil body means there is nothing to wrap (e.g. an
|
|
60
60
|
// IfStatement with no else clause), so it is silently skipped.
|
|
61
61
|
func curlyReportNonBlock(ctx *Context, body *shimast.Node, keyword string) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
if body == nil || body.Kind == shimast.KindBlock {
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
ctx.Report(body, "Expected { after '"+keyword+"' condition.")
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
func init() {
|
|
69
|
-
|
|
69
|
+
Register(curly{})
|
|
70
70
|
}
|
|
@@ -18,22 +18,22 @@ type defaultCase struct{}
|
|
|
18
18
|
func (defaultCase) Name() string { return "default-case" }
|
|
19
19
|
func (defaultCase) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindSwitchStatement} }
|
|
20
20
|
func (defaultCase) Check(ctx *Context, node *shimast.Node) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
21
|
+
sw := node.AsSwitchStatement()
|
|
22
|
+
if sw == nil || sw.CaseBlock == nil {
|
|
23
|
+
return
|
|
24
|
+
}
|
|
25
|
+
block := sw.CaseBlock.AsCaseBlock()
|
|
26
|
+
if block == nil || block.Clauses == nil {
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
for _, clause := range block.Clauses.Nodes {
|
|
30
|
+
if clause != nil && clause.Kind == shimast.KindDefaultClause {
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
ctx.Report(node, "Expected a default case.")
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
func init() {
|
|
38
|
-
|
|
38
|
+
Register(defaultCase{})
|
|
39
39
|
}
|
|
@@ -16,31 +16,31 @@ type defaultCaseLast struct{}
|
|
|
16
16
|
|
|
17
17
|
func (defaultCaseLast) Name() string { return "default-case-last" }
|
|
18
18
|
func (defaultCaseLast) Visits() []shimast.Kind {
|
|
19
|
-
|
|
19
|
+
return []shimast.Kind{shimast.KindSwitchStatement}
|
|
20
20
|
}
|
|
21
21
|
func (defaultCaseLast) Check(ctx *Context, node *shimast.Node) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
22
|
+
sw := node.AsSwitchStatement()
|
|
23
|
+
if sw == nil || sw.CaseBlock == nil {
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
block := sw.CaseBlock.AsCaseBlock()
|
|
27
|
+
if block == nil || block.Clauses == nil {
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
clauses := block.Clauses.Nodes
|
|
31
|
+
if len(clauses) == 0 {
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
last := clauses[len(clauses)-1]
|
|
35
|
+
for i := 0; i < len(clauses)-1; i++ {
|
|
36
|
+
clause := clauses[i]
|
|
37
|
+
if clause != nil && clause.Kind == shimast.KindDefaultClause {
|
|
38
|
+
_ = last
|
|
39
|
+
ctx.Report(clause, "Default clause should be the last clause.")
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
func init() {
|
|
45
|
-
|
|
45
|
+
Register(defaultCaseLast{})
|
|
46
46
|
}
|
|
@@ -0,0 +1,167 @@
|
|
|
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
|
+
// formatArrowParens normalizes the parentheses around a single-parameter
|
|
9
|
+
// arrow function, mirroring Prettier's `arrowParens`:
|
|
10
|
+
//
|
|
11
|
+
// - prefer "always" (Prettier default): a bare `x => x` gains parens,
|
|
12
|
+
// becoming `(x) => x`.
|
|
13
|
+
// - prefer "avoid": `(x) => x` drops them, becoming `x => x`.
|
|
14
|
+
//
|
|
15
|
+
// Only a single parameter that is a plain identifier with no type
|
|
16
|
+
// annotation, default, rest, optional `?`, or modifier is affected, every
|
|
17
|
+
// other shape (`(x: T)`, `({ x })`, `(...x)`, `(x = 1)`, `(x?)`, `(x, y)`,
|
|
18
|
+
// `()`) keeps its parentheses in both modes, exactly as Prettier does.
|
|
19
|
+
// `async x => x` is handled too: the modifier sits before the parameter, so
|
|
20
|
+
// the parameter-name span is unaffected.
|
|
21
|
+
//
|
|
22
|
+
// The rule rewrites only the parameter span (`x` <-> `(x)`), never the body
|
|
23
|
+
// or the `=>`, so a chained arrow `a => b => …` has each eligible arm
|
|
24
|
+
// normalized independently. Idempotent: a parameter already in the
|
|
25
|
+
// preferred shape compares equal and emits nothing.
|
|
26
|
+
type formatArrowParens struct{}
|
|
27
|
+
|
|
28
|
+
type formatArrowParensOptions struct {
|
|
29
|
+
Prefer string `json:"prefer"`
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
func (formatArrowParens) Name() string { return "format/arrow-parens" }
|
|
33
|
+
func (formatArrowParens) IsFormat() bool { return true }
|
|
34
|
+
|
|
35
|
+
func (formatArrowParens) Visits() []shimast.Kind {
|
|
36
|
+
return []shimast.Kind{shimast.KindArrowFunction}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
func (formatArrowParens) Check(ctx *Context, node *shimast.Node) {
|
|
40
|
+
if ctx == nil || ctx.File == nil || node == nil {
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
arrow := node.AsArrowFunction()
|
|
44
|
+
if arrow == nil || arrow.Parameters == nil {
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
params := arrow.Parameters.Nodes
|
|
48
|
+
if len(params) != 1 || params[0] == nil {
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
param := params[0]
|
|
52
|
+
if !isBareIdentifierParam(param) {
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
// A type-parameter list (`<T>(x) => …`) forces the parameter parens in
|
|
56
|
+
// both modes (a bare `<T>x =>` is not valid), so leave such an arrow
|
|
57
|
+
// alone, its parens are mandatory, not stylistic.
|
|
58
|
+
if arrow.TypeParameters != nil && len(arrow.TypeParameters.Nodes) > 0 {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
// A return-type annotation (`(x): T => …`) also requires the parens.
|
|
62
|
+
if arrow.Type != nil {
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
var opts formatArrowParensOptions
|
|
67
|
+
_ = ctx.DecodeOptions(&opts)
|
|
68
|
+
prefer := opts.Prefer
|
|
69
|
+
if prefer != "avoid" {
|
|
70
|
+
prefer = "always"
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
src := ctx.File.Text()
|
|
74
|
+
nameStart := shimscanner.SkipTrivia(src, param.Pos())
|
|
75
|
+
nameEnd := param.End()
|
|
76
|
+
if nameStart < 0 || nameEnd <= nameStart || nameEnd > len(src) {
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Is the parameter already wrapped in `(` … `)`? Scan over whitespace on
|
|
81
|
+
// each side; the sole parameter of an arrow is delimited by the
|
|
82
|
+
// parameter-list parens when present.
|
|
83
|
+
openParen := scanBackForByte(src, nameStart, '(')
|
|
84
|
+
closeParen := scanForwardForByte(src, nameEnd, ')')
|
|
85
|
+
wrapped := openParen >= 0 && closeParen >= 0
|
|
86
|
+
|
|
87
|
+
switch prefer {
|
|
88
|
+
case "avoid":
|
|
89
|
+
if !wrapped {
|
|
90
|
+
return // already bare
|
|
91
|
+
}
|
|
92
|
+
// Replace `( … name … )` with just the name.
|
|
93
|
+
ctx.ReportRangeFix(
|
|
94
|
+
openParen,
|
|
95
|
+
closeParen+1,
|
|
96
|
+
"Single-parameter arrow should omit parentheses.",
|
|
97
|
+
TextEdit{Pos: openParen, End: closeParen + 1, Text: src[nameStart:nameEnd]},
|
|
98
|
+
)
|
|
99
|
+
default: // always
|
|
100
|
+
if wrapped {
|
|
101
|
+
return // already parenthesized
|
|
102
|
+
}
|
|
103
|
+
ctx.ReportRangeFix(
|
|
104
|
+
nameStart,
|
|
105
|
+
nameEnd,
|
|
106
|
+
"Single-parameter arrow should keep parentheses.",
|
|
107
|
+
TextEdit{Pos: nameStart, End: nameEnd, Text: "(" + src[nameStart:nameEnd] + ")"},
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// isBareIdentifierParam reports whether `param` is a plain identifier
|
|
113
|
+
// parameter: no rest `...`, no optional `?`, no type annotation, no default,
|
|
114
|
+
// no modifier (a parameter property), and an identifier name. Only such a
|
|
115
|
+
// parameter is eligible for arrow-paren normalization; every richer shape
|
|
116
|
+
// keeps its parentheses in both Prettier modes.
|
|
117
|
+
func isBareIdentifierParam(param *shimast.Node) bool {
|
|
118
|
+
decl := param.AsParameterDeclaration()
|
|
119
|
+
if decl == nil {
|
|
120
|
+
return false
|
|
121
|
+
}
|
|
122
|
+
if decl.DotDotDotToken != nil || decl.QuestionToken != nil ||
|
|
123
|
+
decl.Type != nil || decl.Initializer != nil {
|
|
124
|
+
return false
|
|
125
|
+
}
|
|
126
|
+
if mods := param.Modifiers(); mods != nil && len(mods.Nodes) > 0 {
|
|
127
|
+
return false
|
|
128
|
+
}
|
|
129
|
+
name := param.Name()
|
|
130
|
+
return name != nil && name.Kind == shimast.KindIdentifier
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// scanBackForByte returns the offset of the nearest `target` byte at or
|
|
134
|
+
// before `from`-1, scanning over whitespace only; -1 if a non-whitespace,
|
|
135
|
+
// non-target byte is reached first.
|
|
136
|
+
func scanBackForByte(src string, from int, target byte) int {
|
|
137
|
+
for i := from - 1; i >= 0; i-- {
|
|
138
|
+
c := src[i]
|
|
139
|
+
if c == target {
|
|
140
|
+
return i
|
|
141
|
+
}
|
|
142
|
+
if c != ' ' && c != '\t' && c != '\r' && c != '\n' {
|
|
143
|
+
return -1
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return -1
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// scanForwardForByte returns the offset of the nearest `target` byte at or
|
|
150
|
+
// after `from`, scanning over whitespace only; -1 if a non-whitespace,
|
|
151
|
+
// non-target byte is reached first.
|
|
152
|
+
func scanForwardForByte(src string, from int, target byte) int {
|
|
153
|
+
for i := from; i < len(src); i++ {
|
|
154
|
+
c := src[i]
|
|
155
|
+
if c == target {
|
|
156
|
+
return i
|
|
157
|
+
}
|
|
158
|
+
if c != ' ' && c != '\t' && c != '\r' && c != '\n' {
|
|
159
|
+
return -1
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return -1
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
func init() {
|
|
166
|
+
Register(formatArrowParens{})
|
|
167
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
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
|
+
// formatBracketSpacing normalizes the inner padding of single-line brace
|
|
9
|
+
// pairs, mirroring Prettier's `bracketSpacing`:
|
|
10
|
+
//
|
|
11
|
+
// - prefer true (Prettier default): one space just inside the braces,
|
|
12
|
+
// `{ x: 1 }`, `{ a, b }`, `import { foo } from "m"`.
|
|
13
|
+
// - prefer false: no inner space, `{x: 1}`, `{a, b}`, `import {foo}`.
|
|
14
|
+
//
|
|
15
|
+
// It applies to object literals, object binding patterns (destructuring),
|
|
16
|
+
// named imports/exports, and type literals, the brace kinds Prettier's
|
|
17
|
+
// bracketSpacing governs. Block, class, interface, enum, and module braces
|
|
18
|
+
// are NOT affected (their layout is owned by the indentation rules).
|
|
19
|
+
//
|
|
20
|
+
// The rule touches only a brace pair that opens and closes on the SAME
|
|
21
|
+
// line: a multi-line container's interior is the indentation rules' surface,
|
|
22
|
+
// and an empty `{}` has no interior to pad. It rewrites just the whitespace
|
|
23
|
+
// run immediately inside each brace, so it never disturbs the contents.
|
|
24
|
+
// Idempotent: a pair already in the preferred shape compares equal.
|
|
25
|
+
type formatBracketSpacing struct{}
|
|
26
|
+
|
|
27
|
+
type formatBracketSpacingOptions struct {
|
|
28
|
+
Spacing *bool `json:"spacing"`
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
func (formatBracketSpacing) Name() string { return "format/bracket-spacing" }
|
|
32
|
+
func (formatBracketSpacing) IsFormat() bool { return true }
|
|
33
|
+
|
|
34
|
+
func (formatBracketSpacing) Visits() []shimast.Kind {
|
|
35
|
+
return []shimast.Kind{
|
|
36
|
+
shimast.KindObjectLiteralExpression,
|
|
37
|
+
shimast.KindObjectBindingPattern,
|
|
38
|
+
shimast.KindNamedImports,
|
|
39
|
+
shimast.KindNamedExports,
|
|
40
|
+
shimast.KindTypeLiteral,
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
func (formatBracketSpacing) Check(ctx *Context, node *shimast.Node) {
|
|
45
|
+
if ctx == nil || ctx.File == nil || node == nil {
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
var opts formatBracketSpacingOptions
|
|
49
|
+
_ = ctx.DecodeOptions(&opts)
|
|
50
|
+
spacing := true
|
|
51
|
+
if opts.Spacing != nil {
|
|
52
|
+
spacing = *opts.Spacing
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
src := ctx.File.Text()
|
|
56
|
+
start := shimscanner.SkipTrivia(src, node.Pos())
|
|
57
|
+
end := node.End()
|
|
58
|
+
if start < 0 || end <= start || end > len(src) {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
// The node's first byte should be `{` and last `}`; a parenthesized or
|
|
62
|
+
// otherwise-wrapped form is out of scope.
|
|
63
|
+
if src[start] != '{' || src[end-1] != '}' {
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
inner := src[start+1 : end-1]
|
|
67
|
+
if len(inner) == 0 {
|
|
68
|
+
return // empty `{}`, nothing to pad
|
|
69
|
+
}
|
|
70
|
+
// Multi-line: the interior belongs to the indentation rules.
|
|
71
|
+
for i := 0; i < len(inner); i++ {
|
|
72
|
+
if inner[i] == '\n' || inner[i] == '\r' {
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Only-whitespace interior (`{ }`) is treated as empty: collapse to the
|
|
77
|
+
// canonical empty form rather than padding nothing.
|
|
78
|
+
trimmed := trimASCIISpace(inner)
|
|
79
|
+
if len(trimmed) == 0 {
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Compute the desired interior: exactly one leading+trailing space when
|
|
84
|
+
// spacing is on, none when off.
|
|
85
|
+
var want string
|
|
86
|
+
if spacing {
|
|
87
|
+
want = " " + trimmed + " "
|
|
88
|
+
} else {
|
|
89
|
+
want = trimmed
|
|
90
|
+
}
|
|
91
|
+
if inner == want {
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
ctx.ReportRangeFix(
|
|
95
|
+
start+1,
|
|
96
|
+
end-1,
|
|
97
|
+
"Normalize brace spacing to match bracketSpacing.",
|
|
98
|
+
TextEdit{Pos: start + 1, End: end - 1, Text: want},
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// trimASCIISpace strips leading and trailing spaces and tabs from s.
|
|
103
|
+
func trimASCIISpace(s string) string {
|
|
104
|
+
i := 0
|
|
105
|
+
for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
|
|
106
|
+
i++
|
|
107
|
+
}
|
|
108
|
+
j := len(s)
|
|
109
|
+
for j > i && (s[j-1] == ' ' || s[j-1] == '\t') {
|
|
110
|
+
j--
|
|
111
|
+
}
|
|
112
|
+
return s[i:j]
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
func init() {
|
|
116
|
+
Register(formatBracketSpacing{})
|
|
117
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
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
|
+
// formatClauseJoin joins a single non-block statement that sits on its
|
|
11
|
+
// own line back onto its control-flow header, mirroring Prettier:
|
|
12
|
+
//
|
|
13
|
+
// if (a)
|
|
14
|
+
// b();
|
|
15
|
+
//
|
|
16
|
+
// becomes `if (a) b();` when the joined line fits printWidth. The same
|
|
17
|
+
// applies to `for`, `for-in`, `for-of`, and `while` headers. A braced
|
|
18
|
+
// body, a body that already shares the header line, a multi-line body,
|
|
19
|
+
// or a join that would overflow printWidth is left untouched.
|
|
20
|
+
//
|
|
21
|
+
// The rule only ever rewrites the whitespace gap between a header's
|
|
22
|
+
// closing `)` and the controlled statement, so its edits never overlap
|
|
23
|
+
// `format/indent` (leading whitespace of a line) or `format/print-width`
|
|
24
|
+
// (interior reflow). Idempotent: once joined the gap holds no newline
|
|
25
|
+
// and the rule abstains.
|
|
26
|
+
type formatClauseJoin struct{}
|
|
27
|
+
|
|
28
|
+
// formatClauseJoinOptions mirrors the printWidth/indent keys the rule
|
|
29
|
+
// needs to decide whether the joined line fits. The config layer mirrors
|
|
30
|
+
// `format.printWidth`/`tabWidth`/`useTabs` into this rule's option blob
|
|
31
|
+
// (see expandFormatBlock).
|
|
32
|
+
type formatClauseJoinOptions struct {
|
|
33
|
+
PrintWidth *int `json:"printWidth"`
|
|
34
|
+
TabWidth *int `json:"tabWidth"`
|
|
35
|
+
UseTabs *bool `json:"useTabs"`
|
|
36
|
+
EndOfLine *string `json:"endOfLine"`
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
func (formatClauseJoin) Name() string { return "format/clause-join" }
|
|
40
|
+
func (formatClauseJoin) IsFormat() bool { return true }
|
|
41
|
+
|
|
42
|
+
func (formatClauseJoin) Visits() []shimast.Kind {
|
|
43
|
+
return []shimast.Kind{
|
|
44
|
+
shimast.KindIfStatement,
|
|
45
|
+
shimast.KindWhileStatement,
|
|
46
|
+
shimast.KindForStatement,
|
|
47
|
+
shimast.KindForInStatement,
|
|
48
|
+
shimast.KindForOfStatement,
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
func (formatClauseJoin) Check(ctx *Context, node *shimast.Node) {
|
|
53
|
+
if ctx == nil || ctx.File == nil || node == nil {
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
var opts formatClauseJoinOptions
|
|
57
|
+
_ = ctx.DecodeOptions(&opts)
|
|
58
|
+
printWidth := 80
|
|
59
|
+
if opts.PrintWidth != nil && *opts.PrintWidth > 0 {
|
|
60
|
+
printWidth = *opts.PrintWidth
|
|
61
|
+
}
|
|
62
|
+
tabWidth := 2
|
|
63
|
+
if opts.TabWidth != nil && *opts.TabWidth > 0 {
|
|
64
|
+
tabWidth = *opts.TabWidth
|
|
65
|
+
}
|
|
66
|
+
joinClauseBody(ctx, ctx.File.Text(), node, clauseControlledBody(node), printWidth, tabWidth)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// clauseControlledBody returns the single controlled statement of a
|
|
70
|
+
// control-flow header, the `then` branch for `if`, the loop body for
|
|
71
|
+
// the iteration statements. The `else` branch is intentionally excluded:
|
|
72
|
+
// its body is anchored after the `else` keyword rather than a `)`, so it
|
|
73
|
+
// does not share this rule's `)`-anchored join shape.
|
|
74
|
+
func clauseControlledBody(node *shimast.Node) *shimast.Node {
|
|
75
|
+
switch node.Kind {
|
|
76
|
+
case shimast.KindIfStatement:
|
|
77
|
+
return node.AsIfStatement().ThenStatement
|
|
78
|
+
case shimast.KindWhileStatement:
|
|
79
|
+
return node.AsWhileStatement().Statement
|
|
80
|
+
case shimast.KindForStatement:
|
|
81
|
+
return node.AsForStatement().Statement
|
|
82
|
+
case shimast.KindForInStatement, shimast.KindForOfStatement:
|
|
83
|
+
return node.AsForInOrOfStatement().Statement
|
|
84
|
+
}
|
|
85
|
+
return nil
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
func joinClauseBody(
|
|
89
|
+
ctx *Context,
|
|
90
|
+
src string,
|
|
91
|
+
node *shimast.Node,
|
|
92
|
+
body *shimast.Node,
|
|
93
|
+
printWidth int,
|
|
94
|
+
tabWidth int,
|
|
95
|
+
) {
|
|
96
|
+
if body == nil || body.Kind == shimast.KindBlock {
|
|
97
|
+
return
|
|
98
|
+
}
|
|
99
|
+
bodyStart := shimscanner.SkipTrivia(src, body.Pos())
|
|
100
|
+
bodyEnd := body.End()
|
|
101
|
+
if bodyStart < 0 || bodyEnd < bodyStart || bodyEnd > len(src) {
|
|
102
|
+
return
|
|
103
|
+
}
|
|
104
|
+
// The gap is the whitespace run immediately before the body. Walk back
|
|
105
|
+
// over horizontal whitespace and newlines; the byte before it must be
|
|
106
|
+
// the header's closing `)` so a comment between header and body (which
|
|
107
|
+
// SkipTrivia would have stepped over) can never be swallowed.
|
|
108
|
+
gapStart := bodyStart
|
|
109
|
+
for gapStart > 0 && isClauseGapByte(src[gapStart-1]) {
|
|
110
|
+
gapStart--
|
|
111
|
+
}
|
|
112
|
+
if gapStart == 0 || src[gapStart-1] != ')' {
|
|
113
|
+
return
|
|
114
|
+
}
|
|
115
|
+
gap := src[gapStart:bodyStart]
|
|
116
|
+
if !strings.Contains(gap, "\n") {
|
|
117
|
+
return // body already shares the header line
|
|
118
|
+
}
|
|
119
|
+
// The header and the body must each be single-line; a multi-line body
|
|
120
|
+
// (e.g. a nested clause not yet joined) waits for the cascade to settle
|
|
121
|
+
// its inner join first.
|
|
122
|
+
headerStart := shimscanner.SkipTrivia(src, node.Pos())
|
|
123
|
+
if headerStart < 0 || headerStart > gapStart {
|
|
124
|
+
return
|
|
125
|
+
}
|
|
126
|
+
headerLineStart := lineStartOffset(src, headerStart)
|
|
127
|
+
if strings.ContainsRune(src[headerLineStart:gapStart], '\n') {
|
|
128
|
+
return
|
|
129
|
+
}
|
|
130
|
+
if strings.ContainsRune(src[bodyStart:bodyEnd], '\n') {
|
|
131
|
+
return
|
|
132
|
+
}
|
|
133
|
+
joined := visualWidth(src[headerLineStart:gapStart], tabWidth) + 1 +
|
|
134
|
+
visualWidth(src[bodyStart:bodyEnd], tabWidth)
|
|
135
|
+
if joined > printWidth {
|
|
136
|
+
return
|
|
137
|
+
}
|
|
138
|
+
ctx.ReportRangeFix(
|
|
139
|
+
gapStart,
|
|
140
|
+
bodyStart,
|
|
141
|
+
"Single-statement clause body should join its header line.",
|
|
142
|
+
TextEdit{Pos: gapStart, End: bodyStart, Text: " "},
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// isClauseGapByte reports whether `c` is whitespace that may appear in
|
|
147
|
+
// the gap between a clause header and its controlled statement.
|
|
148
|
+
func isClauseGapByte(c byte) bool {
|
|
149
|
+
return c == ' ' || c == '\t' || c == '\r' || c == '\n'
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// visualWidth returns the column width of `s`, expanding tab characters
|
|
153
|
+
// to `tabWidth` columns. Non-tab bytes count as one column, which is
|
|
154
|
+
// exact for the ASCII that dominates control-flow headers and the common
|
|
155
|
+
// case; it can under/over-count multi-byte runes, but clause bodies that
|
|
156
|
+
// land exactly on the printWidth boundary are rare enough that the
|
|
157
|
+
// approximation never changes a real join decision.
|
|
158
|
+
func visualWidth(s string, tabWidth int) int {
|
|
159
|
+
width := 0
|
|
160
|
+
for _, r := range s {
|
|
161
|
+
if r == '\t' {
|
|
162
|
+
width += tabWidth
|
|
163
|
+
continue
|
|
164
|
+
}
|
|
165
|
+
width += runeWidth(r)
|
|
166
|
+
}
|
|
167
|
+
return width
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
func init() {
|
|
171
|
+
Register(formatClauseJoin{})
|
|
172
|
+
}
|