@ttsc/lint 0.13.0 → 0.14.0-dev.20250530.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +955 -85
- package/lib/defaultFormat.d.ts +15 -8
- package/lib/defaultFormat.js +15 -8
- package/lib/defaultFormat.js.map +1 -1
- package/lib/index.d.ts +46 -0
- package/lib/index.js +60 -37
- package/lib/index.js.map +1 -1
- package/lib/structures/ITtscLintConfig.d.ts +12 -6
- package/lib/structures/TtscLintRuleSetting.d.ts +49 -0
- package/lib/structures/{TtscLintRuleOptions.js → TtscLintRuleSetting.js} +1 -1
- package/lib/structures/TtscLintRuleSetting.js.map +1 -0
- package/lib/structures/format/ITtscLintFormat.d.ts +128 -0
- package/lib/structures/{TtscLintRuleMap.js → format/ITtscLintFormat.js} +1 -1
- package/lib/structures/format/ITtscLintFormat.js.map +1 -0
- package/lib/structures/format/ITtscLintFormatJsDoc.d.ts +17 -0
- package/lib/structures/{ITtscLintFormatConfig.js → format/ITtscLintFormatJsDoc.js} +1 -1
- 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 +3 -4
- package/lib/structures/index.js +3 -4
- package/lib/structures/index.js.map +1 -1
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.d.ts +95 -0
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js +13 -0
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintBoundariesRules.d.ts +75 -0
- package/lib/structures/rules/ITtscLintBoundariesRules.js +3 -0
- package/lib/structures/rules/ITtscLintBoundariesRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintContributorRules.d.ts +16 -0
- package/lib/structures/rules/ITtscLintContributorRules.js +3 -0
- package/lib/structures/rules/ITtscLintContributorRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintCoreRules.d.ts +1229 -0
- package/lib/structures/rules/ITtscLintCoreRules.js +3 -0
- package/lib/structures/rules/ITtscLintCoreRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintCypressRuleOptions.d.ts +17 -0
- package/lib/structures/rules/ITtscLintCypressRuleOptions.js +10 -0
- package/lib/structures/rules/ITtscLintCypressRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintCypressRules.d.ts +125 -0
- package/lib/structures/rules/ITtscLintCypressRules.js +3 -0
- package/lib/structures/rules/ITtscLintCypressRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintFunctionalRuleOptions.d.ts +154 -0
- package/lib/structures/rules/ITtscLintFunctionalRuleOptions.js +13 -0
- package/lib/structures/rules/ITtscLintFunctionalRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintFunctionalRules.d.ts +162 -0
- package/lib/structures/rules/ITtscLintFunctionalRules.js +3 -0
- package/lib/structures/rules/ITtscLintFunctionalRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintJestRules.d.ts +190 -0
- package/lib/structures/rules/ITtscLintJestRules.js +3 -0
- package/lib/structures/rules/ITtscLintJestRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintJsdocRules.d.ts +133 -0
- package/lib/structures/rules/ITtscLintJsdocRules.js +3 -0
- package/lib/structures/rules/ITtscLintJsdocRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintJsxA11yRules.d.ts +294 -0
- package/lib/structures/rules/ITtscLintJsxA11yRules.js +3 -0
- package/lib/structures/rules/ITtscLintJsxA11yRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintNextjsRules.d.ts +180 -0
- package/lib/structures/rules/ITtscLintNextjsRules.js +3 -0
- package/lib/structures/rules/ITtscLintNextjsRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintPlaywrightRules.d.ts +312 -0
- package/lib/structures/rules/ITtscLintPlaywrightRules.js +3 -0
- package/lib/structures/rules/ITtscLintPlaywrightRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintPromiseRules.d.ts +179 -0
- package/lib/structures/rules/ITtscLintPromiseRules.js +3 -0
- package/lib/structures/rules/ITtscLintPromiseRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintReactPerfRuleOptions.d.ts +18 -0
- package/lib/structures/rules/ITtscLintReactPerfRuleOptions.js +8 -0
- package/lib/structures/rules/ITtscLintReactPerfRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintReactPerfRules.d.ts +49 -0
- package/lib/structures/rules/ITtscLintReactPerfRules.js +3 -0
- package/lib/structures/rules/ITtscLintReactPerfRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintReactRuleOptions.d.ts +37 -0
- package/lib/structures/rules/ITtscLintReactRuleOptions.js +11 -0
- package/lib/structures/rules/ITtscLintReactRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintReactRules.d.ts +276 -0
- package/lib/structures/rules/ITtscLintReactRules.js +3 -0
- package/lib/structures/rules/ITtscLintReactRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintRegexpRules.d.ts +182 -0
- package/lib/structures/rules/ITtscLintRegexpRules.js +3 -0
- package/lib/structures/rules/ITtscLintRegexpRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintRuleOptionsMap.d.ts +65 -0
- package/lib/structures/rules/ITtscLintRuleOptionsMap.js +3 -0
- package/lib/structures/rules/ITtscLintRuleOptionsMap.js.map +1 -0
- package/lib/structures/rules/ITtscLintRules.d.ts +55 -0
- package/lib/structures/{TtscLintRule.js → rules/ITtscLintRules.js} +1 -1
- package/lib/structures/rules/ITtscLintRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintSecurityRules.d.ts +141 -0
- package/lib/structures/rules/ITtscLintSecurityRules.js +3 -0
- package/lib/structures/rules/ITtscLintSecurityRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintSolidRules.d.ts +178 -0
- package/lib/structures/rules/ITtscLintSolidRules.js +3 -0
- package/lib/structures/rules/ITtscLintSolidRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintStorybookRuleOptions.d.ts +20 -0
- package/lib/structures/rules/ITtscLintStorybookRuleOptions.js +9 -0
- package/lib/structures/rules/ITtscLintStorybookRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintStorybookRules.d.ts +165 -0
- package/lib/structures/rules/ITtscLintStorybookRules.js +3 -0
- package/lib/structures/rules/ITtscLintStorybookRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintTanstackQueryRules.d.ts +88 -0
- package/lib/structures/rules/ITtscLintTanstackQueryRules.js +3 -0
- package/lib/structures/rules/ITtscLintTanstackQueryRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.d.ts +21 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.js +10 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRules.d.ts +293 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRules.js +3 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintTypeScriptRules.d.ts +1074 -0
- package/lib/structures/rules/ITtscLintTypeScriptRules.js +3 -0
- package/lib/structures/rules/ITtscLintTypeScriptRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintUnicornRules.d.ts +997 -0
- package/lib/structures/rules/ITtscLintUnicornRules.js +3 -0
- package/lib/structures/rules/ITtscLintUnicornRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintVitestRules.d.ts +133 -0
- package/lib/structures/rules/ITtscLintVitestRules.js +3 -0
- package/lib/structures/rules/ITtscLintVitestRules.js.map +1 -0
- package/lib/structures/rules/index.d.ts +31 -0
- package/lib/structures/rules/index.js +48 -0
- package/lib/structures/rules/index.js.map +1 -0
- package/linthost/ast_helpers.go +30 -5
- package/linthost/compile.go +33 -2
- package/linthost/config.go +118 -71
- package/linthost/config_format.go +270 -104
- package/linthost/directives.go +67 -25
- package/linthost/dispatch.go +14 -3
- package/linthost/engine.go +160 -40
- package/linthost/fix.go +10 -3
- package/linthost/flags_gen.go +17 -15
- package/linthost/format.go +222 -25
- package/linthost/format_editor_settings.go +262 -0
- package/linthost/host.go +40 -3
- package/linthost/lsp.go +898 -0
- package/linthost/print_dispatch.go +5 -2
- package/linthost/print_engine.go +5 -5
- package/linthost/print_nodes_call.go +149 -67
- package/linthost/print_nodes_function.go +27 -2
- package/linthost/print_nodes_list.go +40 -5
- package/linthost/print_nodes_object.go +1 -1
- package/linthost/print_nodes_ternary.go +86 -0
- package/linthost/rule_names.go +14 -0
- package/linthost/rules_arrays.go +2 -2
- package/linthost/rules_boundaries.go +532 -0
- package/linthost/rules_camelcase.go +133 -0
- package/linthost/rules_complexity.go +95 -0
- package/linthost/rules_consistent_return.go +130 -0
- package/linthost/rules_console.go +1 -1
- package/linthost/rules_core_extra.go +739 -0
- package/linthost/rules_curly.go +70 -0
- package/linthost/rules_cypress.go +608 -0
- package/linthost/rules_debugger.go +2 -2
- package/linthost/rules_default_case.go +39 -0
- package/linthost/rules_default_case_last.go +46 -0
- package/linthost/rules_dupes.go +3 -3
- package/linthost/rules_empty.go +3 -3
- package/linthost/rules_escape.go +44 -24
- package/linthost/rules_eval.go +2 -2
- package/linthost/rules_finally.go +2 -2
- 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 +595 -0
- package/linthost/rules_format_indent.go +372 -0
- package/linthost/rules_format_jsdoc.go +5 -5
- 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 +66 -55
- package/linthost/rules_format_quote_props.go +169 -0
- package/linthost/rules_format_quotes.go +76 -30
- package/linthost/rules_format_semi.go +186 -11
- package/linthost/rules_format_sort_imports.go +437 -118
- package/linthost/rules_format_statement_split.go +343 -0
- package/linthost/rules_format_ternary_nullish_parens.go +77 -0
- package/linthost/rules_format_trailing_comma.go +22 -3
- package/linthost/rules_format_whitespace.go +336 -0
- package/linthost/rules_functional.go +967 -0
- package/linthost/rules_gap.go +24 -45
- package/linthost/rules_grouped_accessor_pairs.go +87 -0
- package/linthost/rules_guard_for_in.go +198 -0
- package/linthost/rules_id_length.go +77 -0
- package/linthost/rules_imports.go +70 -2
- package/linthost/rules_init_declarations.go +53 -0
- package/linthost/rules_jest.go +618 -0
- package/linthost/rules_jsdoc.go +502 -0
- package/linthost/rules_jsx_a11y.go +1264 -0
- package/linthost/rules_logic.go +12 -12
- package/linthost/rules_loops.go +1 -1
- package/linthost/rules_max_classes_per_file.go +58 -0
- package/linthost/rules_max_depth.go +83 -0
- package/linthost/rules_max_lines.go +101 -0
- package/linthost/rules_max_lines_per_function.go +57 -0
- package/linthost/rules_max_nested_callbacks.go +61 -0
- package/linthost/rules_max_params.go +49 -0
- package/linthost/rules_max_statements.go +59 -0
- package/linthost/rules_misc.go +1 -1
- package/linthost/rules_nextjs.go +697 -0
- package/linthost/rules_no_else_return.go +75 -0
- package/linthost/rules_no_empty_named_blocks.go +91 -0
- package/linthost/rules_no_extend_native.go +51 -0
- package/linthost/rules_no_import_assign.go +140 -0
- package/linthost/rules_no_invalid_this.go +52 -0
- package/linthost/rules_no_loop_func.go +85 -0
- package/linthost/rules_no_magic_numbers.go +123 -0
- package/linthost/rules_no_mixed_operators.go +80 -0
- package/linthost/rules_no_param_reassign.go +98 -0
- package/linthost/rules_no_redeclare.go +270 -0
- package/linthost/rules_no_restricted_imports.go +105 -0
- package/linthost/rules_no_restricted_syntax.go +49 -0
- package/linthost/rules_no_shadow.go +147 -0
- package/linthost/rules_no_unreachable.go +77 -0
- package/linthost/rules_no_useless_assignment.go +120 -0
- package/linthost/rules_no_useless_constructor.go +245 -0
- package/linthost/rules_no_useless_return.go +51 -0
- package/linthost/rules_params.go +1 -1
- package/linthost/rules_playwright.go +788 -0
- package/linthost/rules_prefer_arrow_callback.go +124 -0
- package/linthost/rules_prefer_destructuring.go +98 -0
- package/linthost/rules_prefer_named_capture_group.go +129 -0
- package/linthost/rules_prefer_rest_params.go +94 -0
- package/linthost/rules_problems.go +41 -30
- package/linthost/rules_promise.go +1057 -2
- package/linthost/rules_protos.go +2 -2
- package/linthost/rules_react.go +773 -0
- package/linthost/rules_react_extras.go +227 -0
- package/linthost/rules_react_hooks.go +848 -0
- package/linthost/rules_react_perf.go +293 -0
- package/linthost/rules_react_refresh.go +583 -0
- package/linthost/rules_regexp.go +410 -0
- package/linthost/rules_security.go +830 -0
- package/linthost/rules_self.go +2 -2
- package/linthost/rules_solid.go +1073 -0
- package/linthost/rules_sort_imports.go +69 -0
- package/linthost/rules_sort_keys.go +134 -0
- package/linthost/rules_storybook.go +1176 -0
- package/linthost/rules_strings.go +4 -4
- package/linthost/rules_suggestions.go +38 -38
- package/linthost/rules_tanstack_query.go +844 -0
- package/linthost/rules_testing_library.go +1204 -0
- package/linthost/rules_throw.go +1 -1
- package/linthost/rules_ts.go +19 -19
- package/linthost/rules_ts_async.go +399 -0
- package/linthost/rules_ts_class_literal_property_style.go +115 -0
- package/linthost/rules_ts_consistent_type_exports.go +256 -0
- package/linthost/rules_ts_explicit_function_return_type.go +67 -0
- package/linthost/rules_ts_extra.go +159 -36
- package/linthost/rules_ts_no_base_to_string.go +218 -0
- package/linthost/rules_ts_no_confusing_void.go +72 -0
- package/linthost/rules_ts_no_deprecated.go +195 -0
- package/linthost/rules_ts_no_for_in_array.go +84 -0
- package/linthost/rules_ts_no_magic_numbers.go +124 -0
- package/linthost/rules_ts_no_meaningless_void_operator.go +84 -0
- package/linthost/rules_ts_no_misused_spread.go +104 -0
- package/linthost/rules_ts_no_redundant_type_constituents.go +113 -0
- package/linthost/rules_ts_no_restricted_types.go +62 -0
- package/linthost/rules_ts_no_unnecessary_boolean_literal_compare.go +129 -0
- package/linthost/rules_ts_no_unnecessary_condition.go +250 -0
- package/linthost/rules_ts_no_unnecessary_qualifier.go +118 -0
- package/linthost/rules_ts_no_unnecessary_template_expression.go +178 -0
- package/linthost/rules_ts_no_unnecessary_type_arguments.go +234 -0
- package/linthost/rules_ts_no_unnecessary_type_assertion.go +157 -0
- package/linthost/rules_ts_no_unsafe_argument.go +82 -0
- package/linthost/rules_ts_no_unsafe_assignment.go +102 -0
- package/linthost/rules_ts_no_unsafe_call.go +82 -0
- package/linthost/rules_ts_no_unsafe_enum_comparison.go +235 -0
- package/linthost/rules_ts_no_unsafe_member_access.go +58 -0
- package/linthost/rules_ts_no_unsafe_return.go +126 -0
- package/linthost/rules_ts_no_unsafe_unary_minus.go +81 -0
- package/linthost/rules_ts_no_useless_constructor.go +52 -0
- package/linthost/rules_ts_non_nullable_type_assertion_style.go +108 -0
- package/linthost/rules_ts_parameter_properties.go +38 -0
- package/linthost/rules_ts_prefer_find.go +178 -0
- package/linthost/rules_ts_prefer_includes.go +255 -0
- package/linthost/rules_ts_prefer_nullish_coalescing.go +104 -0
- package/linthost/rules_ts_prefer_optional_chain.go +228 -0
- package/linthost/rules_ts_prefer_promise_reject_errors.go +176 -0
- package/linthost/rules_ts_prefer_readonly.go +73 -0
- package/linthost/rules_ts_prefer_reduce_type_parameter.go +116 -0
- package/linthost/rules_ts_prefer_regexp_exec.go +122 -0
- package/linthost/rules_ts_prefer_return_this_type.go +135 -0
- package/linthost/rules_ts_prefer_string_starts_ends_with.go +360 -0
- package/linthost/rules_ts_promise_function_async.go +77 -0
- package/linthost/rules_ts_related_getter_setter_pairs.go +113 -0
- package/linthost/rules_ts_require_array_sort_compare.go +96 -0
- package/linthost/rules_ts_restrict_plus_operands.go +127 -0
- package/linthost/rules_ts_restrict_template_expressions.go +95 -0
- package/linthost/rules_ts_simple.go +387 -0
- package/linthost/rules_ts_sort_type_constituents.go +144 -0
- package/linthost/rules_ts_strict_boolean_expressions.go +157 -0
- package/linthost/rules_ts_switch_exhaustiveness_check.go +147 -0
- package/linthost/rules_ts_unbound_method.go +126 -0
- package/linthost/rules_tsdoc.go +136 -0
- package/linthost/rules_unicorn_better_regex.go +27 -0
- package/linthost/rules_unicorn_catch_error_name.go +46 -0
- package/linthost/rules_unicorn_consistent_assert.go +47 -0
- package/linthost/rules_unicorn_consistent_date_clone.go +54 -0
- package/linthost/rules_unicorn_consistent_destructuring.go +25 -0
- package/linthost/rules_unicorn_consistent_empty_array_spread.go +62 -0
- package/linthost/rules_unicorn_consistent_existence_index_check.go +80 -0
- package/linthost/rules_unicorn_consistent_function_scoping.go +25 -0
- package/linthost/rules_unicorn_consistent_template_literal_escape.go +25 -0
- package/linthost/rules_unicorn_custom_error_definition.go +138 -0
- package/linthost/rules_unicorn_empty_brace_spaces.go +73 -0
- package/linthost/rules_unicorn_error_message.go +64 -0
- package/linthost/rules_unicorn_escape_case.go +51 -0
- package/linthost/rules_unicorn_expiring_todo_comments.go +78 -0
- package/linthost/rules_unicorn_explicit_length_check.go +88 -0
- package/linthost/rules_unicorn_filename_case.go +29 -0
- package/linthost/rules_unicorn_import_style.go +28 -0
- package/linthost/rules_unicorn_isolated_functions.go +29 -0
- package/linthost/rules_unicorn_new_for_builtins.go +87 -0
- package/linthost/rules_unicorn_no_abusive_eslint_disable.go +63 -0
- package/linthost/rules_unicorn_no_accessor_recursion.go +115 -0
- package/linthost/rules_unicorn_no_anonymous_default_export.go +74 -0
- package/linthost/rules_unicorn_no_array_callback_reference.go +65 -0
- package/linthost/rules_unicorn_no_array_for_each.go +40 -0
- package/linthost/rules_unicorn_no_array_method_this_argument.go +61 -0
- package/linthost/rules_unicorn_no_array_reduce.go +41 -0
- package/linthost/rules_unicorn_no_array_reverse.go +44 -0
- package/linthost/rules_unicorn_no_array_sort.go +43 -0
- package/linthost/rules_unicorn_no_await_expression_member.go +40 -0
- package/linthost/rules_unicorn_no_await_in_promise_methods.go +69 -0
- package/linthost/rules_unicorn_no_console_spaces.go +61 -0
- package/linthost/rules_unicorn_no_document_cookie.go +41 -0
- package/linthost/rules_unicorn_no_empty_file.go +44 -0
- package/linthost/rules_unicorn_no_for_loop.go +102 -0
- package/linthost/rules_unicorn_no_hex_escape.go +42 -0
- package/linthost/rules_unicorn_no_immediate_mutation.go +90 -0
- package/linthost/rules_unicorn_no_instanceof_builtins.go +66 -0
- package/linthost/rules_unicorn_no_invalid_fetch_options.go +79 -0
- package/linthost/rules_unicorn_no_invalid_remove_event_listener.go +51 -0
- package/linthost/rules_unicorn_no_keyword_prefix.go +101 -0
- package/linthost/rules_unicorn_no_lonely_if.go +44 -0
- package/linthost/rules_unicorn_no_magic_array_flat_depth.go +51 -0
- package/linthost/rules_unicorn_no_named_default.go +54 -0
- package/linthost/rules_unicorn_no_negated_condition.go +85 -0
- package/linthost/rules_unicorn_no_negation_in_equality_check.go +50 -0
- package/linthost/rules_unicorn_no_nested_ternary.go +43 -0
- package/linthost/rules_unicorn_no_new_array.go +30 -0
- package/linthost/rules_unicorn_no_new_buffer.go +31 -0
- package/linthost/rules_unicorn_no_null.go +24 -0
- package/linthost/rules_unicorn_no_object_as_default_parameter.go +48 -0
- package/linthost/rules_unicorn_no_process_exit.go +43 -0
- package/linthost/rules_unicorn_no_single_promise_in_promise_methods.go +59 -0
- package/linthost/rules_unicorn_no_static_only_class.go +56 -0
- package/linthost/rules_unicorn_no_thenable.go +74 -0
- package/linthost/rules_unicorn_no_this_assignment.go +35 -0
- package/linthost/rules_unicorn_no_typeof_undefined.go +58 -0
- package/linthost/rules_unicorn_no_unnecessary_array_flat_depth.go +49 -0
- package/linthost/rules_unicorn_no_unnecessary_array_splice_count.go +70 -0
- package/linthost/rules_unicorn_no_unnecessary_await.go +51 -0
- package/linthost/rules_unicorn_no_unnecessary_polyfills.go +32 -0
- package/linthost/rules_unicorn_no_unnecessary_slice_end.go +48 -0
- package/linthost/rules_unicorn_no_unreadable_array_destructuring.go +115 -0
- package/linthost/rules_unicorn_no_unreadable_iife.go +50 -0
- package/linthost/rules_unicorn_no_unused_properties.go +30 -0
- package/linthost/rules_unicorn_no_useless_collection_argument.go +63 -0
- package/linthost/rules_unicorn_no_useless_error_capture_stack_trace.go +46 -0
- package/linthost/rules_unicorn_no_useless_fallback_in_spread.go +81 -0
- package/linthost/rules_unicorn_no_useless_iterator_to_array.go +72 -0
- package/linthost/rules_unicorn_no_useless_length_check.go +144 -0
- package/linthost/rules_unicorn_no_useless_promise_resolve_reject.go +81 -0
- package/linthost/rules_unicorn_no_useless_spread.go +67 -0
- package/linthost/rules_unicorn_no_useless_switch_case.go +55 -0
- package/linthost/rules_unicorn_no_useless_undefined.go +55 -0
- package/linthost/rules_unicorn_no_zero_fractions.go +52 -0
- package/linthost/rules_unicorn_number_literal_case.go +69 -0
- package/linthost/rules_unicorn_numeric_separators_style.go +75 -0
- package/linthost/rules_unicorn_prefer_add_event_listener.go +66 -0
- package/linthost/rules_unicorn_prefer_array_find.go +51 -0
- package/linthost/rules_unicorn_prefer_array_flat.go +52 -0
- package/linthost/rules_unicorn_prefer_array_flat_map.go +63 -0
- package/linthost/rules_unicorn_prefer_array_index_of.go +147 -0
- package/linthost/rules_unicorn_prefer_array_some.go +67 -0
- package/linthost/rules_unicorn_prefer_at.go +77 -0
- package/linthost/rules_unicorn_prefer_bigint_literals.go +77 -0
- package/linthost/rules_unicorn_prefer_blob_reading_methods.go +44 -0
- package/linthost/rules_unicorn_prefer_class_fields.go +93 -0
- package/linthost/rules_unicorn_prefer_classlist_toggle.go +120 -0
- package/linthost/rules_unicorn_prefer_code_point.go +49 -0
- package/linthost/rules_unicorn_prefer_date_now.go +78 -0
- package/linthost/rules_unicorn_prefer_default_parameters.go +144 -0
- package/linthost/rules_unicorn_prefer_dom_node_append.go +40 -0
- package/linthost/rules_unicorn_prefer_dom_node_dataset.go +55 -0
- package/linthost/rules_unicorn_prefer_dom_node_remove.go +41 -0
- package/linthost/rules_unicorn_prefer_dom_node_text_content.go +37 -0
- package/linthost/rules_unicorn_prefer_event_target.go +36 -0
- package/linthost/rules_unicorn_prefer_export_from.go +129 -0
- package/linthost/rules_unicorn_prefer_global_this.go +127 -0
- package/linthost/rules_unicorn_prefer_import_meta_properties.go +66 -0
- package/linthost/rules_unicorn_prefer_includes.go +149 -0
- package/linthost/rules_unicorn_prefer_json_parse_buffer.go +65 -0
- package/linthost/rules_unicorn_prefer_keyboard_event_key.go +38 -0
- package/linthost/rules_unicorn_prefer_logical_operator_over_ternary.go +48 -0
- package/linthost/rules_unicorn_prefer_math_min_max.go +60 -0
- package/linthost/rules_unicorn_prefer_math_trunc.go +62 -0
- package/linthost/rules_unicorn_prefer_modern_dom_apis.go +47 -0
- package/linthost/rules_unicorn_prefer_modern_math_apis.go +70 -0
- package/linthost/rules_unicorn_prefer_module.go +50 -0
- package/linthost/rules_unicorn_prefer_native_coercion_functions.go +114 -0
- package/linthost/rules_unicorn_prefer_negative_index.go +74 -0
- package/linthost/rules_unicorn_prefer_node_protocol.go +122 -0
- package/linthost/rules_unicorn_prefer_number_properties.go +88 -0
- package/linthost/rules_unicorn_prefer_object_from_entries.go +55 -0
- package/linthost/rules_unicorn_prefer_optional_catch_binding.go +62 -0
- package/linthost/rules_unicorn_prefer_prototype_methods.go +54 -0
- package/linthost/rules_unicorn_prefer_query_selector.go +56 -0
- package/linthost/rules_unicorn_prefer_reflect_apply.go +36 -0
- package/linthost/rules_unicorn_prefer_regexp_test_rule.go +80 -0
- package/linthost/rules_unicorn_prefer_response_static_json.go +53 -0
- package/linthost/rules_unicorn_prefer_set_has.go +42 -0
- package/linthost/rules_unicorn_prefer_set_size.go +48 -0
- package/linthost/rules_unicorn_prefer_simple_condition_first.go +34 -0
- package/linthost/rules_unicorn_prefer_single_call.go +96 -0
- package/linthost/rules_unicorn_prefer_spread.go +51 -0
- package/linthost/rules_unicorn_prefer_string_raw.go +43 -0
- package/linthost/rules_unicorn_prefer_string_replace_all.go +95 -0
- package/linthost/rules_unicorn_prefer_string_slice.go +43 -0
- package/linthost/rules_unicorn_prefer_string_starts_ends_with.go +148 -0
- package/linthost/rules_unicorn_prefer_string_trim_start_end.go +48 -0
- package/linthost/rules_unicorn_prefer_structured_clone.go +71 -0
- package/linthost/rules_unicorn_prefer_switch.go +103 -0
- package/linthost/rules_unicorn_prefer_ternary.go +71 -0
- package/linthost/rules_unicorn_prefer_top_level_await.go +72 -0
- package/linthost/rules_unicorn_prefer_type_error.go +127 -0
- package/linthost/rules_unicorn_prevent_abbreviations.go +127 -0
- package/linthost/rules_unicorn_relative_url_style.go +49 -0
- package/linthost/rules_unicorn_require_array_join_separator.go +45 -0
- package/linthost/rules_unicorn_require_module_attributes.go +54 -0
- package/linthost/rules_unicorn_require_module_specifiers.go +55 -0
- package/linthost/rules_unicorn_require_number_to_fixed_digits_argument.go +43 -0
- package/linthost/rules_unicorn_require_post_message_target_origin.go +44 -0
- package/linthost/rules_unicorn_string_content.go +27 -0
- package/linthost/rules_unicorn_switch_case_braces.go +42 -0
- package/linthost/rules_unicorn_switch_case_break_position.go +31 -0
- package/linthost/rules_unicorn_template_indent.go +28 -0
- package/linthost/rules_unicorn_text_encoding_identifier_case.go +72 -0
- package/linthost/rules_unicorn_throw_new_error.go +61 -0
- package/linthost/rules_var.go +10 -4
- package/linthost/rules_vitest.go +568 -0
- package/package.json +3 -3
- package/plugin/main.go +49 -3
- package/rule/astutil/astutil.go +10 -3
- package/rule/rule.go +12 -10
- package/src/defaultFormat.ts +17 -10
- package/src/index.ts +65 -43
- package/src/structures/ITtscLintConfig.ts +14 -8
- package/src/structures/TtscLintRuleSetting.ts +55 -0
- package/src/structures/format/ITtscLintFormat.ts +141 -0
- package/src/structures/format/ITtscLintFormatJsDoc.ts +18 -0
- package/src/structures/format/ITtscLintFormatSortImports.ts +62 -0
- package/src/structures/format/index.ts +3 -0
- package/src/structures/index.ts +3 -4
- package/src/structures/rules/ITtscLintBoundariesRuleOptions.ts +117 -0
- package/src/structures/rules/ITtscLintBoundariesRules.ts +91 -0
- package/src/structures/rules/ITtscLintContributorRules.ts +20 -0
- package/src/structures/rules/ITtscLintCoreRules.ts +1378 -0
- package/src/structures/rules/ITtscLintCypressRuleOptions.ts +18 -0
- package/src/structures/rules/ITtscLintCypressRules.ts +141 -0
- package/src/structures/rules/ITtscLintFunctionalRuleOptions.ts +200 -0
- package/src/structures/rules/ITtscLintFunctionalRules.ts +197 -0
- package/src/structures/rules/ITtscLintJestRules.ts +209 -0
- package/src/structures/rules/ITtscLintJsdocRules.ts +146 -0
- package/src/structures/rules/ITtscLintJsxA11yRules.ts +331 -0
- package/src/structures/rules/ITtscLintNextjsRules.ts +201 -0
- package/src/structures/rules/ITtscLintPlaywrightRules.ts +343 -0
- package/src/structures/rules/ITtscLintPromiseRules.ts +196 -0
- package/src/structures/rules/ITtscLintReactPerfRuleOptions.ts +19 -0
- package/src/structures/rules/ITtscLintReactPerfRules.ts +53 -0
- package/src/structures/rules/ITtscLintReactRuleOptions.ts +41 -0
- package/src/structures/rules/ITtscLintReactRules.ts +308 -0
- package/src/structures/rules/ITtscLintRegexpRules.ts +204 -0
- package/src/structures/rules/ITtscLintRuleOptionsMap.ts +88 -0
- package/src/structures/rules/ITtscLintRules.ts +77 -0
- package/src/structures/rules/ITtscLintSecurityRules.ts +155 -0
- package/src/structures/rules/ITtscLintSolidRules.ts +199 -0
- package/src/structures/rules/ITtscLintStorybookRuleOptions.ts +22 -0
- package/src/structures/rules/ITtscLintStorybookRules.ts +184 -0
- package/src/structures/rules/ITtscLintTanstackQueryRules.ts +96 -0
- package/src/structures/rules/ITtscLintTestingLibraryRuleOptions.ts +23 -0
- package/src/structures/rules/ITtscLintTestingLibraryRules.ts +325 -0
- package/src/structures/rules/ITtscLintTypeScriptRules.ts +1172 -0
- package/src/structures/rules/ITtscLintUnicornRules.ts +1143 -0
- package/src/structures/rules/ITtscLintVitestRules.ts +146 -0
- package/src/structures/rules/index.ts +31 -0
- package/lib/structures/ITtscLintFormatConfig.d.ts +0 -153
- package/lib/structures/ITtscLintFormatConfig.js.map +0 -1
- package/lib/structures/TtscLintRule.d.ts +0 -17
- package/lib/structures/TtscLintRule.js.map +0 -1
- package/lib/structures/TtscLintRuleMap.d.ts +0 -46
- package/lib/structures/TtscLintRuleMap.js.map +0 -1
- package/lib/structures/TtscLintRuleOptions.d.ts +0 -137
- package/lib/structures/TtscLintRuleOptions.js.map +0 -1
- package/src/structures/ITtscLintFormatConfig.ts +0 -168
- package/src/structures/TtscLintRule.ts +0 -160
- package/src/structures/TtscLintRuleMap.ts +0 -55
- package/src/structures/TtscLintRuleOptions.ts +0 -151
|
@@ -9,50 +9,59 @@ import (
|
|
|
9
9
|
shimscanner "github.com/microsoft/typescript-go/shim/scanner"
|
|
10
10
|
)
|
|
11
11
|
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
const
|
|
12
|
+
// Group-order placeholders accepted inside the `order` option. They mirror
|
|
13
|
+
// `@ianvs/prettier-plugin-sort-imports`: a single declarative array expresses
|
|
14
|
+
// group order, blank-line separation, and special groups all by position.
|
|
15
|
+
const (
|
|
16
|
+
// builtinModulesPlaceholder buckets Node built-in modules (`fs`,
|
|
17
|
+
// `node:path`, `fs/promises`, ...).
|
|
18
|
+
builtinModulesPlaceholder = "<BUILTIN_MODULES>"
|
|
19
|
+
// thirdPartyModulesPlaceholder absorbs any specifier that matched no
|
|
20
|
+
// earlier explicit group.
|
|
21
|
+
thirdPartyModulesPlaceholder = "<THIRD_PARTY_MODULES>"
|
|
22
|
+
// typesPlaceholderPrefix marks the group of `import type` declarations.
|
|
23
|
+
// A regex may follow (`<TYPES>^[.]`) to scope the group to matching
|
|
24
|
+
// specifiers.
|
|
25
|
+
typesPlaceholderPrefix = "<TYPES>"
|
|
26
|
+
// separatorPlaceholder ("") emits one blank line at its position.
|
|
27
|
+
separatorPlaceholder = ""
|
|
28
|
+
)
|
|
16
29
|
|
|
17
|
-
// formatSortImportsOptions mirrors `
|
|
30
|
+
// formatSortImportsOptions mirrors `ITtscLintFormatSortImports`.
|
|
18
31
|
type formatSortImportsOptions struct {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
// (
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
//
|
|
32
|
+
Order []string `json:"order"`
|
|
33
|
+
CaseSensitive bool `json:"caseSensitive"`
|
|
34
|
+
CombineTypeAndValue bool `json:"combineTypeAndValue"`
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// defaultImportOrder mirrors `@ianvs/prettier-plugin-sort-imports`' default
|
|
38
|
+
// `importOrder`: Node built-ins, then third-party catch-all, then relative
|
|
39
|
+
// imports. No `""` entries, so the default emits no blank lines between
|
|
40
|
+
// groups (blank lines are opt-in by position).
|
|
41
|
+
var defaultImportOrder = []string{
|
|
42
|
+
builtinModulesPlaceholder,
|
|
43
|
+
thirdPartyModulesPlaceholder,
|
|
44
|
+
`^[.]`,
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// formatSortImports orders the file's top-level import declarations into
|
|
48
|
+
// canonical groups, alphabetizes each group, merges duplicate imports of the
|
|
49
|
+
// same module, and (when `combineTypeAndValue` is on) folds a type-only
|
|
50
|
+
// import into a value import of the same module. Modeled on
|
|
51
|
+
// `@ianvs/prettier-plugin-sort-imports`. Groups are user-configurable via the
|
|
52
|
+
// `order` option; when omitted, the rule falls back to {@link
|
|
53
|
+
// defaultImportOrder}.
|
|
40
54
|
//
|
|
41
|
-
//
|
|
42
|
-
// `
|
|
43
|
-
//
|
|
44
|
-
// when `importOrderCaseInsensitive: true`). Named specifiers inside each
|
|
45
|
-
// declaration are alphabetized when `importOrderSortSpecifiers` is true
|
|
46
|
-
// (the default).
|
|
55
|
+
// Within each group, declarations are sorted by their module-specifier text
|
|
56
|
+
// (ASCII order, or case-insensitive unless `caseSensitive: true`). Named
|
|
57
|
+
// specifiers inside each declaration are always sorted.
|
|
47
58
|
//
|
|
48
59
|
// Safety policy: if any byte between the contiguous imports is not
|
|
49
60
|
// whitespace, the rule bails. Comments anchored to specific imports would
|
|
50
61
|
// otherwise move with the wrong declaration, which is a strictly worse
|
|
51
|
-
// outcome than declining to sort.
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
// (`import * as ns from`), default imports, and `import type` all
|
|
55
|
-
// participate in the same group based on their module specifier.
|
|
62
|
+
// outcome than declining to sort. Side-effect imports (`import "foo"`) also
|
|
63
|
+
// bail the whole block because their evaluation order can carry meaning the
|
|
64
|
+
// rule cannot reason about.
|
|
56
65
|
type formatSortImports struct{}
|
|
57
66
|
|
|
58
67
|
func (formatSortImports) Name() string { return "format/sort-imports" }
|
|
@@ -80,7 +89,7 @@ func (formatSortImports) Check(ctx *Context, node *shimast.Node) {
|
|
|
80
89
|
// its module's top-level code for its observable effect; sorting it
|
|
81
90
|
// across a sibling import that depends on the polyfill being
|
|
82
91
|
// initialized first would silently change runtime behavior. The
|
|
83
|
-
// rule conservatively refuses to
|
|
92
|
+
// rule conservatively refuses to reorder the entire block in that
|
|
84
93
|
// case.
|
|
85
94
|
if len(imports) >= 2 &&
|
|
86
95
|
leadingTriviaIsAllWhitespace(src, imports) &&
|
|
@@ -101,11 +110,8 @@ func (formatSortImports) Check(ctx *Context, node *shimast.Node) {
|
|
|
101
110
|
return
|
|
102
111
|
}
|
|
103
112
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
for _, decl := range collectLeadingImports(statements.Nodes) {
|
|
108
|
-
reportNamedSpecifierSort(ctx, decl, opts.caseInsensitive)
|
|
113
|
+
for _, decl := range imports {
|
|
114
|
+
reportNamedSpecifierSort(ctx, decl, opts.caseSensitive)
|
|
109
115
|
}
|
|
110
116
|
}
|
|
111
117
|
|
|
@@ -113,63 +119,93 @@ func (formatSortImports) Check(ctx *Context, node *shimast.Node) {
|
|
|
113
119
|
// during one Check call. All option defaults are applied here so the
|
|
114
120
|
// rest of the rule code does not branch on nil-ness.
|
|
115
121
|
type resolvedSortImportsOptions struct {
|
|
116
|
-
groups
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
caseInsensitive bool
|
|
122
|
+
groups []sortImportsGroup
|
|
123
|
+
caseSensitive bool
|
|
124
|
+
combineTypeAndValue bool
|
|
120
125
|
}
|
|
121
126
|
|
|
127
|
+
// sortImportsGroup is one resolved entry of the `order` array. A separator
|
|
128
|
+
// entry ("") is not a real group; it is folded into the following group's
|
|
129
|
+
// sepBefore flag during parsing and never appears in the resolved list.
|
|
122
130
|
type sortImportsGroup struct {
|
|
123
131
|
raw string
|
|
124
|
-
pattern *regexp.Regexp
|
|
132
|
+
pattern *regexp.Regexp // nil for placeholder groups without a regex
|
|
125
133
|
thirdParty bool
|
|
134
|
+
builtin bool
|
|
135
|
+
typesOnly bool // <TYPES> group: matches `import type` declarations
|
|
136
|
+
sepBefore bool // a "" preceded this group in the `order` array
|
|
126
137
|
}
|
|
127
138
|
|
|
128
139
|
func loadSortImportsOptions(ctx *Context) resolvedSortImportsOptions {
|
|
129
140
|
var raw formatSortImportsOptions
|
|
130
141
|
_ = ctx.DecodeOptions(&raw)
|
|
131
|
-
order := raw.
|
|
142
|
+
order := raw.Order
|
|
132
143
|
if len(order) == 0 {
|
|
133
144
|
order = defaultImportOrder
|
|
134
145
|
}
|
|
146
|
+
groups := parseImportOrder(order)
|
|
147
|
+
return resolvedSortImportsOptions{
|
|
148
|
+
groups: groups,
|
|
149
|
+
caseSensitive: raw.CaseSensitive,
|
|
150
|
+
combineTypeAndValue: raw.CombineTypeAndValue,
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// parseImportOrder turns the raw `order` array into resolved groups. "" entries
|
|
155
|
+
// fold into the next group's sepBefore flag. A third-party catch-all is
|
|
156
|
+
// appended when the user omitted one so unmatched specifiers always land in a
|
|
157
|
+
// real group.
|
|
158
|
+
func parseImportOrder(order []string) []sortImportsGroup {
|
|
135
159
|
groups := make([]sortImportsGroup, 0, len(order))
|
|
160
|
+
pendingSep := false
|
|
136
161
|
for _, pat := range order {
|
|
137
|
-
if pat ==
|
|
138
|
-
|
|
162
|
+
if pat == separatorPlaceholder {
|
|
163
|
+
pendingSep = true
|
|
139
164
|
continue
|
|
140
165
|
}
|
|
141
|
-
|
|
142
|
-
if
|
|
166
|
+
group, ok := compileImportOrderGroup(pat)
|
|
167
|
+
if !ok {
|
|
143
168
|
// Bad regex: skip the group rather than failing the entire run.
|
|
144
|
-
//
|
|
145
|
-
//
|
|
169
|
+
// Users see "no match" behavior instead of a crash; a stray
|
|
170
|
+
// separator in front of the skipped group carries to the next.
|
|
146
171
|
continue
|
|
147
172
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
// Empty `importOrder` collapses to the third-party catchall so the
|
|
152
|
-
// rule still produces a deterministic ordering.
|
|
153
|
-
groups = []sortImportsGroup{{raw: thirdPartyModulesPlaceholder, thirdParty: true}}
|
|
173
|
+
group.sepBefore = pendingSep
|
|
174
|
+
pendingSep = false
|
|
175
|
+
groups = append(groups, group)
|
|
154
176
|
}
|
|
155
|
-
// Ensure a third-party catchall exists; if the user omitted it,
|
|
156
|
-
// append one so unmatched specifiers don't land in a phantom group.
|
|
157
177
|
if !hasThirdPartyGroup(groups) {
|
|
158
178
|
groups = append(groups, sortImportsGroup{raw: thirdPartyModulesPlaceholder, thirdParty: true})
|
|
159
179
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
180
|
+
return groups
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// compileImportOrderGroup resolves one non-separator `order` entry into a
|
|
184
|
+
// group. The bool is false only when a regex entry fails to compile.
|
|
185
|
+
func compileImportOrderGroup(pat string) (sortImportsGroup, bool) {
|
|
186
|
+
switch {
|
|
187
|
+
case pat == builtinModulesPlaceholder:
|
|
188
|
+
return sortImportsGroup{raw: pat, builtin: true}, true
|
|
189
|
+
case pat == thirdPartyModulesPlaceholder:
|
|
190
|
+
return sortImportsGroup{raw: pat, thirdParty: true}, true
|
|
191
|
+
case strings.HasPrefix(pat, typesPlaceholderPrefix):
|
|
192
|
+
rest := strings.TrimPrefix(pat, typesPlaceholderPrefix)
|
|
193
|
+
group := sortImportsGroup{raw: pat, typesOnly: true}
|
|
194
|
+
if rest == "" {
|
|
195
|
+
return group, true
|
|
196
|
+
}
|
|
197
|
+
compiled, err := regexp.Compile(rest)
|
|
198
|
+
if err != nil {
|
|
199
|
+
return sortImportsGroup{}, false
|
|
200
|
+
}
|
|
201
|
+
group.pattern = compiled
|
|
202
|
+
return group, true
|
|
203
|
+
default:
|
|
204
|
+
compiled, err := regexp.Compile(pat)
|
|
205
|
+
if err != nil {
|
|
206
|
+
return sortImportsGroup{}, false
|
|
207
|
+
}
|
|
208
|
+
return sortImportsGroup{raw: pat, pattern: compiled}, true
|
|
173
209
|
}
|
|
174
210
|
}
|
|
175
211
|
|
|
@@ -184,32 +220,64 @@ func hasThirdPartyGroup(groups []sortImportsGroup) bool {
|
|
|
184
220
|
return false
|
|
185
221
|
}
|
|
186
222
|
|
|
187
|
-
// matchGroup returns the index of the first group that claims
|
|
188
|
-
//
|
|
189
|
-
//
|
|
190
|
-
|
|
223
|
+
// matchGroup returns the index of the first group that claims a declaration
|
|
224
|
+
// with the given specifier and type-only flag. Groups are checked in order, so
|
|
225
|
+
// a `<TYPES>` group placed ahead of a regex group claims type-only imports
|
|
226
|
+
// first; the third-party catchall absorbs anything left over.
|
|
227
|
+
func matchGroup(groups []sortImportsGroup, specifier string, typeOnly bool) int {
|
|
191
228
|
thirdPartyIdx := -1
|
|
192
229
|
for i, g := range groups {
|
|
193
|
-
|
|
230
|
+
switch {
|
|
231
|
+
case g.thirdParty:
|
|
194
232
|
if thirdPartyIdx < 0 {
|
|
195
233
|
thirdPartyIdx = i
|
|
196
234
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
235
|
+
case g.builtin:
|
|
236
|
+
if isBuiltinModule(specifier) {
|
|
237
|
+
return i
|
|
238
|
+
}
|
|
239
|
+
case g.typesOnly:
|
|
240
|
+
if typeOnly && (g.pattern == nil || g.pattern.MatchString(specifier)) {
|
|
241
|
+
return i
|
|
242
|
+
}
|
|
243
|
+
case g.pattern != nil && g.pattern.MatchString(specifier):
|
|
200
244
|
return i
|
|
201
245
|
}
|
|
202
246
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
247
|
+
return thirdPartyIdx
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// nodeBuiltinModules is the set of Node.js built-in module names recognized by
|
|
251
|
+
// the `<BUILTIN_MODULES>` group. A `node:` prefix and a `pkg/subpath` suffix
|
|
252
|
+
// are both stripped before the lookup.
|
|
253
|
+
var nodeBuiltinModules = map[string]struct{}{
|
|
254
|
+
"assert": {}, "async_hooks": {}, "buffer": {}, "child_process": {},
|
|
255
|
+
"cluster": {}, "console": {}, "constants": {}, "crypto": {},
|
|
256
|
+
"dgram": {}, "diagnostics_channel": {}, "dns": {}, "domain": {},
|
|
257
|
+
"events": {}, "fs": {}, "http": {}, "http2": {}, "https": {},
|
|
258
|
+
"inspector": {}, "module": {}, "net": {}, "os": {}, "path": {},
|
|
259
|
+
"perf_hooks": {}, "process": {}, "punycode": {}, "querystring": {},
|
|
260
|
+
"readline": {}, "repl": {}, "stream": {}, "string_decoder": {},
|
|
261
|
+
"sys": {}, "test": {}, "timers": {}, "tls": {}, "trace_events": {},
|
|
262
|
+
"tty": {}, "url": {}, "util": {}, "v8": {}, "vm": {}, "wasi": {},
|
|
263
|
+
"worker_threads": {}, "zlib": {},
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// isBuiltinModule reports whether the specifier names a Node.js built-in
|
|
267
|
+
// module. `node:fs`, `fs`, and `fs/promises` all qualify.
|
|
268
|
+
func isBuiltinModule(specifier string) bool {
|
|
269
|
+
name := strings.TrimPrefix(specifier, "node:")
|
|
270
|
+
if slash := strings.IndexByte(name, '/'); slash >= 0 {
|
|
271
|
+
name = name[:slash]
|
|
272
|
+
}
|
|
273
|
+
_, ok := nodeBuiltinModules[name]
|
|
274
|
+
return ok
|
|
207
275
|
}
|
|
208
276
|
|
|
209
277
|
// specifierListHasCommentTrivia returns true when the source between
|
|
210
278
|
// adjacent specifiers contains any byte that is not whitespace,
|
|
211
279
|
// comma, or whitespace-equivalent. A `/* x */` or `// x` inside the
|
|
212
|
-
// list anchors the rule into a no-op
|
|
280
|
+
// list anchors the rule into a no-op, sorting would re-emit the
|
|
213
281
|
// specifier texts joined with `", "` and silently drop the comment.
|
|
214
282
|
func specifierListHasCommentTrivia(src string, specifiers []*shimast.Node) bool {
|
|
215
283
|
for i := 1; i < len(specifiers); i++ {
|
|
@@ -284,29 +352,52 @@ func leadingTriviaIsAllWhitespace(src string, imports []*shimast.Node) bool {
|
|
|
284
352
|
return true
|
|
285
353
|
}
|
|
286
354
|
|
|
287
|
-
//
|
|
288
|
-
// the
|
|
355
|
+
// siSpec is one named import specifier captured for merge/sort: its local
|
|
356
|
+
// name drives the sort key, its source text is re-emitted verbatim, and the
|
|
357
|
+
// type-only flag of the owning declaration drives `combineTypeAndValue`
|
|
358
|
+
// promotion.
|
|
359
|
+
type siSpec struct {
|
|
360
|
+
sortKey string
|
|
361
|
+
text string
|
|
362
|
+
fromTypeOnlyDecl bool
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// siDecl is the parsed shape of one import declaration used by the block
|
|
366
|
+
// rebuilder. Declarations with a namespace binding are not mergeable and are
|
|
367
|
+
// re-emitted from their original text.
|
|
368
|
+
type siDecl struct {
|
|
369
|
+
specifier string
|
|
370
|
+
specRaw string
|
|
371
|
+
typeOnly bool
|
|
372
|
+
defaultName string
|
|
373
|
+
named []siSpec
|
|
374
|
+
hasNamed bool
|
|
375
|
+
namespace bool
|
|
376
|
+
original string
|
|
377
|
+
semicolon bool
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// siEntry is a (possibly merged) import declaration ready to be grouped,
|
|
381
|
+
// sorted, and emitted.
|
|
382
|
+
type siEntry struct {
|
|
383
|
+
group int
|
|
384
|
+
specifier string
|
|
385
|
+
sortKey string
|
|
386
|
+
typeOnly bool
|
|
387
|
+
text string
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// buildSortedImportBlock returns the canonical group/sort/merge representation
|
|
391
|
+
// of the contiguous import declarations.
|
|
289
392
|
func buildSortedImportBlock(src string, imports []*shimast.Node, opts resolvedSortImportsOptions) string {
|
|
290
|
-
|
|
291
|
-
group int
|
|
292
|
-
specifier string
|
|
293
|
-
sortKey string
|
|
294
|
-
text string
|
|
295
|
-
}
|
|
296
|
-
entries := make([]entry, 0, len(imports))
|
|
393
|
+
decls := make([]siDecl, 0, len(imports))
|
|
297
394
|
for _, decl := range imports {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
entries = append(entries, entry{
|
|
305
|
-
group: matchGroup(opts.groups, spec),
|
|
306
|
-
specifier: spec,
|
|
307
|
-
sortKey: sortKey,
|
|
308
|
-
text: text,
|
|
309
|
-
})
|
|
395
|
+
decls = append(decls, parseImportDecl(src, decl))
|
|
396
|
+
}
|
|
397
|
+
entries := mergeImportDecls(decls, opts)
|
|
398
|
+
for i := range entries {
|
|
399
|
+
entries[i].group = matchGroup(opts.groups, entries[i].specifier, entries[i].typeOnly)
|
|
400
|
+
entries[i].sortKey = foldCase(entries[i].specifier, opts.caseSensitive)
|
|
310
401
|
}
|
|
311
402
|
sort.SliceStable(entries, func(i, j int) bool {
|
|
312
403
|
if entries[i].group != entries[j].group {
|
|
@@ -319,7 +410,7 @@ func buildSortedImportBlock(src string, imports []*shimast.Node, opts resolvedSo
|
|
|
319
410
|
prevGroup := entries[0].group
|
|
320
411
|
for i, e := range entries {
|
|
321
412
|
if i > 0 {
|
|
322
|
-
if e.group != prevGroup && opts.
|
|
413
|
+
if e.group != prevGroup && separatorBetween(opts.groups, prevGroup, e.group) {
|
|
323
414
|
b.WriteString("\n\n")
|
|
324
415
|
} else {
|
|
325
416
|
b.WriteString("\n")
|
|
@@ -331,6 +422,214 @@ func buildSortedImportBlock(src string, imports []*shimast.Node, opts resolvedSo
|
|
|
331
422
|
return b.String()
|
|
332
423
|
}
|
|
333
424
|
|
|
425
|
+
// separatorBetween reports whether a blank line should sit between two
|
|
426
|
+
// consecutive (in sorted output) groups. Groups skipped because they had no
|
|
427
|
+
// imports still contribute their sepBefore flag, so `[A, "", B]` with an empty
|
|
428
|
+
// A and B that both fall through to a later group collapses to one blank line.
|
|
429
|
+
func separatorBetween(groups []sortImportsGroup, prev, curr int) bool {
|
|
430
|
+
for k := prev + 1; k <= curr && k < len(groups); k++ {
|
|
431
|
+
if groups[k].sepBefore {
|
|
432
|
+
return true
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
return false
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// parseImportDecl captures the merge-relevant shape of one import declaration.
|
|
439
|
+
func parseImportDecl(src string, decl *shimast.Node) siDecl {
|
|
440
|
+
out := siDecl{
|
|
441
|
+
specifier: moduleSpecifierText(decl),
|
|
442
|
+
specRaw: moduleSpecifierRaw(src, decl),
|
|
443
|
+
original: importStatementText(src, decl),
|
|
444
|
+
}
|
|
445
|
+
out.semicolon = strings.HasSuffix(out.original, ";")
|
|
446
|
+
imp := decl.AsImportDeclaration()
|
|
447
|
+
if imp == nil || imp.ImportClause == nil {
|
|
448
|
+
return out
|
|
449
|
+
}
|
|
450
|
+
clause := imp.ImportClause.AsImportClause()
|
|
451
|
+
if clause == nil {
|
|
452
|
+
return out
|
|
453
|
+
}
|
|
454
|
+
out.typeOnly = clause.PhaseModifier == shimast.KindTypeKeyword
|
|
455
|
+
out.defaultName = identifierText(clause.Name())
|
|
456
|
+
if clause.NamedBindings == nil {
|
|
457
|
+
return out
|
|
458
|
+
}
|
|
459
|
+
if clause.NamedBindings.Kind == shimast.KindNamespaceImport {
|
|
460
|
+
out.namespace = true
|
|
461
|
+
return out
|
|
462
|
+
}
|
|
463
|
+
if clause.NamedBindings.Kind != shimast.KindNamedImports {
|
|
464
|
+
return out
|
|
465
|
+
}
|
|
466
|
+
named := clause.NamedBindings.AsNamedImports()
|
|
467
|
+
if named == nil || named.Elements == nil {
|
|
468
|
+
return out
|
|
469
|
+
}
|
|
470
|
+
out.hasNamed = true
|
|
471
|
+
for _, spec := range named.Elements.Nodes {
|
|
472
|
+
s := spec.AsImportSpecifier()
|
|
473
|
+
if s == nil {
|
|
474
|
+
continue
|
|
475
|
+
}
|
|
476
|
+
start := shimscanner.SkipTrivia(src, spec.Pos())
|
|
477
|
+
out.named = append(out.named, siSpec{
|
|
478
|
+
sortKey: identifierText(s.Name()),
|
|
479
|
+
text: src[start:spec.End()],
|
|
480
|
+
fromTypeOnlyDecl: out.typeOnly,
|
|
481
|
+
})
|
|
482
|
+
}
|
|
483
|
+
return out
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// mergeImportDecls collapses declarations of the same module into one entry.
|
|
487
|
+
// Same-module value imports always merge; same-module type-only imports always
|
|
488
|
+
// merge; a value import and a type-only import of the same module merge only
|
|
489
|
+
// when `combineTypeAndValue` is set. Namespace imports and merge conflicts fall
|
|
490
|
+
// back to one entry per original declaration.
|
|
491
|
+
func mergeImportDecls(decls []siDecl, opts resolvedSortImportsOptions) []siEntry {
|
|
492
|
+
order := make([]string, 0, len(decls))
|
|
493
|
+
buckets := make(map[string][]siDecl)
|
|
494
|
+
for _, d := range decls {
|
|
495
|
+
key := mergeKey(d, opts.combineTypeAndValue)
|
|
496
|
+
if _, seen := buckets[key]; !seen {
|
|
497
|
+
order = append(order, key)
|
|
498
|
+
}
|
|
499
|
+
buckets[key] = append(buckets[key], d)
|
|
500
|
+
}
|
|
501
|
+
entries := make([]siEntry, 0, len(decls))
|
|
502
|
+
for _, key := range order {
|
|
503
|
+
entries = append(entries, mergeBucket(buckets[key], opts)...)
|
|
504
|
+
}
|
|
505
|
+
return entries
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// mergeKey groups declarations that are eligible to merge. Namespace imports
|
|
509
|
+
// get a unique key (a per-declaration counter via the original text plus a
|
|
510
|
+
// sentinel) so they never merge.
|
|
511
|
+
func mergeKey(d siDecl, combine bool) string {
|
|
512
|
+
if d.namespace {
|
|
513
|
+
return "\x00ns\x00" + d.original
|
|
514
|
+
}
|
|
515
|
+
if combine || !d.typeOnly {
|
|
516
|
+
return "v\x00" + d.specifier
|
|
517
|
+
}
|
|
518
|
+
return "t\x00" + d.specifier
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// mergeBucket renders a bucket of same-key declarations. A single declaration
|
|
522
|
+
// (or an unmergeable conflict) is emitted from its original text; otherwise the
|
|
523
|
+
// declarations fold into one rebuilt statement.
|
|
524
|
+
func mergeBucket(group []siDecl, opts resolvedSortImportsOptions) []siEntry {
|
|
525
|
+
if len(group) == 1 {
|
|
526
|
+
return []siEntry{originalEntry(group[0])}
|
|
527
|
+
}
|
|
528
|
+
text, typeOnly, ok := renderMergedDecl(group, opts)
|
|
529
|
+
if !ok {
|
|
530
|
+
out := make([]siEntry, 0, len(group))
|
|
531
|
+
for _, d := range group {
|
|
532
|
+
out = append(out, originalEntry(d))
|
|
533
|
+
}
|
|
534
|
+
return out
|
|
535
|
+
}
|
|
536
|
+
return []siEntry{{specifier: group[0].specifier, typeOnly: typeOnly, text: text}}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// originalEntry wraps one declaration's untouched source text as an entry.
|
|
540
|
+
func originalEntry(d siDecl) siEntry {
|
|
541
|
+
return siEntry{specifier: d.specifier, typeOnly: d.typeOnly, text: d.original}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// renderMergedDecl folds a bucket of mergeable declarations into one statement.
|
|
545
|
+
// The bool is false when the declarations cannot be merged (conflicting default
|
|
546
|
+
// names, or a type-only default that cannot survive in a mixed value import).
|
|
547
|
+
func renderMergedDecl(group []siDecl, opts resolvedSortImportsOptions) (string, bool, bool) {
|
|
548
|
+
mergedTypeOnly := true
|
|
549
|
+
for _, d := range group {
|
|
550
|
+
if !d.typeOnly {
|
|
551
|
+
mergedTypeOnly = false
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
defaultName := ""
|
|
555
|
+
defaultTypeOnly := false
|
|
556
|
+
for _, d := range group {
|
|
557
|
+
if d.defaultName == "" {
|
|
558
|
+
continue
|
|
559
|
+
}
|
|
560
|
+
if defaultName != "" && defaultName != d.defaultName {
|
|
561
|
+
return "", false, false
|
|
562
|
+
}
|
|
563
|
+
defaultName = d.defaultName
|
|
564
|
+
defaultTypeOnly = d.typeOnly
|
|
565
|
+
}
|
|
566
|
+
// A type-only default cannot be expressed inside a mixed value import
|
|
567
|
+
// (`import type Foo, { value }` would retype `value`).
|
|
568
|
+
if defaultName != "" && defaultTypeOnly && !mergedTypeOnly {
|
|
569
|
+
return "", false, false
|
|
570
|
+
}
|
|
571
|
+
specs := collectMergedSpecs(group, mergedTypeOnly, opts.caseSensitive)
|
|
572
|
+
if defaultName == "" && len(specs) == 0 {
|
|
573
|
+
return "", false, false
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
var b strings.Builder
|
|
577
|
+
b.WriteString("import ")
|
|
578
|
+
if mergedTypeOnly {
|
|
579
|
+
b.WriteString("type ")
|
|
580
|
+
}
|
|
581
|
+
if defaultName != "" {
|
|
582
|
+
b.WriteString(defaultName)
|
|
583
|
+
if len(specs) > 0 {
|
|
584
|
+
b.WriteString(", ")
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
if len(specs) > 0 {
|
|
588
|
+
b.WriteString("{ ")
|
|
589
|
+
b.WriteString(strings.Join(specs, ", "))
|
|
590
|
+
b.WriteString(" }")
|
|
591
|
+
}
|
|
592
|
+
b.WriteString(" from ")
|
|
593
|
+
b.WriteString(group[0].specRaw)
|
|
594
|
+
if group[0].semicolon {
|
|
595
|
+
b.WriteString(";")
|
|
596
|
+
}
|
|
597
|
+
return b.String(), mergedTypeOnly, true
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// collectMergedSpecs gathers, de-duplicates, and sorts the named specifiers of
|
|
601
|
+
// a merged declaration. A specifier from a type-only declaration folded into a
|
|
602
|
+
// mixed value import gains an inline `type ` prefix.
|
|
603
|
+
func collectMergedSpecs(group []siDecl, mergedTypeOnly, caseSensitive bool) []string {
|
|
604
|
+
type keyed struct {
|
|
605
|
+
sortKey string
|
|
606
|
+
text string
|
|
607
|
+
}
|
|
608
|
+
seen := make(map[string]struct{})
|
|
609
|
+
items := make([]keyed, 0)
|
|
610
|
+
for _, d := range group {
|
|
611
|
+
for _, s := range d.named {
|
|
612
|
+
text := s.text
|
|
613
|
+
if s.fromTypeOnlyDecl && !mergedTypeOnly && !strings.HasPrefix(text, "type ") {
|
|
614
|
+
text = "type " + text
|
|
615
|
+
}
|
|
616
|
+
if _, dup := seen[text]; dup {
|
|
617
|
+
continue
|
|
618
|
+
}
|
|
619
|
+
seen[text] = struct{}{}
|
|
620
|
+
items = append(items, keyed{sortKey: foldCase(s.sortKey, caseSensitive), text: text})
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
sort.SliceStable(items, func(i, j int) bool {
|
|
624
|
+
return items[i].sortKey < items[j].sortKey
|
|
625
|
+
})
|
|
626
|
+
texts := make([]string, len(items))
|
|
627
|
+
for i, it := range items {
|
|
628
|
+
texts[i] = it.text
|
|
629
|
+
}
|
|
630
|
+
return texts
|
|
631
|
+
}
|
|
632
|
+
|
|
334
633
|
// importStatementText returns the import declaration's source text,
|
|
335
634
|
// stripped of any leading whitespace/comment trivia.
|
|
336
635
|
func importStatementText(src string, decl *shimast.Node) string {
|
|
@@ -355,6 +654,30 @@ func moduleSpecifierText(decl *shimast.Node) string {
|
|
|
355
654
|
return stringLiteralText(imp.ModuleSpecifier)
|
|
356
655
|
}
|
|
357
656
|
|
|
657
|
+
// moduleSpecifierRaw returns the module specifier's source text including its
|
|
658
|
+
// surrounding quotes, so a merged declaration preserves the original quote
|
|
659
|
+
// style.
|
|
660
|
+
func moduleSpecifierRaw(src string, decl *shimast.Node) string {
|
|
661
|
+
imp := decl.AsImportDeclaration()
|
|
662
|
+
if imp == nil || imp.ModuleSpecifier == nil {
|
|
663
|
+
return ""
|
|
664
|
+
}
|
|
665
|
+
start := shimscanner.SkipTrivia(src, imp.ModuleSpecifier.Pos())
|
|
666
|
+
end := imp.ModuleSpecifier.End()
|
|
667
|
+
if start < 0 || start > end || end > len(src) {
|
|
668
|
+
return ""
|
|
669
|
+
}
|
|
670
|
+
return src[start:end]
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// foldCase lowercases `s` unless case-sensitive ordering was requested.
|
|
674
|
+
func foldCase(s string, caseSensitive bool) string {
|
|
675
|
+
if caseSensitive {
|
|
676
|
+
return s
|
|
677
|
+
}
|
|
678
|
+
return strings.ToLower(s)
|
|
679
|
+
}
|
|
680
|
+
|
|
358
681
|
// specifierEntry is the sortable pair captured for each named import
|
|
359
682
|
// specifier: the identifier used as the sort key and the literal source
|
|
360
683
|
// text that gets re-emitted in canonical order.
|
|
@@ -365,7 +688,7 @@ type specifierEntry struct {
|
|
|
365
688
|
|
|
366
689
|
// reportNamedSpecifierSort reports a fix when an import's `{ a, b }` list
|
|
367
690
|
// is out of alphabetical order. Type-only specifiers participate in the
|
|
368
|
-
// same sort key as value specifiers
|
|
691
|
+
// same sort key as value specifiers, prettier's plugin-sort-imports
|
|
369
692
|
// matches this behavior.
|
|
370
693
|
//
|
|
371
694
|
// Safety policy: comment trivia between specifiers anchors the rule
|
|
@@ -373,7 +696,7 @@ type specifierEntry struct {
|
|
|
373
696
|
// would discard any `/* x */` comment carried inside the list. The
|
|
374
697
|
// block-level sort applies the same policy via
|
|
375
698
|
// `leadingTriviaIsAllWhitespace`; this is the per-specifier analog.
|
|
376
|
-
func reportNamedSpecifierSort(ctx *Context, decl *shimast.Node,
|
|
699
|
+
func reportNamedSpecifierSort(ctx *Context, decl *shimast.Node, caseSensitive bool) {
|
|
377
700
|
imp := decl.AsImportDeclaration()
|
|
378
701
|
if imp == nil || imp.ImportClause == nil {
|
|
379
702
|
return
|
|
@@ -410,12 +733,8 @@ func reportNamedSpecifierSort(ctx *Context, decl *shimast.Node, caseInsensitive
|
|
|
410
733
|
}
|
|
411
734
|
start := shimscanner.SkipTrivia(src, spec.Pos())
|
|
412
735
|
end := spec.End()
|
|
413
|
-
key := name
|
|
414
|
-
if caseInsensitive {
|
|
415
|
-
key = strings.ToLower(name)
|
|
416
|
-
}
|
|
417
736
|
entries = append(entries, specifierEntry{
|
|
418
|
-
key:
|
|
737
|
+
key: foldCase(name, caseSensitive),
|
|
419
738
|
text: src[start:end],
|
|
420
739
|
})
|
|
421
740
|
}
|