@ttsc/lint 0.13.0 → 0.14.0-dev.20260528
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 +948 -69
- package/lib/defaultFormat.d.ts +9 -6
- package/lib/defaultFormat.js +9 -6
- 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/{ITtscLintFormatConfig.d.ts → ITtscLintFormat.d.ts} +2 -2
- package/lib/structures/{TtscLintRuleMap.js → ITtscLintFormat.js} +1 -1
- package/lib/structures/ITtscLintFormat.js.map +1 -0
- 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/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 +104 -0
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js +14 -0
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintBoundariesRules.d.ts +79 -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 +17 -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 +1257 -0
- package/lib/structures/{ITtscLintFormatConfig.js → rules/ITtscLintCoreRules.js} +1 -1
- 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 +129 -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 +157 -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 +167 -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 +201 -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 +140 -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 +302 -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 +185 -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 +330 -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 +188 -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 +51 -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 +39 -0
- package/lib/structures/rules/ITtscLintReactRuleOptions.js +12 -0
- package/lib/structures/rules/ITtscLintReactRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintReactRules.d.ts +289 -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 +190 -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 +66 -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 +148 -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 +181 -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 +21 -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 +174 -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 +94 -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 +22 -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 +310 -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 +1132 -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 +141 -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 +48 -17
- package/linthost/config_format.go +9 -9
- package/linthost/directives.go +67 -25
- package/linthost/dispatch.go +14 -3
- package/linthost/engine.go +160 -40
- package/linthost/fix.go +2 -2
- package/linthost/flags_gen.go +17 -15
- package/linthost/host.go +40 -3
- package/linthost/lsp.go +747 -0
- package/linthost/print_dispatch.go +2 -2
- package/linthost/print_nodes_function.go +2 -2
- package/linthost/print_nodes_object.go +1 -1
- 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 +94 -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_jsdoc.go +1 -1
- package/linthost/rules_format_print_width.go +9 -9
- package/linthost/rules_format_quotes.go +1 -1
- package/linthost/rules_format_semi.go +1 -1
- package/linthost/rules_format_sort_imports.go +1 -1
- package/linthost/rules_format_trailing_comma.go +1 -1
- 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 +1128 -73
- 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 +155 -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 +11 -8
- package/src/index.ts +65 -43
- package/src/structures/ITtscLintConfig.ts +12 -6
- package/src/structures/{ITtscLintFormatConfig.ts → ITtscLintFormat.ts} +2 -2
- package/src/structures/TtscLintRuleSetting.ts +55 -0
- package/src/structures/index.ts +3 -4
- package/src/structures/rules/ITtscLintBoundariesRuleOptions.ts +128 -0
- package/src/structures/rules/ITtscLintBoundariesRules.ts +95 -0
- package/src/structures/rules/ITtscLintContributorRules.ts +21 -0
- package/src/structures/rules/ITtscLintCoreRules.ts +1406 -0
- package/src/structures/rules/ITtscLintCypressRuleOptions.ts +18 -0
- package/src/structures/rules/ITtscLintCypressRules.ts +145 -0
- package/src/structures/rules/ITtscLintFunctionalRuleOptions.ts +213 -0
- package/src/structures/rules/ITtscLintFunctionalRules.ts +202 -0
- package/src/structures/rules/ITtscLintJestRules.ts +220 -0
- package/src/structures/rules/ITtscLintJsdocRules.ts +153 -0
- package/src/structures/rules/ITtscLintJsxA11yRules.ts +339 -0
- package/src/structures/rules/ITtscLintNextjsRules.ts +206 -0
- package/src/structures/rules/ITtscLintPlaywrightRules.ts +361 -0
- package/src/structures/rules/ITtscLintPromiseRules.ts +205 -0
- package/src/structures/rules/ITtscLintReactPerfRuleOptions.ts +19 -0
- package/src/structures/rules/ITtscLintReactPerfRules.ts +55 -0
- package/src/structures/rules/ITtscLintReactRuleOptions.ts +43 -0
- package/src/structures/rules/ITtscLintReactRules.ts +321 -0
- package/src/structures/rules/ITtscLintRegexpRules.ts +212 -0
- package/src/structures/rules/ITtscLintRuleOptionsMap.ts +89 -0
- package/src/structures/rules/ITtscLintRules.ts +77 -0
- package/src/structures/rules/ITtscLintSecurityRules.ts +162 -0
- package/src/structures/rules/ITtscLintSolidRules.ts +202 -0
- package/src/structures/rules/ITtscLintStorybookRuleOptions.ts +23 -0
- package/src/structures/rules/ITtscLintStorybookRules.ts +193 -0
- package/src/structures/rules/ITtscLintTanstackQueryRules.ts +102 -0
- package/src/structures/rules/ITtscLintTestingLibraryRuleOptions.ts +24 -0
- package/src/structures/rules/ITtscLintTestingLibraryRules.ts +342 -0
- package/src/structures/rules/ITtscLintTypeScriptRules.ts +1230 -0
- package/src/structures/rules/ITtscLintUnicornRules.ts +1143 -0
- package/src/structures/rules/ITtscLintVitestRules.ts +154 -0
- package/src/structures/rules/index.ts +31 -0
- 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/TtscLintRule.ts +0 -160
- package/src/structures/TtscLintRuleMap.ts +0 -55
- package/src/structures/TtscLintRuleOptions.ts +0 -151
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// noShadow reports a binding declaration whose name matches a binding
|
|
2
|
+
// already in scope at an outer level. The inner declaration silently
|
|
3
|
+
// obscures the outer reference — readers expect `outer` inside the body
|
|
4
|
+
// to mean the outer binding, but it now resolves to the inner one. The
|
|
5
|
+
// pattern is almost always an accidental rebind during refactoring.
|
|
6
|
+
// https://eslint.org/docs/latest/rules/no-shadow
|
|
7
|
+
//
|
|
8
|
+
// Conservative scope tracking: walk the file once with an explicit
|
|
9
|
+
// stack of scope frames. A frame is pushed on every function-like
|
|
10
|
+
// node (which contributes its parameter names) and on every Block /
|
|
11
|
+
// CatchClause (which contributes its block-scoped `let`, `const`,
|
|
12
|
+
// `class`, and `function` declarations). `var` bindings are recorded
|
|
13
|
+
// on the nearest enclosing function frame instead — they hoist past
|
|
14
|
+
// inner block boundaries.
|
|
15
|
+
//
|
|
16
|
+
// Only plain identifier bindings are tracked. Destructuring patterns
|
|
17
|
+
// (`const { a } = …`, `function f({ x }) {}`) are skipped because the
|
|
18
|
+
// rule cannot reason about pattern equality without a real binder, and
|
|
19
|
+
// the AST-only baseline prefers false negatives to false positives.
|
|
20
|
+
package linthost
|
|
21
|
+
|
|
22
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
23
|
+
|
|
24
|
+
type noShadow struct{}
|
|
25
|
+
|
|
26
|
+
func (noShadow) Name() string { return "no-shadow" }
|
|
27
|
+
func (noShadow) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindSourceFile} }
|
|
28
|
+
func (noShadow) Check(ctx *Context, node *shimast.Node) {
|
|
29
|
+
if node == nil {
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
// Each frame records the names declared at that lexical level.
|
|
33
|
+
// `isFunction` marks frames that absorb hoisted `var` bindings.
|
|
34
|
+
type frame struct {
|
|
35
|
+
names map[string]bool
|
|
36
|
+
isFunction bool
|
|
37
|
+
}
|
|
38
|
+
stack := []*frame{{names: map[string]bool{}, isFunction: true}}
|
|
39
|
+
|
|
40
|
+
outerHas := func(name string) bool {
|
|
41
|
+
for i := len(stack) - 2; i >= 0; i-- {
|
|
42
|
+
if stack[i].names[name] {
|
|
43
|
+
return true
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return false
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
declare := func(name string, declNode *shimast.Node, hoist bool) {
|
|
50
|
+
if name == "" {
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
target := stack[len(stack)-1]
|
|
54
|
+
if hoist {
|
|
55
|
+
for i := len(stack) - 1; i >= 0; i-- {
|
|
56
|
+
if stack[i].isFunction {
|
|
57
|
+
target = stack[i]
|
|
58
|
+
break
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if outerHas(name) {
|
|
63
|
+
ctx.Report(declNode, "'"+name+"' is already declared in the upper scope.")
|
|
64
|
+
}
|
|
65
|
+
target.names[name] = true
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
var walk func(n *shimast.Node)
|
|
69
|
+
walk = func(n *shimast.Node) {
|
|
70
|
+
if n == nil {
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
// Bind a function declaration's name in the enclosing scope
|
|
74
|
+
// before descending into its body. `var`-style hoisting takes
|
|
75
|
+
// the name to the nearest function frame.
|
|
76
|
+
if n.Kind == shimast.KindFunctionDeclaration {
|
|
77
|
+
if decl := n.AsFunctionDeclaration(); decl != nil && decl.Body != nil {
|
|
78
|
+
if name := identifierText(decl.Name()); name != "" {
|
|
79
|
+
declare(name, n, true)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Push a frame for every scope-introducing node. Function-like
|
|
84
|
+
// frames also receive their parameter names before descending.
|
|
85
|
+
if isFunctionLikeKind(n) {
|
|
86
|
+
stack = append(stack, &frame{names: map[string]bool{}, isFunction: true})
|
|
87
|
+
for _, name := range parameterBindingNames(n) {
|
|
88
|
+
declare(name, n, false)
|
|
89
|
+
}
|
|
90
|
+
n.ForEachChild(func(child *shimast.Node) bool {
|
|
91
|
+
walk(child)
|
|
92
|
+
return false
|
|
93
|
+
})
|
|
94
|
+
stack = stack[:len(stack)-1]
|
|
95
|
+
return
|
|
96
|
+
}
|
|
97
|
+
switch n.Kind {
|
|
98
|
+
case shimast.KindBlock, shimast.KindCatchClause:
|
|
99
|
+
// Function bodies are blocks too, but the function frame
|
|
100
|
+
// pushed above already represents that scope — skip the
|
|
101
|
+
// extra frame so a parameter and a body-level `let` of the
|
|
102
|
+
// same name still register as a redeclare, not a shadow.
|
|
103
|
+
if n.Kind == shimast.KindBlock && n.Parent != nil && isFunctionLikeKind(n.Parent) {
|
|
104
|
+
n.ForEachChild(func(child *shimast.Node) bool {
|
|
105
|
+
walk(child)
|
|
106
|
+
return false
|
|
107
|
+
})
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
stack = append(stack, &frame{names: map[string]bool{}})
|
|
111
|
+
if catch := n.AsCatchClause(); catch != nil && catch.VariableDeclaration != nil {
|
|
112
|
+
if name := identifierText(catch.VariableDeclaration.Name()); name != "" {
|
|
113
|
+
declare(name, catch.VariableDeclaration, false)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
n.ForEachChild(func(child *shimast.Node) bool {
|
|
117
|
+
walk(child)
|
|
118
|
+
return false
|
|
119
|
+
})
|
|
120
|
+
stack = stack[:len(stack)-1]
|
|
121
|
+
return
|
|
122
|
+
case shimast.KindVariableStatement:
|
|
123
|
+
vs := n.AsVariableStatement()
|
|
124
|
+
if vs != nil && vs.DeclarationList != nil {
|
|
125
|
+
hoist := shimast.IsVar(vs.DeclarationList)
|
|
126
|
+
for _, name := range variableStatementBindingNames(n) {
|
|
127
|
+
declare(name, n, hoist)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
case shimast.KindClassDeclaration:
|
|
131
|
+
if decl := n.AsClassDeclaration(); decl != nil {
|
|
132
|
+
if name := identifierText(decl.Name()); name != "" {
|
|
133
|
+
declare(name, n, false)
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
n.ForEachChild(func(child *shimast.Node) bool {
|
|
138
|
+
walk(child)
|
|
139
|
+
return false
|
|
140
|
+
})
|
|
141
|
+
}
|
|
142
|
+
walk(node)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
func init() {
|
|
146
|
+
Register(noShadow{})
|
|
147
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// noUnreachable reports statements that follow an unconditional control-
|
|
2
|
+
// flow terminator inside the same statement list. After `return`, `throw`,
|
|
3
|
+
// `break`, or `continue` the surrounding block exits, so any later
|
|
4
|
+
// statement in the list is dead code — almost always a leftover from
|
|
5
|
+
// refactoring.
|
|
6
|
+
//
|
|
7
|
+
// Conservative baseline: only the immediate statement list of a Block,
|
|
8
|
+
// SourceFile, or ModuleBlock is inspected; nested conditionals and loops
|
|
9
|
+
// are left to a real control-flow pass. Hoistable function declarations
|
|
10
|
+
// following the terminator are exempt because they are hoisted above the
|
|
11
|
+
// unreachable point and remain callable from earlier statements.
|
|
12
|
+
// https://eslint.org/docs/latest/rules/no-unreachable
|
|
13
|
+
package linthost
|
|
14
|
+
|
|
15
|
+
import (
|
|
16
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
type noUnreachable struct{}
|
|
20
|
+
|
|
21
|
+
func (noUnreachable) Name() string { return "no-unreachable" }
|
|
22
|
+
func (noUnreachable) Visits() []shimast.Kind {
|
|
23
|
+
return []shimast.Kind{
|
|
24
|
+
shimast.KindBlock,
|
|
25
|
+
shimast.KindSourceFile,
|
|
26
|
+
shimast.KindModuleBlock,
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
func (noUnreachable) Check(ctx *Context, node *shimast.Node) {
|
|
30
|
+
stmts := node.Statements()
|
|
31
|
+
if len(stmts) < 2 {
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
terminated := false
|
|
35
|
+
for _, stmt := range stmts {
|
|
36
|
+
if stmt == nil {
|
|
37
|
+
continue
|
|
38
|
+
}
|
|
39
|
+
if terminated && !isHoistableDeclaration(stmt) {
|
|
40
|
+
ctx.Report(stmt, "Unreachable code.")
|
|
41
|
+
continue
|
|
42
|
+
}
|
|
43
|
+
if isControlFlowTerminator(stmt) {
|
|
44
|
+
terminated = true
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// isControlFlowTerminator reports whether `stmt` is one of the four
|
|
50
|
+
// statement kinds that unconditionally leave the surrounding block:
|
|
51
|
+
// `return`, `throw`, `break`, `continue`.
|
|
52
|
+
func isControlFlowTerminator(stmt *shimast.Node) bool {
|
|
53
|
+
if stmt == nil {
|
|
54
|
+
return false
|
|
55
|
+
}
|
|
56
|
+
switch stmt.Kind {
|
|
57
|
+
case shimast.KindReturnStatement,
|
|
58
|
+
shimast.KindThrowStatement,
|
|
59
|
+
shimast.KindBreakStatement,
|
|
60
|
+
shimast.KindContinueStatement:
|
|
61
|
+
return true
|
|
62
|
+
}
|
|
63
|
+
return false
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// isHoistableDeclaration reports whether `stmt` is a declaration whose
|
|
67
|
+
// binding survives even when it textually follows a terminator. Function
|
|
68
|
+
// declarations hoist to the top of their containing scope, so a
|
|
69
|
+
// `function f() {…}` after a `return` is still callable from earlier
|
|
70
|
+
// statements and is not dead code in the ESLint sense.
|
|
71
|
+
func isHoistableDeclaration(stmt *shimast.Node) bool {
|
|
72
|
+
return stmt != nil && stmt.Kind == shimast.KindFunctionDeclaration
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
func init() {
|
|
76
|
+
Register(noUnreachable{})
|
|
77
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// noUselessAssignment reports an assignment whose value is immediately
|
|
2
|
+
// overwritten by the very next statement without an intervening read of
|
|
3
|
+
// the same identifier. `x = 1; x = 2;` writes the first value just to
|
|
4
|
+
// discard it — almost always a leftover from refactoring.
|
|
5
|
+
// https://eslint.org/docs/latest/rules/no-useless-assignment
|
|
6
|
+
//
|
|
7
|
+
// Conservative baseline: only the syntactically adjacent
|
|
8
|
+
// ExpressionStatement / ExpressionStatement pair is inspected, and only
|
|
9
|
+
// when both left-hand sides are bare identifiers with the same name. A
|
|
10
|
+
// real dead-store analysis would track reads across branches and inside
|
|
11
|
+
// the right-hand expression; the simpler textual match catches the
|
|
12
|
+
// common copy-paste case without needing full control-flow.
|
|
13
|
+
package linthost
|
|
14
|
+
|
|
15
|
+
import (
|
|
16
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
type noUselessAssignment struct{}
|
|
20
|
+
|
|
21
|
+
func (noUselessAssignment) Name() string { return "no-useless-assignment" }
|
|
22
|
+
func (noUselessAssignment) Visits() []shimast.Kind {
|
|
23
|
+
return []shimast.Kind{shimast.KindBlock}
|
|
24
|
+
}
|
|
25
|
+
func (noUselessAssignment) Check(ctx *Context, node *shimast.Node) {
|
|
26
|
+
block := node.AsBlock()
|
|
27
|
+
if block == nil || block.Statements == nil {
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
stmts := block.Statements.Nodes
|
|
31
|
+
if len(stmts) < 2 {
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
for i := 0; i+1 < len(stmts); i++ {
|
|
35
|
+
firstName, firstAssign := plainAssignmentTarget(stmts[i])
|
|
36
|
+
if firstName == "" {
|
|
37
|
+
continue
|
|
38
|
+
}
|
|
39
|
+
secondName, _ := plainAssignmentTarget(stmts[i+1])
|
|
40
|
+
if secondName != firstName {
|
|
41
|
+
continue
|
|
42
|
+
}
|
|
43
|
+
// If the second statement's RHS reads the first target, the
|
|
44
|
+
// first write is load-bearing — skip.
|
|
45
|
+
if assignmentRhsReadsIdent(stmts[i+1], firstName) {
|
|
46
|
+
continue
|
|
47
|
+
}
|
|
48
|
+
ctx.Report(firstAssign, "Assignment to `"+firstName+"` is immediately overwritten without being read.")
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// plainAssignmentTarget returns the identifier name on the left-hand
|
|
53
|
+
// side of `stmt` when it is an `ExpressionStatement` wrapping a plain
|
|
54
|
+
// `<ident> = <expr>` assignment. Anything else (compound assignment,
|
|
55
|
+
// destructuring target, property access, non-statement) returns "".
|
|
56
|
+
func plainAssignmentTarget(stmt *shimast.Node) (string, *shimast.Node) {
|
|
57
|
+
if stmt == nil || stmt.Kind != shimast.KindExpressionStatement {
|
|
58
|
+
return "", nil
|
|
59
|
+
}
|
|
60
|
+
expr := stmt.AsExpressionStatement()
|
|
61
|
+
if expr == nil || expr.Expression == nil {
|
|
62
|
+
return "", nil
|
|
63
|
+
}
|
|
64
|
+
inner := stripParens(expr.Expression)
|
|
65
|
+
if inner == nil || inner.Kind != shimast.KindBinaryExpression {
|
|
66
|
+
return "", nil
|
|
67
|
+
}
|
|
68
|
+
bin := inner.AsBinaryExpression()
|
|
69
|
+
if bin == nil || bin.OperatorToken == nil || bin.OperatorToken.Kind != shimast.KindEqualsToken {
|
|
70
|
+
return "", nil
|
|
71
|
+
}
|
|
72
|
+
name := identifierText(stripParens(bin.Left))
|
|
73
|
+
if name == "" {
|
|
74
|
+
return "", nil
|
|
75
|
+
}
|
|
76
|
+
return name, stmt
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// assignmentRhsReadsIdent reports whether the second statement's
|
|
80
|
+
// assignment right-hand side references the same identifier name. A
|
|
81
|
+
// `x = x + 1` style update reads the previous value, so the prior
|
|
82
|
+
// assignment is not actually dead.
|
|
83
|
+
func assignmentRhsReadsIdent(stmt *shimast.Node, name string) bool {
|
|
84
|
+
if stmt == nil || stmt.Kind != shimast.KindExpressionStatement {
|
|
85
|
+
return false
|
|
86
|
+
}
|
|
87
|
+
expr := stmt.AsExpressionStatement()
|
|
88
|
+
if expr == nil || expr.Expression == nil {
|
|
89
|
+
return false
|
|
90
|
+
}
|
|
91
|
+
inner := stripParens(expr.Expression)
|
|
92
|
+
if inner == nil || inner.Kind != shimast.KindBinaryExpression {
|
|
93
|
+
return false
|
|
94
|
+
}
|
|
95
|
+
bin := inner.AsBinaryExpression()
|
|
96
|
+
if bin == nil || bin.Right == nil {
|
|
97
|
+
return false
|
|
98
|
+
}
|
|
99
|
+
found := false
|
|
100
|
+
var walk func(n *shimast.Node)
|
|
101
|
+
walk = func(n *shimast.Node) {
|
|
102
|
+
if found || n == nil {
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
if n.Kind == shimast.KindIdentifier && identifierText(n) == name {
|
|
106
|
+
found = true
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
n.ForEachChild(func(child *shimast.Node) bool {
|
|
110
|
+
walk(child)
|
|
111
|
+
return false
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
walk(bin.Right)
|
|
115
|
+
return found
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
func init() {
|
|
119
|
+
Register(noUselessAssignment{})
|
|
120
|
+
}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
// noUselessConstructor: report class constructors that contribute
|
|
2
|
+
// nothing beyond what the engine would synthesize on its own. Two
|
|
3
|
+
// shapes fire:
|
|
4
|
+
//
|
|
5
|
+
// - Empty body, no parameters, no accessibility/decorator modifiers.
|
|
6
|
+
// The engine generates an identical implicit constructor when the
|
|
7
|
+
// class declares none, so the explicit declaration is pure noise.
|
|
8
|
+
//
|
|
9
|
+
// - Derived constructor that does nothing but forward to `super(...args)`
|
|
10
|
+
// unchanged. The default constructor of a subclass already forwards
|
|
11
|
+
// every argument to `super`, so an explicit `constructor(...args) {
|
|
12
|
+
// super(...args); }` is redundant. The forwarded parameter list and
|
|
13
|
+
// the `super` call's argument list must be identical rest-spreads of
|
|
14
|
+
// the same name — modifying, reordering, or filtering the arguments
|
|
15
|
+
// means the constructor still has a purpose and is left alone.
|
|
16
|
+
//
|
|
17
|
+
// Constructors that carry parameter properties (`constructor(private x:
|
|
18
|
+
// number)`) or accessibility / decorator modifiers are skipped: removing
|
|
19
|
+
// them would change the class shape or its observable metadata, so they
|
|
20
|
+
// are never "useless" by this rule's standard.
|
|
21
|
+
// https://typescript-eslint.io/rules/no-useless-constructor/
|
|
22
|
+
package linthost
|
|
23
|
+
|
|
24
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
25
|
+
|
|
26
|
+
type noUselessConstructor struct{}
|
|
27
|
+
|
|
28
|
+
func (noUselessConstructor) Name() string { return "no-useless-constructor" }
|
|
29
|
+
func (noUselessConstructor) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindConstructor} }
|
|
30
|
+
func (noUselessConstructor) Check(ctx *Context, node *shimast.Node) {
|
|
31
|
+
ctor := node.AsConstructorDeclaration()
|
|
32
|
+
if ctor == nil || ctor.Body == nil {
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
// Accessibility modifiers (`private`/`protected`) on the constructor
|
|
36
|
+
// itself are load-bearing: they restrict who can `new` the class.
|
|
37
|
+
// Removing the constructor would silently widen visibility.
|
|
38
|
+
if node.ModifierFlags()&(shimast.ModifierFlagsPrivate|shimast.ModifierFlagsProtected) != 0 {
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
if hasParameterProperty(node) {
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
body := ctor.Body.AsBlock()
|
|
45
|
+
if body == nil || body.Statements == nil {
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
params := node.Parameters()
|
|
49
|
+
|
|
50
|
+
// Shape 1: empty body, no parameters. The implicit constructor that
|
|
51
|
+
// the engine generates when no constructor is written is identical,
|
|
52
|
+
// so the explicit declaration is noise.
|
|
53
|
+
if len(params) == 0 && len(body.Statements.Nodes) == 0 {
|
|
54
|
+
ctx.Report(node, "Useless empty constructor.")
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Shape 2: derived class constructor that only forwards arguments to
|
|
59
|
+
// `super(...args)` without modification. The synthetic default
|
|
60
|
+
// constructor of a subclass behaves identically, so the explicit
|
|
61
|
+
// declaration is noise. Only fires when the class extends another.
|
|
62
|
+
parent := node.Parent
|
|
63
|
+
if parent == nil || !classExtendsAnother(parent) {
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
if len(body.Statements.Nodes) != 1 {
|
|
67
|
+
return
|
|
68
|
+
}
|
|
69
|
+
if !isPlainSuperForwarder(params, body.Statements.Nodes[0]) {
|
|
70
|
+
return
|
|
71
|
+
}
|
|
72
|
+
ctx.Report(node, "Useless constructor: forwards arguments to `super` unchanged.")
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// hasParameterProperty reports whether any constructor parameter carries
|
|
76
|
+
// a TypeScript parameter-property modifier (`public`, `private`,
|
|
77
|
+
// `protected`, or `readonly`). Such a parameter declares an instance
|
|
78
|
+
// field, so the constructor is doing real work even if its body is
|
|
79
|
+
// empty — removing it would drop the field.
|
|
80
|
+
func hasParameterProperty(node *shimast.Node) bool {
|
|
81
|
+
for _, p := range node.Parameters() {
|
|
82
|
+
if p == nil {
|
|
83
|
+
continue
|
|
84
|
+
}
|
|
85
|
+
if p.ModifierFlags()&(shimast.ModifierFlagsPrivate|shimast.ModifierFlagsProtected|shimast.ModifierFlagsReadonly) != 0 {
|
|
86
|
+
return true
|
|
87
|
+
}
|
|
88
|
+
// `public` is not represented by any of the above flags but does
|
|
89
|
+
// still create a parameter property. Inspect the raw modifier
|
|
90
|
+
// list for a PublicKeyword.
|
|
91
|
+
decl := p.AsParameterDeclaration()
|
|
92
|
+
if decl == nil {
|
|
93
|
+
continue
|
|
94
|
+
}
|
|
95
|
+
if hasPublicModifier(decl.Modifiers()) {
|
|
96
|
+
return true
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return false
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// hasPublicModifier reports whether `mods` includes a `public` keyword.
|
|
103
|
+
// `public` is a parameter-property qualifier that does not set any of
|
|
104
|
+
// the Private/Protected/Readonly modifier flags, so we walk the raw
|
|
105
|
+
// modifier list to detect it.
|
|
106
|
+
func hasPublicModifier(mods *shimast.ModifierList) bool {
|
|
107
|
+
if mods == nil {
|
|
108
|
+
return false
|
|
109
|
+
}
|
|
110
|
+
for _, m := range mods.Nodes {
|
|
111
|
+
if m != nil && m.Kind == shimast.KindPublicKeyword {
|
|
112
|
+
return true
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return false
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// isPlainSuperForwarder reports whether `stmt` is exactly
|
|
119
|
+
// `super(...name);` (an expression statement wrapping a CallExpression
|
|
120
|
+
// whose callee is the `super` keyword and whose only argument is a
|
|
121
|
+
// SpreadElement over an identifier) AND the constructor parameter list
|
|
122
|
+
// is exactly `(...name)` over the same identifier. Type annotations on
|
|
123
|
+
// the rest parameter are allowed — `(...args: unknown[])` still
|
|
124
|
+
// forwards unchanged.
|
|
125
|
+
func isPlainSuperForwarder(params []*shimast.Node, stmt *shimast.Node) bool {
|
|
126
|
+
if stmt == nil || stmt.Kind != shimast.KindExpressionStatement {
|
|
127
|
+
return false
|
|
128
|
+
}
|
|
129
|
+
exprStmt := stmt.AsExpressionStatement()
|
|
130
|
+
if exprStmt == nil || exprStmt.Expression == nil {
|
|
131
|
+
return false
|
|
132
|
+
}
|
|
133
|
+
expr := stripParens(exprStmt.Expression)
|
|
134
|
+
if expr == nil || expr.Kind != shimast.KindCallExpression {
|
|
135
|
+
return false
|
|
136
|
+
}
|
|
137
|
+
call := expr.AsCallExpression()
|
|
138
|
+
if call == nil || call.Expression == nil || call.Expression.Kind != shimast.KindSuperKeyword {
|
|
139
|
+
return false
|
|
140
|
+
}
|
|
141
|
+
if call.Arguments == nil {
|
|
142
|
+
return false
|
|
143
|
+
}
|
|
144
|
+
args := call.Arguments.Nodes
|
|
145
|
+
// `super()` — zero arguments — only matches when the constructor
|
|
146
|
+
// also declares zero parameters. ESLint flags this shape too: the
|
|
147
|
+
// synthetic default constructor of a derived class would call
|
|
148
|
+
// `super(...args)`, which for a zero-arg case is the same thing.
|
|
149
|
+
if len(args) == 0 {
|
|
150
|
+
return len(params) == 0
|
|
151
|
+
}
|
|
152
|
+
if len(args) != len(params) {
|
|
153
|
+
return false
|
|
154
|
+
}
|
|
155
|
+
// All arguments must be `...name` spreading the identically named
|
|
156
|
+
// rest parameter. ESLint also accepts the positional `super(a, b)`
|
|
157
|
+
// over `(a, b)` shape — match that too: every parameter must be a
|
|
158
|
+
// plain identifier (or rest), and the argument must spread/use the
|
|
159
|
+
// same identifier in the same position.
|
|
160
|
+
for i, arg := range args {
|
|
161
|
+
paramName, paramRest, ok := plainParamIdentifier(params[i])
|
|
162
|
+
if !ok {
|
|
163
|
+
return false
|
|
164
|
+
}
|
|
165
|
+
argName, argSpread, ok := plainArgIdentifier(arg)
|
|
166
|
+
if !ok {
|
|
167
|
+
return false
|
|
168
|
+
}
|
|
169
|
+
if paramName != argName {
|
|
170
|
+
return false
|
|
171
|
+
}
|
|
172
|
+
if paramRest != argSpread {
|
|
173
|
+
return false
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return true
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// plainParamIdentifier extracts the identifier name of a parameter that
|
|
180
|
+
// is a plain `name` or `...name`. Returns `(name, isRest, true)` on
|
|
181
|
+
// match, or zero values + false when the parameter is a destructuring
|
|
182
|
+
// pattern, has a default value, has an accessibility modifier, has a
|
|
183
|
+
// `?` token (optional), or otherwise carries observable behavior.
|
|
184
|
+
// Type annotations are intentionally ignored — they do not change the
|
|
185
|
+
// runtime forwarding behavior.
|
|
186
|
+
func plainParamIdentifier(param *shimast.Node) (string, bool, bool) {
|
|
187
|
+
if param == nil {
|
|
188
|
+
return "", false, false
|
|
189
|
+
}
|
|
190
|
+
decl := param.AsParameterDeclaration()
|
|
191
|
+
if decl == nil {
|
|
192
|
+
return "", false, false
|
|
193
|
+
}
|
|
194
|
+
if decl.Initializer != nil || decl.QuestionToken != nil {
|
|
195
|
+
return "", false, false
|
|
196
|
+
}
|
|
197
|
+
// Accessibility modifier on the parameter would already have been
|
|
198
|
+
// caught by hasParameterProperty above, but guard locally too.
|
|
199
|
+
if param.ModifierFlags()&(shimast.ModifierFlagsPrivate|shimast.ModifierFlagsProtected|shimast.ModifierFlagsReadonly) != 0 {
|
|
200
|
+
return "", false, false
|
|
201
|
+
}
|
|
202
|
+
if hasPublicModifier(decl.Modifiers()) {
|
|
203
|
+
return "", false, false
|
|
204
|
+
}
|
|
205
|
+
name := identifierText(decl.Name())
|
|
206
|
+
if name == "" {
|
|
207
|
+
return "", false, false
|
|
208
|
+
}
|
|
209
|
+
return name, decl.DotDotDotToken != nil, true
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// plainArgIdentifier extracts the identifier name of a call argument
|
|
213
|
+
// that is a plain `name` or `...name`. Returns `(name, isSpread, true)`
|
|
214
|
+
// on match. Anything else — a literal, property access, expression —
|
|
215
|
+
// is treated as observable work and disqualifies the forwarder.
|
|
216
|
+
func plainArgIdentifier(arg *shimast.Node) (string, bool, bool) {
|
|
217
|
+
if arg == nil {
|
|
218
|
+
return "", false, false
|
|
219
|
+
}
|
|
220
|
+
stripped := stripParens(arg)
|
|
221
|
+
if stripped == nil {
|
|
222
|
+
return "", false, false
|
|
223
|
+
}
|
|
224
|
+
if stripped.Kind == shimast.KindSpreadElement {
|
|
225
|
+
spread := stripped.AsSpreadElement()
|
|
226
|
+
if spread == nil {
|
|
227
|
+
return "", false, false
|
|
228
|
+
}
|
|
229
|
+
inner := stripParens(spread.Expression)
|
|
230
|
+
name := identifierText(inner)
|
|
231
|
+
if name == "" {
|
|
232
|
+
return "", false, false
|
|
233
|
+
}
|
|
234
|
+
return name, true, true
|
|
235
|
+
}
|
|
236
|
+
name := identifierText(stripped)
|
|
237
|
+
if name == "" {
|
|
238
|
+
return "", false, false
|
|
239
|
+
}
|
|
240
|
+
return name, false, true
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
func init() {
|
|
244
|
+
Register(noUselessConstructor{})
|
|
245
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// noUselessReturn reports a bare `return;` whose only effect is to end a
|
|
2
|
+
// function body that would have returned anyway. `function f() { … ;
|
|
3
|
+
// return; }` is identical to `function f() { … ; }`: the trailing
|
|
4
|
+
// statement adds no behavior, only noise. The conservative baseline only
|
|
5
|
+
// fires at the very last statement of a block that is itself the
|
|
6
|
+
// immediate body of a function-like — any earlier `return;` inside a
|
|
7
|
+
// loop, branch, or inner block may still be load-bearing.
|
|
8
|
+
// https://eslint.org/docs/latest/rules/no-useless-return
|
|
9
|
+
package linthost
|
|
10
|
+
|
|
11
|
+
import (
|
|
12
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
type noUselessReturn struct{}
|
|
16
|
+
|
|
17
|
+
func (noUselessReturn) Name() string { return "no-useless-return" }
|
|
18
|
+
func (noUselessReturn) Visits() []shimast.Kind {
|
|
19
|
+
return []shimast.Kind{shimast.KindReturnStatement}
|
|
20
|
+
}
|
|
21
|
+
func (noUselessReturn) Check(ctx *Context, node *shimast.Node) {
|
|
22
|
+
ret := node.AsReturnStatement()
|
|
23
|
+
if ret == nil || ret.Expression != nil {
|
|
24
|
+
// `return X;` is never useless: it carries a value.
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
parent := node.Parent
|
|
28
|
+
if parent == nil || parent.Kind != shimast.KindBlock {
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
block := parent.AsBlock()
|
|
32
|
+
if block == nil || block.Statements == nil {
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
stmts := block.Statements.Nodes
|
|
36
|
+
if len(stmts) == 0 || stmts[len(stmts)-1] != node {
|
|
37
|
+
// Only the last statement of the block is provably useless;
|
|
38
|
+
// any earlier `return;` may guard the statements that follow.
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
if !isFunctionLikeKind(parent.Parent) {
|
|
42
|
+
// The block must be the immediate body of a function-like so
|
|
43
|
+
// the function's natural completion is what would run next.
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
ctx.Report(node, "Unnecessary return statement.")
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
func init() {
|
|
50
|
+
Register(noUselessReturn{})
|
|
51
|
+
}
|
package/linthost/rules_params.go
CHANGED
|
@@ -2,7 +2,7 @@ package linthost
|
|
|
2
2
|
|
|
3
3
|
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
4
4
|
|
|
5
|
-
//
|
|
5
|
+
// defaultParamLast: forbid parameters with default initializers that
|
|
6
6
|
// precede non-default parameters. The combination forces every caller
|
|
7
7
|
// to spell out `undefined` for the defaulted parameter — which defeats
|
|
8
8
|
// the purpose of the default. ESLint canonical:
|