@ttsc/lint 0.14.0-dev.20260529.1 → 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 +85 -87
- 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
|
@@ -3,13 +3,14 @@ package linthost
|
|
|
3
3
|
import (
|
|
4
4
|
"encoding/json"
|
|
5
5
|
"fmt"
|
|
6
|
+
"strings"
|
|
6
7
|
)
|
|
7
8
|
|
|
8
9
|
// expandFormatBlock translates a Prettier-style `format` block into the
|
|
9
10
|
// per-rule severity + options shape the existing rule parsers consume.
|
|
10
11
|
// The result is a `map[string]any` that mirrors what a user would
|
|
11
|
-
// have written under `rules` directly
|
|
12
|
-
// `"format/semi": ["off", {"prefer": "always"}]
|
|
12
|
+
// have written under `rules` directly, entries like
|
|
13
|
+
// `"format/semi": ["off", {"prefer": "always"}]`, so the caller
|
|
13
14
|
// can route it through either `ParseRulesWithOptions` or
|
|
14
15
|
// `parseExternalRuleMapInto` without duplicating option-decoding logic.
|
|
15
16
|
//
|
|
@@ -20,16 +21,27 @@ import (
|
|
|
20
21
|
//
|
|
21
22
|
// The block's enablement matrix:
|
|
22
23
|
//
|
|
23
|
-
// - `format/semi
|
|
24
|
-
// - `format/quotes
|
|
25
|
-
// - `format/
|
|
26
|
-
// - `format/
|
|
27
|
-
// - `format/
|
|
28
|
-
// - `format/
|
|
24
|
+
// - `format/semi`, always on. `semi: false` flips to `prefer: "never"`.
|
|
25
|
+
// - `format/quotes`, always on. `singleQuote: true` flips to `prefer: "single"`.
|
|
26
|
+
// - `format/arrow-parens`, always on. `arrowParens: "avoid"` strips a single bare-identifier arrow parameter's parens; default "always" adds them.
|
|
27
|
+
// - `format/bracket-spacing`, always on. `bracketSpacing: false` removes the inner space of single-line object/destructure/import/export/type braces; default true keeps it.
|
|
28
|
+
// - `format/quote-props`, always on. `quoteProps: "as-needed"` (default) unquotes identifier object keys; "consistent" keeps all keys quoted when any needs it; "preserve" leaves quoting alone.
|
|
29
|
+
// - `format/trailing-comma`, always on with the requested mode.
|
|
30
|
+
// - `format/print-width`, always on, driven by printWidth/tabWidth/useTabs/endOfLine.
|
|
31
|
+
// - `format/clause-join`, always on, joins a single-statement clause body that fits printWidth.
|
|
32
|
+
// - `format/declaration-header`, always on, reflows a class/interface header's type params and heritage clauses.
|
|
33
|
+
// - `format/ternary-nullish-parens`, always on, parenthesizes a `??` operand of a conditional expression.
|
|
34
|
+
// - `format/orphan-semi`, always on; under semi:false, merges a leading-semicolon ASI guard onto its statement.
|
|
35
|
+
// - `format/parameter-properties`, always on, breaks a constructor's parameter list when it has parameter properties.
|
|
36
|
+
// - `format/statement-split`, always on, driven by tabWidth/useTabs/endOfLine.
|
|
37
|
+
// - `format/indent`, always on, driven by tabWidth/useTabs/endOfLine.
|
|
38
|
+
// - `format/whitespace`, always on, driven by endOfLine.
|
|
39
|
+
// - `format/sort-imports`, opt-in by setting `sortImports`.
|
|
40
|
+
// - `format/jsdoc`, always-on; `jsDoc: false` opts out, an object customizes.
|
|
29
41
|
//
|
|
30
42
|
// The returned map is the raw form rules parsers expect. Callers MUST
|
|
31
43
|
// merge any user-supplied `rules` map on top of this one (rules-wins
|
|
32
|
-
// semantics) before invoking the existing parsers
|
|
44
|
+
// semantics) before invoking the existing parsers, `mergeRuleMaps`
|
|
33
45
|
// below performs the merge with the right precedence.
|
|
34
46
|
func expandFormatBlock(raw map[string]any) (map[string]any, error) {
|
|
35
47
|
if raw == nil {
|
|
@@ -60,6 +72,10 @@ func expandFormatBlock(raw map[string]any) (map[string]any, error) {
|
|
|
60
72
|
}
|
|
61
73
|
out["format/semi"] = ruleEntry(map[string]any{"prefer": semiPrefer})
|
|
62
74
|
|
|
75
|
+
// formatOrphanSemi, always on; mirrors the effective semi setting so
|
|
76
|
+
// it only merges the leading-semicolon ASI guard under semi:false.
|
|
77
|
+
out["format/orphan-semi"] = ruleEntry(map[string]any{"semi": semiPrefer == "always"})
|
|
78
|
+
|
|
63
79
|
// formatQuotes
|
|
64
80
|
quotesPrefer := "double"
|
|
65
81
|
if v, ok := raw["singleQuote"]; ok {
|
|
@@ -73,6 +89,56 @@ func expandFormatBlock(raw map[string]any) (map[string]any, error) {
|
|
|
73
89
|
}
|
|
74
90
|
out["format/quotes"] = ruleEntry(map[string]any{"prefer": quotesPrefer})
|
|
75
91
|
|
|
92
|
+
// formatArrowParens, always on. Mirrors Prettier's arrowParens; the
|
|
93
|
+
// default "always" parenthesizes a single bare-identifier arrow parameter,
|
|
94
|
+
// "avoid" strips the parens.
|
|
95
|
+
arrowPrefer := "always"
|
|
96
|
+
if v, ok := raw["arrowParens"]; ok {
|
|
97
|
+
s, err := asString("format.arrowParens", v)
|
|
98
|
+
if err != nil {
|
|
99
|
+
return nil, err
|
|
100
|
+
}
|
|
101
|
+
switch s {
|
|
102
|
+
case "always", "avoid":
|
|
103
|
+
arrowPrefer = s
|
|
104
|
+
default:
|
|
105
|
+
return nil, fmt.Errorf("@ttsc/lint: format.arrowParens must be \"always\" or \"avoid\"; got %q", s)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
out["format/arrow-parens"] = ruleEntry(map[string]any{"prefer": arrowPrefer})
|
|
109
|
+
|
|
110
|
+
// formatBracketSpacing, always on. Mirrors Prettier's bracketSpacing;
|
|
111
|
+
// the default true pads single-line object/destructure/import/export/type
|
|
112
|
+
// braces with one inner space, false removes it.
|
|
113
|
+
bracketSpacing := true
|
|
114
|
+
if v, ok := raw["bracketSpacing"]; ok {
|
|
115
|
+
b, err := asBool("format.bracketSpacing", v)
|
|
116
|
+
if err != nil {
|
|
117
|
+
return nil, err
|
|
118
|
+
}
|
|
119
|
+
bracketSpacing = b
|
|
120
|
+
}
|
|
121
|
+
out["format/bracket-spacing"] = ruleEntry(map[string]any{"spacing": bracketSpacing})
|
|
122
|
+
|
|
123
|
+
// formatQuoteProps, always on. Mirrors Prettier's quoteProps; the default
|
|
124
|
+
// "as-needed" unquotes object keys that are valid identifiers, "consistent"
|
|
125
|
+
// keeps every key quoted when any one needs it, "preserve" leaves quoting
|
|
126
|
+
// untouched.
|
|
127
|
+
quoteProps := "as-needed"
|
|
128
|
+
if v, ok := raw["quoteProps"]; ok {
|
|
129
|
+
s, err := asString("format.quoteProps", v)
|
|
130
|
+
if err != nil {
|
|
131
|
+
return nil, err
|
|
132
|
+
}
|
|
133
|
+
switch s {
|
|
134
|
+
case "as-needed", "consistent", "preserve":
|
|
135
|
+
quoteProps = s
|
|
136
|
+
default:
|
|
137
|
+
return nil, fmt.Errorf("@ttsc/lint: format.quoteProps must be \"as-needed\", \"consistent\", or \"preserve\"; got %q", s)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
out["format/quote-props"] = ruleEntry(map[string]any{"mode": quoteProps})
|
|
141
|
+
|
|
76
142
|
// formatTrailingComma
|
|
77
143
|
tcMode := "all"
|
|
78
144
|
if v, ok := raw["trailingComma"]; ok {
|
|
@@ -95,9 +161,14 @@ func expandFormatBlock(raw map[string]any) (map[string]any, error) {
|
|
|
95
161
|
// the printer's broken-list reflow emits the same trailing-comma
|
|
96
162
|
// shape `format/trailing-comma` does. Without the mirror the two
|
|
97
163
|
// rules disagree on `es5` / `none` projects and oscillate on every
|
|
98
|
-
// cascade pass
|
|
164
|
+
// cascade pass, the trailing-comma rule says "no comma" while the
|
|
99
165
|
// printer adds one back. See `printArgList` in print_nodes_call.go.
|
|
100
|
-
|
|
166
|
+
layoutOpts, err := collectLayoutOpts(raw)
|
|
167
|
+
if err != nil {
|
|
168
|
+
return nil, err
|
|
169
|
+
}
|
|
170
|
+
pwOpts := cloneStringAnyMap(layoutOpts)
|
|
171
|
+
pwOpts["trailingComma"] = tcMode
|
|
101
172
|
if v, ok := raw["printWidth"]; ok {
|
|
102
173
|
n, err := asInt("format.printWidth", v)
|
|
103
174
|
if err != nil {
|
|
@@ -108,116 +179,153 @@ func expandFormatBlock(raw map[string]any) (map[string]any, error) {
|
|
|
108
179
|
}
|
|
109
180
|
pwOpts["printWidth"] = n
|
|
110
181
|
}
|
|
111
|
-
if v, ok := raw["tabWidth"]; ok {
|
|
112
|
-
n, err := asInt("format.tabWidth", v)
|
|
113
|
-
if err != nil {
|
|
114
|
-
return nil, err
|
|
115
|
-
}
|
|
116
|
-
if n < 1 {
|
|
117
|
-
return nil, fmt.Errorf("@ttsc/lint: format.tabWidth must be a positive integer; got %d", n)
|
|
118
|
-
}
|
|
119
|
-
pwOpts["tabWidth"] = n
|
|
120
|
-
}
|
|
121
|
-
if v, ok := raw["useTabs"]; ok {
|
|
122
|
-
b, err := asBool("format.useTabs", v)
|
|
123
|
-
if err != nil {
|
|
124
|
-
return nil, err
|
|
125
|
-
}
|
|
126
|
-
pwOpts["useTabs"] = b
|
|
127
|
-
}
|
|
128
|
-
if v, ok := raw["endOfLine"]; ok {
|
|
129
|
-
s, err := asString("format.endOfLine", v)
|
|
130
|
-
if err != nil {
|
|
131
|
-
return nil, err
|
|
132
|
-
}
|
|
133
|
-
if s != "lf" && s != "crlf" {
|
|
134
|
-
return nil, fmt.Errorf("@ttsc/lint: format.endOfLine must be \"lf\" or \"crlf\"; got %q", s)
|
|
135
|
-
}
|
|
136
|
-
pwOpts["endOfLine"] = s
|
|
137
|
-
}
|
|
138
182
|
out["format/print-width"] = ruleEntry(pwOpts)
|
|
139
183
|
|
|
140
|
-
//
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
184
|
+
// formatClauseJoin, always on. Reuses the printWidth/tabWidth/useTabs
|
|
185
|
+
// budget so it only joins a single-statement clause body back onto its
|
|
186
|
+
// header when the joined line fits. A distinct map instance so it does
|
|
187
|
+
// not alias the print-width blob.
|
|
188
|
+
out["format/clause-join"] = ruleEntry(cloneStringAnyMap(pwOpts))
|
|
189
|
+
|
|
190
|
+
// formatDeclarationHeader, always on. Reflows a class/interface header
|
|
191
|
+
// (type parameters + heritage clauses) to Prettier's break shapes;
|
|
192
|
+
// needs the same printWidth/tabWidth/useTabs budget.
|
|
193
|
+
out["format/declaration-header"] = ruleEntry(cloneStringAnyMap(pwOpts))
|
|
194
|
+
|
|
195
|
+
// formatTernaryNullishParens, always on, no options: wraps a `??`
|
|
196
|
+
// operand of a conditional expression in parentheses (Prettier 3).
|
|
197
|
+
out["format/ternary-nullish-parens"] = ruleEntry(map[string]any{})
|
|
198
|
+
|
|
199
|
+
// formatStatementSplit + formatIndent, always on, Prettier-style.
|
|
200
|
+
// Both reuse the indentation/EOL settings to synthesize line breaks
|
|
201
|
+
// and indent strings. Only the keys the user actually set are mirrored
|
|
202
|
+
// in (same conditional shape as print-width's pwOpts), so defaults are
|
|
203
|
+
// applied rule-side. The two rules share the same option surface
|
|
204
|
+
// collected once into layoutOpts above.
|
|
205
|
+
//
|
|
206
|
+
// Distinct map instances so the two rule entries don't alias one blob.
|
|
207
|
+
out["format/statement-split"] = ruleEntry(cloneStringAnyMap(layoutOpts))
|
|
208
|
+
out["format/indent"] = ruleEntry(cloneStringAnyMap(layoutOpts))
|
|
209
|
+
|
|
210
|
+
// formatParameterProperties, always on. Force-breaks a constructor's
|
|
211
|
+
// parameter list when it declares parameter properties; needs only the
|
|
212
|
+
// indentation settings.
|
|
213
|
+
out["format/parameter-properties"] = ruleEntry(cloneStringAnyMap(layoutOpts))
|
|
214
|
+
|
|
215
|
+
// formatWhitespace, always on. Needs only endOfLine for the final
|
|
216
|
+
// newline; indentation is irrelevant to text hygiene.
|
|
217
|
+
wsOpts := map[string]any{}
|
|
218
|
+
if v, ok := layoutOpts["endOfLine"]; ok {
|
|
219
|
+
wsOpts["endOfLine"] = v
|
|
220
|
+
}
|
|
221
|
+
out["format/whitespace"] = ruleEntry(wsOpts)
|
|
222
|
+
|
|
223
|
+
// formatSortImports, opt-in by `sortImports` (a boolean or options object).
|
|
224
|
+
if v, ok := raw["sortImports"]; ok && v != nil {
|
|
225
|
+
siOpts, enabled, err := expandSortImportsBlock(v)
|
|
144
226
|
if err != nil {
|
|
145
227
|
return nil, err
|
|
146
228
|
}
|
|
147
|
-
if
|
|
148
|
-
|
|
149
|
-
}
|
|
150
|
-
siOpts["importOrder"] = order
|
|
151
|
-
if x, ok := raw["importOrderSeparation"]; ok {
|
|
152
|
-
b, err := asBool("format.importOrderSeparation", x)
|
|
153
|
-
if err != nil {
|
|
154
|
-
return nil, err
|
|
155
|
-
}
|
|
156
|
-
siOpts["importOrderSeparation"] = b
|
|
157
|
-
}
|
|
158
|
-
if x, ok := raw["importOrderSortSpecifiers"]; ok {
|
|
159
|
-
b, err := asBool("format.importOrderSortSpecifiers", x)
|
|
160
|
-
if err != nil {
|
|
161
|
-
return nil, err
|
|
162
|
-
}
|
|
163
|
-
siOpts["importOrderSortSpecifiers"] = b
|
|
164
|
-
}
|
|
165
|
-
if x, ok := raw["importOrderCaseInsensitive"]; ok {
|
|
166
|
-
b, err := asBool("format.importOrderCaseInsensitive", x)
|
|
167
|
-
if err != nil {
|
|
168
|
-
return nil, err
|
|
169
|
-
}
|
|
170
|
-
siOpts["importOrderCaseInsensitive"] = b
|
|
229
|
+
if enabled {
|
|
230
|
+
out["format/sort-imports"] = ruleEntry(siOpts)
|
|
171
231
|
}
|
|
172
|
-
out["format/sort-imports"] = ruleEntry(siOpts)
|
|
173
232
|
}
|
|
174
233
|
|
|
175
|
-
// formatJsdoc
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
234
|
+
// formatJsdoc, always-on. `jsDoc: false` opts out; a
|
|
235
|
+
// `{ tagSynonyms, sortTags }` object customizes it. The config key is
|
|
236
|
+
// camelCased (jsDoc) to match the other multi-word keys; the emitted rule id
|
|
237
|
+
// stays `format/jsdoc`.
|
|
238
|
+
//
|
|
239
|
+
// Today the rule only rewrites tag synonyms (@return → @returns, ...); tag
|
|
240
|
+
// sorting, column alignment, and wrapping are on the roadmap. It is on by
|
|
241
|
+
// default so JSDoc tag names normalize without opt-in, matching the rest of
|
|
242
|
+
// the always-on format set.
|
|
243
|
+
jdOpts := map[string]any{}
|
|
244
|
+
jdEnabled := true
|
|
245
|
+
if v, ok := raw["jsDoc"]; ok && v != nil {
|
|
179
246
|
switch j := v.(type) {
|
|
180
247
|
case bool:
|
|
181
|
-
|
|
248
|
+
jdEnabled = j
|
|
182
249
|
case map[string]any:
|
|
183
|
-
enabled = true
|
|
184
250
|
for key, val := range j {
|
|
185
251
|
switch key {
|
|
186
252
|
case "tagSynonyms":
|
|
187
253
|
ts, ok := val.(map[string]any)
|
|
188
254
|
if !ok {
|
|
189
|
-
return nil, fmt.Errorf("@ttsc/lint: format.
|
|
255
|
+
return nil, fmt.Errorf("@ttsc/lint: format.jsDoc.tagSynonyms must be an object, got %T", val)
|
|
190
256
|
}
|
|
191
257
|
// Element values must be strings; surface
|
|
192
258
|
// typos early instead of after a downstream
|
|
193
259
|
// JSON-decode failure.
|
|
194
260
|
for k, v := range ts {
|
|
195
261
|
if _, ok := v.(string); !ok {
|
|
196
|
-
return nil, fmt.Errorf("@ttsc/lint: format.
|
|
262
|
+
return nil, fmt.Errorf("@ttsc/lint: format.jsDoc.tagSynonyms[%q] must be a string, got %T", k, v)
|
|
197
263
|
}
|
|
198
264
|
}
|
|
199
265
|
jdOpts["tagSynonyms"] = ts
|
|
200
266
|
case "sortTags":
|
|
201
|
-
b, err := asBool("format.
|
|
267
|
+
b, err := asBool("format.jsDoc.sortTags", val)
|
|
202
268
|
if err != nil {
|
|
203
269
|
return nil, err
|
|
204
270
|
}
|
|
205
271
|
jdOpts["sortTags"] = b
|
|
206
272
|
default:
|
|
207
|
-
return nil, fmt.Errorf("@ttsc/lint: format.
|
|
273
|
+
return nil, fmt.Errorf("@ttsc/lint: format.jsDoc unknown key %q (allowed: tagSynonyms, sortTags)", key)
|
|
208
274
|
}
|
|
209
275
|
}
|
|
210
276
|
default:
|
|
211
|
-
return nil, fmt.Errorf("@ttsc/lint: format.
|
|
212
|
-
}
|
|
213
|
-
if enabled {
|
|
214
|
-
out["format/jsdoc"] = ruleEntry(jdOpts)
|
|
277
|
+
return nil, fmt.Errorf("@ttsc/lint: format.jsDoc must be a boolean or object, got %T", v)
|
|
215
278
|
}
|
|
216
279
|
}
|
|
280
|
+
if jdEnabled {
|
|
281
|
+
out["format/jsdoc"] = ruleEntry(jdOpts)
|
|
282
|
+
}
|
|
217
283
|
|
|
218
284
|
return out, nil
|
|
219
285
|
}
|
|
220
286
|
|
|
287
|
+
// expandSortImportsBlock translates the `format.sortImports` value (a boolean
|
|
288
|
+
// or an options object) into the rule's option map. The bool reports whether
|
|
289
|
+
// the rule is enabled: `true` and any object enable it, `false` keeps it off.
|
|
290
|
+
func expandSortImportsBlock(v any) (map[string]any, bool, error) {
|
|
291
|
+
switch sv := v.(type) {
|
|
292
|
+
case bool:
|
|
293
|
+
return map[string]any{}, sv, nil
|
|
294
|
+
case map[string]any:
|
|
295
|
+
opts := map[string]any{}
|
|
296
|
+
for key, val := range sv {
|
|
297
|
+
switch key {
|
|
298
|
+
case "order":
|
|
299
|
+
order, err := asStringSlice("format.sortImports.order", val)
|
|
300
|
+
if err != nil {
|
|
301
|
+
return nil, false, err
|
|
302
|
+
}
|
|
303
|
+
if len(order) == 0 {
|
|
304
|
+
return nil, false, fmt.Errorf("@ttsc/lint: format.sortImports.order must contain at least one entry; omit it to use the default order")
|
|
305
|
+
}
|
|
306
|
+
opts["order"] = order
|
|
307
|
+
case "caseSensitive":
|
|
308
|
+
b, err := asBool("format.sortImports.caseSensitive", val)
|
|
309
|
+
if err != nil {
|
|
310
|
+
return nil, false, err
|
|
311
|
+
}
|
|
312
|
+
opts["caseSensitive"] = b
|
|
313
|
+
case "combineTypeAndValue":
|
|
314
|
+
b, err := asBool("format.sortImports.combineTypeAndValue", val)
|
|
315
|
+
if err != nil {
|
|
316
|
+
return nil, false, err
|
|
317
|
+
}
|
|
318
|
+
opts["combineTypeAndValue"] = b
|
|
319
|
+
default:
|
|
320
|
+
return nil, false, fmt.Errorf("@ttsc/lint: format.sortImports unknown key %q (allowed: order, caseSensitive, combineTypeAndValue)", key)
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return opts, true, nil
|
|
324
|
+
default:
|
|
325
|
+
return nil, false, fmt.Errorf("@ttsc/lint: format.sortImports must be a boolean or object, got %T", v)
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
221
329
|
// formatBlockSeverity extracts the optional `severity` field from a format
|
|
222
330
|
// block. Defaults to SeverityOff so that format rules never produce check/build
|
|
223
331
|
// diagnostics unless the user explicitly opts in. SeverityOff still allows
|
|
@@ -234,12 +342,20 @@ func formatBlockSeverity(raw map[string]any) (Severity, error) {
|
|
|
234
342
|
return severity, nil
|
|
235
343
|
}
|
|
236
344
|
|
|
345
|
+
// isFormatRuleName reports whether `name` is a formatter rule id. Such
|
|
346
|
+
// rules are configured exclusively through the `format` block; a `format/*`
|
|
347
|
+
// key in the user's `rules` map is dropped before the merge, so the config
|
|
348
|
+
// layer never carries a formatter setting in two places.
|
|
349
|
+
func isFormatRuleName(name string) bool {
|
|
350
|
+
return strings.HasPrefix(name, "format/")
|
|
351
|
+
}
|
|
352
|
+
|
|
237
353
|
// mergeRuleMaps overlays `overrides` on `base` and returns the merged
|
|
238
354
|
// map. Identical keys in `overrides` replace the entire entry from
|
|
239
|
-
// `base`; option objects are NOT deep-merged
|
|
240
|
-
//
|
|
241
|
-
//
|
|
242
|
-
//
|
|
355
|
+
// `base`; option objects are NOT deep-merged. `overrides` (the user's
|
|
356
|
+
// `rules` map) never contains a `format/*` key, those are dropped before
|
|
357
|
+
// the merge, so the merge only ever layers lint-rule severities on top of
|
|
358
|
+
// the format block's expanded entries.
|
|
243
359
|
func mergeRuleMaps(base, overrides map[string]any) map[string]any {
|
|
244
360
|
out := make(map[string]any, len(base)+len(overrides))
|
|
245
361
|
for k, v := range base {
|
|
@@ -251,6 +367,56 @@ func mergeRuleMaps(base, overrides map[string]any) map[string]any {
|
|
|
251
367
|
return out
|
|
252
368
|
}
|
|
253
369
|
|
|
370
|
+
// cloneStringAnyMap returns a shallow copy of `m`. expandFormatBlock uses
|
|
371
|
+
// it so `format/statement-split` and `format/indent` each receive their
|
|
372
|
+
// own options blob rather than aliasing one shared map, a later mutation
|
|
373
|
+
// or marshal of one entry then cannot leak into the other.
|
|
374
|
+
func cloneStringAnyMap(m map[string]any) map[string]any {
|
|
375
|
+
out := make(map[string]any, len(m))
|
|
376
|
+
for k, v := range m {
|
|
377
|
+
out[k] = v
|
|
378
|
+
}
|
|
379
|
+
return out
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// collectLayoutOpts parses the shared tabWidth/useTabs/endOfLine layout
|
|
383
|
+
// fields from a format block once. Only keys the user actually set are
|
|
384
|
+
// emitted, so rule-side defaults still apply for absent fields. Both the
|
|
385
|
+
// print-width blob (which adds trailingComma + printWidth) and the
|
|
386
|
+
// statement-split/indent/parameter-properties entries derive from this
|
|
387
|
+
// single source so their parse-and-validate logic stays in one place.
|
|
388
|
+
func collectLayoutOpts(raw map[string]any) (map[string]any, error) {
|
|
389
|
+
layoutOpts := map[string]any{}
|
|
390
|
+
if v, ok := raw["tabWidth"]; ok {
|
|
391
|
+
n, err := asInt("format.tabWidth", v)
|
|
392
|
+
if err != nil {
|
|
393
|
+
return nil, err
|
|
394
|
+
}
|
|
395
|
+
if n < 1 {
|
|
396
|
+
return nil, fmt.Errorf("@ttsc/lint: format.tabWidth must be a positive integer; got %d", n)
|
|
397
|
+
}
|
|
398
|
+
layoutOpts["tabWidth"] = n
|
|
399
|
+
}
|
|
400
|
+
if v, ok := raw["useTabs"]; ok {
|
|
401
|
+
b, err := asBool("format.useTabs", v)
|
|
402
|
+
if err != nil {
|
|
403
|
+
return nil, err
|
|
404
|
+
}
|
|
405
|
+
layoutOpts["useTabs"] = b
|
|
406
|
+
}
|
|
407
|
+
if v, ok := raw["endOfLine"]; ok {
|
|
408
|
+
s, err := asString("format.endOfLine", v)
|
|
409
|
+
if err != nil {
|
|
410
|
+
return nil, err
|
|
411
|
+
}
|
|
412
|
+
if s != "lf" && s != "crlf" {
|
|
413
|
+
return nil, fmt.Errorf("@ttsc/lint: format.endOfLine must be \"lf\" or \"crlf\"; got %q", s)
|
|
414
|
+
}
|
|
415
|
+
layoutOpts["endOfLine"] = s
|
|
416
|
+
}
|
|
417
|
+
return layoutOpts, nil
|
|
418
|
+
}
|
|
419
|
+
|
|
254
420
|
// asBool coerces a raw config value to a bool, returning a typed error on
|
|
255
421
|
// failure. Used by expandFormatBlock to validate boolean format fields.
|
|
256
422
|
func asBool(field string, v any) (bool, error) {
|
|
@@ -295,7 +461,7 @@ func asInt(field string, v any) (int, error) {
|
|
|
295
461
|
}
|
|
296
462
|
|
|
297
463
|
// asStringSlice coerces a raw config value to a []string, returning a typed
|
|
298
|
-
// error on failure. Used by expandFormatBlock to validate
|
|
464
|
+
// error on failure. Used by expandFormatBlock to validate sortImports.order.
|
|
299
465
|
func asStringSlice(field string, v any) ([]string, error) {
|
|
300
466
|
arr, ok := v.([]any)
|
|
301
467
|
if !ok {
|
|
@@ -317,19 +483,19 @@ func asStringSlice(field string, v any) ([]string, error) {
|
|
|
317
483
|
// key set mirrors `ITtscLintFormat` exactly.
|
|
318
484
|
func rejectUnknownFormatKeys(raw map[string]any) error {
|
|
319
485
|
allowed := map[string]struct{}{
|
|
320
|
-
"severity":
|
|
321
|
-
"semi":
|
|
322
|
-
"singleQuote":
|
|
323
|
-
"
|
|
324
|
-
"
|
|
325
|
-
"
|
|
326
|
-
"
|
|
327
|
-
"
|
|
328
|
-
"
|
|
329
|
-
"
|
|
330
|
-
"
|
|
331
|
-
"
|
|
332
|
-
"
|
|
486
|
+
"severity": {},
|
|
487
|
+
"semi": {},
|
|
488
|
+
"singleQuote": {},
|
|
489
|
+
"arrowParens": {},
|
|
490
|
+
"bracketSpacing": {},
|
|
491
|
+
"quoteProps": {},
|
|
492
|
+
"trailingComma": {},
|
|
493
|
+
"printWidth": {},
|
|
494
|
+
"tabWidth": {},
|
|
495
|
+
"useTabs": {},
|
|
496
|
+
"endOfLine": {},
|
|
497
|
+
"sortImports": {},
|
|
498
|
+
"jsDoc": {},
|
|
333
499
|
}
|
|
334
500
|
for key := range raw {
|
|
335
501
|
if _, ok := allowed[key]; !ok {
|
package/linthost/directives.go
CHANGED
|
@@ -194,7 +194,11 @@ scan:
|
|
|
194
194
|
}
|
|
195
195
|
switch directive.kind {
|
|
196
196
|
case lintDirectiveDisableLine:
|
|
197
|
-
|
|
197
|
+
// Key on endLine, not startLine, so a multi-line block-comment
|
|
198
|
+
// `disable-line` reasons about the comment's end the same way
|
|
199
|
+
// disable-next-line does (endLine+1). A single-line comment has
|
|
200
|
+
// startLine == endLine, so same-line suppression is unchanged.
|
|
201
|
+
directives.lines[endLine] = append(directives.lines[endLine], directive.rules)
|
|
198
202
|
case lintDirectiveDisableNextLine:
|
|
199
203
|
directives.lines[endLine+1] = append(directives.lines[endLine+1], directive.rules)
|
|
200
204
|
case lintDirectiveDisable:
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
package linthost
|
|
2
|
+
|
|
3
|
+
import "unicode"
|
|
4
|
+
|
|
5
|
+
// displayWidth returns the number of terminal columns a string occupies,
|
|
6
|
+
// matching Prettier's getStringWidth: an ASCII string's width equals its byte
|
|
7
|
+
// length, a zero-width combining mark counts as zero, and a wide East Asian
|
|
8
|
+
// (or emoji) code point counts as two. Width decisions across the formatter,
|
|
9
|
+
// the layout engine's fit checks and the print-width rule's source measurement,
|
|
10
|
+
// must use display columns rather than byte length, or a multi-byte token (a
|
|
11
|
+
// subscript digit, a Hangul or CJK identifier) is over-counted and the line is
|
|
12
|
+
// wrongly broken.
|
|
13
|
+
//
|
|
14
|
+
// A tab counts as one column here; callers that need tab-stop expansion handle
|
|
15
|
+
// it separately (the layout engine emits indentation outside of Text nodes, so
|
|
16
|
+
// an embedded tab is rare and was already charged as one byte before this).
|
|
17
|
+
func displayWidth(s string) int {
|
|
18
|
+
w := 0
|
|
19
|
+
for _, r := range s {
|
|
20
|
+
w += runeWidth(r)
|
|
21
|
+
}
|
|
22
|
+
return w
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// displayWidthAfterLastNewline returns the display width of the substring that
|
|
26
|
+
// follows the final newline in s (the whole string when it has none). The
|
|
27
|
+
// layout engine uses it to reset the running column after emitting a verbatim
|
|
28
|
+
// slice that spans lines.
|
|
29
|
+
func displayWidthAfterLastNewline(s string) int {
|
|
30
|
+
for i := len(s) - 1; i >= 0; i-- {
|
|
31
|
+
if s[i] == '\n' {
|
|
32
|
+
return displayWidth(s[i+1:])
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return displayWidth(s)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// runeWidth returns the column width of a single rune: zero for a combining
|
|
39
|
+
// mark or zero-width space, two for a wide East Asian or emoji code point, one
|
|
40
|
+
// otherwise (tabs included, see displayWidth).
|
|
41
|
+
func runeWidth(r rune) int {
|
|
42
|
+
if r == 0x200B || unicode.Is(unicode.Mn, r) || unicode.Is(unicode.Me, r) {
|
|
43
|
+
return 0
|
|
44
|
+
}
|
|
45
|
+
if isWideRune(r) {
|
|
46
|
+
return 2
|
|
47
|
+
}
|
|
48
|
+
return 1
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// isWideRune reports whether a rune renders in two terminal columns, covering
|
|
52
|
+
// the East Asian Wide / Fullwidth ranges and the common emoji blocks the way
|
|
53
|
+
// Prettier's width table does.
|
|
54
|
+
func isWideRune(r rune) bool {
|
|
55
|
+
switch {
|
|
56
|
+
case r >= 0x1100 && r <= 0x115F, // Hangul Jamo
|
|
57
|
+
r >= 0x2E80 && r <= 0x303E, // CJK Radicals .. CJK Symbols (part)
|
|
58
|
+
r >= 0x3041 && r <= 0x33FF, // Hiragana .. CJK Compatibility
|
|
59
|
+
r >= 0x3400 && r <= 0x4DBF, // CJK Extension A
|
|
60
|
+
r >= 0x4E00 && r <= 0x9FFF, // CJK Unified Ideographs
|
|
61
|
+
r >= 0xA000 && r <= 0xA4CF, // Yi
|
|
62
|
+
r >= 0xAC00 && r <= 0xD7A3, // Hangul Syllables
|
|
63
|
+
r >= 0xF900 && r <= 0xFAFF, // CJK Compatibility Ideographs
|
|
64
|
+
r >= 0xFE30 && r <= 0xFE4F, // CJK Compatibility Forms
|
|
65
|
+
r >= 0xFF00 && r <= 0xFF60, // Fullwidth Forms
|
|
66
|
+
r >= 0xFFE0 && r <= 0xFFE6, // Fullwidth signs
|
|
67
|
+
r >= 0x1F300 && r <= 0x1FAFF, // emoji & pictographs
|
|
68
|
+
r >= 0x20000 && r <= 0x3FFFD: // CJK Extension B and beyond
|
|
69
|
+
return true
|
|
70
|
+
}
|
|
71
|
+
return false
|
|
72
|
+
}
|
package/linthost/fix.go
CHANGED
|
@@ -43,7 +43,14 @@ func runFix(opts *subcommandOpts) int {
|
|
|
43
43
|
fmt.Fprintln(os.Stderr, err)
|
|
44
44
|
return 2
|
|
45
45
|
}
|
|
46
|
-
|
|
46
|
+
// `ttsc fix` is the run-everything entry point: lint fixes AND formatter
|
|
47
|
+
// edits. Formatting is configured solely through the `format` block (a
|
|
48
|
+
// format/* key in `rules` is dropped), so wrap the resolver the same way
|
|
49
|
+
// `ttsc format` and the LSP paths do — formatCommandResolver force-
|
|
50
|
+
// activates the format rules the format block configured. A project with
|
|
51
|
+
// no format block populates no format options, so nothing extra is enabled
|
|
52
|
+
// and fix stays a pure lint pass.
|
|
53
|
+
engine := NewEngineWithResolver(formatCommandResolver{inner: rules})
|
|
47
54
|
engine.SetSerial(opts.singleThreaded)
|
|
48
55
|
needsRuleChecker := engine.NeedsTypeChecker()
|
|
49
56
|
|
|
@@ -258,12 +265,30 @@ func selectTextEdits(sourceLen int, edits []TextEdit) []TextEdit {
|
|
|
258
265
|
|
|
259
266
|
selected := make([]TextEdit, 0, len(sorted))
|
|
260
267
|
lastEnd := -1
|
|
268
|
+
// lastInsertAt marks the offset of the previously-selected edit when that
|
|
269
|
+
// edit was a zero-width insert (Pos==End), else -1. A new zero-width
|
|
270
|
+
// insert at that same offset must be dropped: two coincident inserts both
|
|
271
|
+
// pass the `edit.Pos < lastEnd` gate, then apply in reverse sort order and
|
|
272
|
+
// concatenate at one point — silently corrupting the source (e.g. a `;`
|
|
273
|
+
// insert and a `\n` insert at EOF yielding `\n;`). The host contract keeps
|
|
274
|
+
// one winner and drops the rest (see rule.TextEdit). A zero-width insert
|
|
275
|
+
// sitting at the end of a prior NON-empty edit is left alone: it applies
|
|
276
|
+
// cleanly after the replacement and is a legitimate adjacency.
|
|
277
|
+
lastInsertAt := -1
|
|
261
278
|
for _, edit := range sorted {
|
|
262
279
|
if edit.Pos < lastEnd {
|
|
263
280
|
continue
|
|
264
281
|
}
|
|
282
|
+
if edit.Pos == edit.End && edit.Pos == lastInsertAt {
|
|
283
|
+
continue
|
|
284
|
+
}
|
|
265
285
|
selected = append(selected, edit)
|
|
266
286
|
lastEnd = edit.End
|
|
287
|
+
if edit.Pos == edit.End {
|
|
288
|
+
lastInsertAt = edit.Pos
|
|
289
|
+
} else {
|
|
290
|
+
lastInsertAt = -1
|
|
291
|
+
}
|
|
267
292
|
}
|
|
268
293
|
return selected
|
|
269
294
|
}
|