@ttsc/lint 0.13.1 → 0.14.0-dev.20260528.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 +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 +35 -10
- 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/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 +152 -31
- package/linthost/fix.go +2 -2
- 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 +4 -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 +40 -16
- 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,113 @@
|
|
|
1
|
+
// AST-only baseline of typescript-eslint's `no-redundant-type-constituents`.
|
|
2
|
+
//
|
|
3
|
+
// The rule reports type union/intersection constituents that the type
|
|
4
|
+
// system would absorb — `string | any` collapses to `any`, `T & never`
|
|
5
|
+
// collapses to `never`, `T & unknown` collapses to `T`, and repeated
|
|
6
|
+
// constituents add nothing.
|
|
7
|
+
//
|
|
8
|
+
// Without the Checker the rule can only see what the type node declares,
|
|
9
|
+
// so the baseline covers the cases where one operand is the literal
|
|
10
|
+
// `any` / `unknown` / `never` keyword, plus duplicate operands matched
|
|
11
|
+
// by textual identity. Subset relations such as `string | "foo"` and
|
|
12
|
+
// generic alias resolution still need the type-aware path.
|
|
13
|
+
// https://typescript-eslint.io/rules/no-redundant-type-constituents/
|
|
14
|
+
package linthost
|
|
15
|
+
|
|
16
|
+
import (
|
|
17
|
+
"strings"
|
|
18
|
+
|
|
19
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
type noRedundantTypeConstituents struct{}
|
|
23
|
+
|
|
24
|
+
func (noRedundantTypeConstituents) Name() string {
|
|
25
|
+
return "typescript/no-redundant-type-constituents"
|
|
26
|
+
}
|
|
27
|
+
func (noRedundantTypeConstituents) Visits() []shimast.Kind {
|
|
28
|
+
return []shimast.Kind{shimast.KindUnionType, shimast.KindIntersectionType}
|
|
29
|
+
}
|
|
30
|
+
func (noRedundantTypeConstituents) Check(ctx *Context, node *shimast.Node) {
|
|
31
|
+
types := unionOrIntersectionTypes(node)
|
|
32
|
+
if len(types) < 2 {
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
isUnion := node.Kind == shimast.KindUnionType
|
|
36
|
+
hasAny := containsKeywordType(types, shimast.KindAnyKeyword)
|
|
37
|
+
hasUnknown := containsKeywordType(types, shimast.KindUnknownKeyword)
|
|
38
|
+
hasNever := containsKeywordType(types, shimast.KindNeverKeyword)
|
|
39
|
+
label := "intersection"
|
|
40
|
+
if isUnion {
|
|
41
|
+
label = "union"
|
|
42
|
+
}
|
|
43
|
+
seen := map[string]bool{}
|
|
44
|
+
for _, t := range types {
|
|
45
|
+
if t == nil {
|
|
46
|
+
continue
|
|
47
|
+
}
|
|
48
|
+
switch {
|
|
49
|
+
case isUnion && (hasAny || hasUnknown) && t.Kind != shimast.KindAnyKeyword && t.Kind != shimast.KindUnknownKeyword:
|
|
50
|
+
// `T | any` / `T | unknown` — every non-top constituent is
|
|
51
|
+
// absorbed. `any` takes precedence in the message because
|
|
52
|
+
// `any` also subsumes `unknown`.
|
|
53
|
+
absorbing := "unknown"
|
|
54
|
+
if hasAny {
|
|
55
|
+
absorbing = "any"
|
|
56
|
+
}
|
|
57
|
+
ctx.Report(t, "Constituent is overridden by `"+absorbing+"` in the surrounding union.")
|
|
58
|
+
case isUnion && hasNever && t.Kind == shimast.KindNeverKeyword:
|
|
59
|
+
ctx.Report(t, "`never` is absorbed by the surrounding union.")
|
|
60
|
+
case !isUnion && hasNever:
|
|
61
|
+
// `T & never` collapses to `never` for every constituent.
|
|
62
|
+
ctx.Report(t, "Intersection with `never` collapses to `never`.")
|
|
63
|
+
case !isUnion && hasUnknown && t.Kind == shimast.KindUnknownKeyword:
|
|
64
|
+
ctx.Report(t, "`unknown` is absorbed by the surrounding intersection.")
|
|
65
|
+
}
|
|
66
|
+
// Duplicate by textual identity — fire on the second occurrence
|
|
67
|
+
// so the first declaration stays unblamed.
|
|
68
|
+
key := strings.TrimSpace(nodeText(ctx.File, t))
|
|
69
|
+
if key == "" {
|
|
70
|
+
continue
|
|
71
|
+
}
|
|
72
|
+
if seen[key] {
|
|
73
|
+
ctx.Report(t, "Duplicate constituent in "+label+".")
|
|
74
|
+
continue
|
|
75
|
+
}
|
|
76
|
+
seen[key] = true
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// unionOrIntersectionTypes returns the constituent type nodes of a union
|
|
81
|
+
// or intersection type node, or nil for other shapes.
|
|
82
|
+
func unionOrIntersectionTypes(node *shimast.Node) []*shimast.Node {
|
|
83
|
+
if node == nil {
|
|
84
|
+
return nil
|
|
85
|
+
}
|
|
86
|
+
switch node.Kind {
|
|
87
|
+
case shimast.KindUnionType:
|
|
88
|
+
if u := node.AsUnionTypeNode(); u != nil && u.Types != nil {
|
|
89
|
+
return u.Types.Nodes
|
|
90
|
+
}
|
|
91
|
+
case shimast.KindIntersectionType:
|
|
92
|
+
if i := node.AsIntersectionTypeNode(); i != nil && i.Types != nil {
|
|
93
|
+
return i.Types.Nodes
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return nil
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// containsKeywordType reports whether `types` contains a direct keyword
|
|
100
|
+
// type node of `kind` — `any`, `unknown`, or `never` in type position
|
|
101
|
+
// parse as bare keyword nodes rather than identifiers.
|
|
102
|
+
func containsKeywordType(types []*shimast.Node, kind shimast.Kind) bool {
|
|
103
|
+
for _, t := range types {
|
|
104
|
+
if t != nil && t.Kind == kind {
|
|
105
|
+
return true
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return false
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
func init() {
|
|
112
|
+
Register(noRedundantTypeConstituents{})
|
|
113
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// AST-only baseline of typescript-eslint's `no-restricted-types`.
|
|
2
|
+
//
|
|
3
|
+
// The upstream rule is fully configurable — users supply a map from
|
|
4
|
+
// banned type name to a custom message and (optionally) a rewrite hint.
|
|
5
|
+
// Without the rule-options plumbing, this baseline ships a fixed
|
|
6
|
+
// default set that covers the five built-in wrapper / global types
|
|
7
|
+
// that almost every team forbids: `Object`, `Function`, `Number`,
|
|
8
|
+
// `String`, and `Boolean`. The dedicated `typescript/no-unsafe-function-type`
|
|
9
|
+
// and `typescript/no-wrapper-object-types` rules also cover some of
|
|
10
|
+
// these, but `no-restricted-types` is the documented umbrella users
|
|
11
|
+
// reach for when they want a single "ban these names" knob.
|
|
12
|
+
//
|
|
13
|
+
// https://typescript-eslint.io/rules/no-restricted-types/
|
|
14
|
+
package linthost
|
|
15
|
+
|
|
16
|
+
import (
|
|
17
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
type noRestrictedTypes struct{}
|
|
21
|
+
|
|
22
|
+
// noRestrictedTypesDefault is the default set surfaced by the rule
|
|
23
|
+
// when no config is supplied. Each entry pairs the banned identifier
|
|
24
|
+
// with a short, actionable replacement hint.
|
|
25
|
+
var noRestrictedTypesDefault = map[string]string{
|
|
26
|
+
"Object": "Use `object` (any non-primitive) or a specific shape like `Record<string, unknown>` instead of `Object`.",
|
|
27
|
+
"Function": "Declare the specific call signature instead of the unsafe `Function` type.",
|
|
28
|
+
"Number": "Use the lowercase primitive `number` instead of the wrapper type `Number`.",
|
|
29
|
+
"String": "Use the lowercase primitive `string` instead of the wrapper type `String`.",
|
|
30
|
+
"Boolean": "Use the lowercase primitive `boolean` instead of the wrapper type `Boolean`.",
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
func (noRestrictedTypes) Name() string { return "typescript/no-restricted-types" }
|
|
34
|
+
func (noRestrictedTypes) Visits() []shimast.Kind {
|
|
35
|
+
return []shimast.Kind{shimast.KindTypeReference}
|
|
36
|
+
}
|
|
37
|
+
func (noRestrictedTypes) Check(ctx *Context, node *shimast.Node) {
|
|
38
|
+
ref := node.AsTypeReferenceNode()
|
|
39
|
+
if ref == nil || ref.TypeName == nil {
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
name := identifierText(ref.TypeName)
|
|
43
|
+
if name == "" {
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
message, banned := noRestrictedTypesDefault[name]
|
|
47
|
+
if !banned {
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
// Shadow guard: if the user has declared a same-named `type` /
|
|
51
|
+
// `interface` / `class` at file scope, their identifier is NOT the
|
|
52
|
+
// global wrapper. Re-use the wrapper-types helper so the two rules
|
|
53
|
+
// stay consistent about what counts as a shadow.
|
|
54
|
+
if fileShadowsWrapperName(ctx.File, name) {
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
ctx.Report(node, message)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
func init() {
|
|
61
|
+
Register(noRestrictedTypes{})
|
|
62
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// typescript/no-unnecessary-boolean-literal-compare: comparing a value
|
|
2
|
+
// already typed as `boolean` against `true` / `false` adds noise without
|
|
3
|
+
// changing the result — `x === true` evaluates to `x`, `x === false`
|
|
4
|
+
// evaluates to `!x`. The rule narrows to direct comparisons because once
|
|
5
|
+
// the operand carries `null` / `undefined` the literal compare actually
|
|
6
|
+
// strips nullability and is no longer redundant. typescript-eslint:
|
|
7
|
+
// https://typescript-eslint.io/rules/no-unnecessary-boolean-literal-compare/
|
|
8
|
+
//
|
|
9
|
+
// Type-aware. Without a Checker we cannot prove the non-literal side is
|
|
10
|
+
// pure boolean, so Context.Checker == nil short-circuits the rule the
|
|
11
|
+
// same way `no-misused-promises` and `strict-boolean-expressions` do.
|
|
12
|
+
package linthost
|
|
13
|
+
|
|
14
|
+
import (
|
|
15
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
16
|
+
shimchecker "github.com/microsoft/typescript-go/shim/checker"
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
type noUnnecessaryBooleanLiteralCompare struct{}
|
|
20
|
+
|
|
21
|
+
func (noUnnecessaryBooleanLiteralCompare) Name() string {
|
|
22
|
+
return "typescript/no-unnecessary-boolean-literal-compare"
|
|
23
|
+
}
|
|
24
|
+
func (noUnnecessaryBooleanLiteralCompare) NeedsTypeChecker() bool {
|
|
25
|
+
return true
|
|
26
|
+
}
|
|
27
|
+
func (noUnnecessaryBooleanLiteralCompare) Visits() []shimast.Kind {
|
|
28
|
+
return []shimast.Kind{shimast.KindBinaryExpression}
|
|
29
|
+
}
|
|
30
|
+
func (noUnnecessaryBooleanLiteralCompare) Check(ctx *Context, node *shimast.Node) {
|
|
31
|
+
if ctx.Checker == nil {
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
bin := node.AsBinaryExpression()
|
|
35
|
+
if bin == nil || bin.OperatorToken == nil || bin.Left == nil || bin.Right == nil {
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
// Only equality / inequality operators are subject to the rewrite —
|
|
39
|
+
// `<`, `>`, `&&`, etc. against `true` / `false` are not the same shape.
|
|
40
|
+
switch bin.OperatorToken.Kind {
|
|
41
|
+
case shimast.KindEqualsEqualsToken,
|
|
42
|
+
shimast.KindEqualsEqualsEqualsToken,
|
|
43
|
+
shimast.KindExclamationEqualsToken,
|
|
44
|
+
shimast.KindExclamationEqualsEqualsToken:
|
|
45
|
+
default:
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
left := stripParens(bin.Left)
|
|
49
|
+
right := stripParens(bin.Right)
|
|
50
|
+
if left == nil || right == nil {
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
// Identify which side is the literal and which side is the value.
|
|
54
|
+
// `true === x` and `x === true` are both reported.
|
|
55
|
+
var value *shimast.Node
|
|
56
|
+
switch {
|
|
57
|
+
case noUnnecessaryBooleanLiteralCompareIsBoolLiteral(left):
|
|
58
|
+
value = right
|
|
59
|
+
case noUnnecessaryBooleanLiteralCompareIsBoolLiteral(right):
|
|
60
|
+
value = left
|
|
61
|
+
default:
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
// Skip when both sides are literals — that's a different code smell
|
|
65
|
+
// (e.g. `true === false`) that other rules cover.
|
|
66
|
+
if noUnnecessaryBooleanLiteralCompareIsBoolLiteral(value) {
|
|
67
|
+
return
|
|
68
|
+
}
|
|
69
|
+
t := ctx.Checker.GetTypeAtLocation(value)
|
|
70
|
+
if t == nil {
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
// Only fire when the value side is pure boolean. A `boolean | null`
|
|
74
|
+
// operand uses the literal compare to strip nullability — leaving
|
|
75
|
+
// that intact is the explicit carve-out the rule documentation calls
|
|
76
|
+
// out, so we refuse to flag it.
|
|
77
|
+
if !noUnnecessaryBooleanLiteralCompareIsPureBoolean(t) {
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
ctx.Report(node, "This comparison against a boolean literal is unnecessary; use the value (or its negation) directly.")
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// noUnnecessaryBooleanLiteralCompareIsBoolLiteral reports whether node is
|
|
84
|
+
// the literal `true` or `false` keyword.
|
|
85
|
+
func noUnnecessaryBooleanLiteralCompareIsBoolLiteral(node *shimast.Node) bool {
|
|
86
|
+
if node == nil {
|
|
87
|
+
return false
|
|
88
|
+
}
|
|
89
|
+
return node.Kind == shimast.KindTrueKeyword || node.Kind == shimast.KindFalseKeyword
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// noUnnecessaryBooleanLiteralCompareIsPureBoolean reports whether t is a
|
|
93
|
+
// pure boolean type — `boolean`, `true`, `false`, or a union strictly of
|
|
94
|
+
// these. `boolean | null`, `boolean | undefined`, and `any` / `unknown`
|
|
95
|
+
// are explicitly excluded so the literal compare stays in place when it
|
|
96
|
+
// is also stripping nullability or escaping an opaque value.
|
|
97
|
+
func noUnnecessaryBooleanLiteralCompareIsPureBoolean(t *shimchecker.Type) bool {
|
|
98
|
+
if t == nil {
|
|
99
|
+
return false
|
|
100
|
+
}
|
|
101
|
+
flags := t.Flags()
|
|
102
|
+
if flags&(shimchecker.TypeFlagsAny|shimchecker.TypeFlagsUnknown|shimchecker.TypeFlagsNever) != 0 {
|
|
103
|
+
return false
|
|
104
|
+
}
|
|
105
|
+
if flags&shimchecker.TypeFlagsUnion != 0 {
|
|
106
|
+
parts := t.Types()
|
|
107
|
+
if len(parts) == 0 {
|
|
108
|
+
return false
|
|
109
|
+
}
|
|
110
|
+
for _, part := range parts {
|
|
111
|
+
if part == nil {
|
|
112
|
+
return false
|
|
113
|
+
}
|
|
114
|
+
pf := part.Flags()
|
|
115
|
+
if pf&(shimchecker.TypeFlagsNull|shimchecker.TypeFlagsUndefined) != 0 {
|
|
116
|
+
return false
|
|
117
|
+
}
|
|
118
|
+
if pf&shimchecker.TypeFlagsBooleanLike == 0 {
|
|
119
|
+
return false
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return true
|
|
123
|
+
}
|
|
124
|
+
return flags&shimchecker.TypeFlagsBooleanLike != 0
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
func init() {
|
|
128
|
+
Register(noUnnecessaryBooleanLiteralCompare{})
|
|
129
|
+
}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
// typescript/no-unnecessary-condition: a conditional whose test expression
|
|
2
|
+
// has a type that can only ever evaluate to one truthiness — `if ({})`,
|
|
3
|
+
// `if (null)`, `while ("")` — branches that never run (or always run) and
|
|
4
|
+
// almost always reflect a logic error. The runtime takes the static
|
|
5
|
+
// answer that the type system already had, so naming the constant intent
|
|
6
|
+
// explicitly (`if (true)`, deleting the dead arm, or widening the type)
|
|
7
|
+
// is the fix. typescript-eslint:
|
|
8
|
+
// https://typescript-eslint.io/rules/no-unnecessary-condition/
|
|
9
|
+
//
|
|
10
|
+
// Type-aware. Without a Checker the rule cannot tell `null` apart from
|
|
11
|
+
// `string | null`, so Context.Checker == nil short-circuits each Check to
|
|
12
|
+
// a no-op the way `strict-boolean-expressions` and `no-misused-promises`
|
|
13
|
+
// do.
|
|
14
|
+
package linthost
|
|
15
|
+
|
|
16
|
+
import (
|
|
17
|
+
"strings"
|
|
18
|
+
|
|
19
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
20
|
+
shimchecker "github.com/microsoft/typescript-go/shim/checker"
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
// truthState is the lattice value the rule tracks for each constituent of
|
|
24
|
+
// the test expression's static type.
|
|
25
|
+
//
|
|
26
|
+
// - truthStateUnknowable — `any` / `unknown` / `never`, or any other
|
|
27
|
+
// constituent we cannot prove either truthy or falsy. Treated as
|
|
28
|
+
// "abandon the analysis" — if any constituent is unknowable the
|
|
29
|
+
// overall result is unknowable and the rule does not fire.
|
|
30
|
+
// - truthStateAlwaysTruthy / truthStateAlwaysFalsy — a constituent
|
|
31
|
+
// whose runtime truthiness is fixed.
|
|
32
|
+
// - truthStateMixed — a constituent that could be either (plain
|
|
33
|
+
// `string`, plain `number`, plain `boolean`, enum, etc.). Reaching
|
|
34
|
+
// "mixed" disqualifies the whole expression from the rule.
|
|
35
|
+
type truthState int
|
|
36
|
+
|
|
37
|
+
const (
|
|
38
|
+
truthStateUnknowable truthState = iota
|
|
39
|
+
truthStateAlwaysTruthy
|
|
40
|
+
truthStateAlwaysFalsy
|
|
41
|
+
truthStateMixed
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
type noUnnecessaryCondition struct{}
|
|
45
|
+
|
|
46
|
+
func (noUnnecessaryCondition) Name() string { return "typescript/no-unnecessary-condition" }
|
|
47
|
+
func (noUnnecessaryCondition) NeedsTypeChecker() bool {
|
|
48
|
+
return true
|
|
49
|
+
}
|
|
50
|
+
func (noUnnecessaryCondition) Visits() []shimast.Kind {
|
|
51
|
+
return []shimast.Kind{
|
|
52
|
+
shimast.KindIfStatement,
|
|
53
|
+
shimast.KindWhileStatement,
|
|
54
|
+
shimast.KindDoStatement,
|
|
55
|
+
shimast.KindForStatement,
|
|
56
|
+
shimast.KindConditionalExpression,
|
|
57
|
+
shimast.KindBinaryExpression,
|
|
58
|
+
shimast.KindPrefixUnaryExpression,
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
func (noUnnecessaryCondition) Check(ctx *Context, node *shimast.Node) {
|
|
62
|
+
if ctx.Checker == nil {
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
switch node.Kind {
|
|
66
|
+
case shimast.KindIfStatement:
|
|
67
|
+
if stmt := node.AsIfStatement(); stmt != nil {
|
|
68
|
+
noUnnecessaryConditionReport(ctx, stmt.Expression)
|
|
69
|
+
}
|
|
70
|
+
case shimast.KindWhileStatement:
|
|
71
|
+
if stmt := node.AsWhileStatement(); stmt != nil {
|
|
72
|
+
noUnnecessaryConditionReport(ctx, stmt.Expression)
|
|
73
|
+
}
|
|
74
|
+
case shimast.KindDoStatement:
|
|
75
|
+
if stmt := node.AsDoStatement(); stmt != nil {
|
|
76
|
+
noUnnecessaryConditionReport(ctx, stmt.Expression)
|
|
77
|
+
}
|
|
78
|
+
case shimast.KindForStatement:
|
|
79
|
+
if stmt := node.AsForStatement(); stmt != nil {
|
|
80
|
+
noUnnecessaryConditionReport(ctx, stmt.Condition)
|
|
81
|
+
}
|
|
82
|
+
case shimast.KindConditionalExpression:
|
|
83
|
+
if expr := node.AsConditionalExpression(); expr != nil {
|
|
84
|
+
noUnnecessaryConditionReport(ctx, expr.Condition)
|
|
85
|
+
}
|
|
86
|
+
case shimast.KindPrefixUnaryExpression:
|
|
87
|
+
expr := node.AsPrefixUnaryExpression()
|
|
88
|
+
if expr != nil && expr.Operator == shimast.KindExclamationToken {
|
|
89
|
+
noUnnecessaryConditionReport(ctx, expr.Operand)
|
|
90
|
+
}
|
|
91
|
+
case shimast.KindBinaryExpression:
|
|
92
|
+
bin := node.AsBinaryExpression()
|
|
93
|
+
if bin == nil || bin.OperatorToken == nil {
|
|
94
|
+
return
|
|
95
|
+
}
|
|
96
|
+
// Only `&&` / `||` test their left operand for truthiness. `??`
|
|
97
|
+
// short-circuits on nullish, not on falsy, and is intentionally
|
|
98
|
+
// out of scope — its dedicated rule
|
|
99
|
+
// `no-unnecessary-nullish-coalescing` covers that pattern.
|
|
100
|
+
switch bin.OperatorToken.Kind {
|
|
101
|
+
case shimast.KindAmpersandAmpersandToken, shimast.KindBarBarToken:
|
|
102
|
+
noUnnecessaryConditionReport(ctx, bin.Left)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// noUnnecessaryConditionReport flags `expr` when its static type proves
|
|
108
|
+
// the runtime truthiness is fixed. The descent through `&&` / `||`
|
|
109
|
+
// mirrors `strict-boolean-expressions`: the outer BinaryExpression visit
|
|
110
|
+
// only checks Left, so the recursion here picks up Right too. Wrapping
|
|
111
|
+
// parens are skipped via stripParens.
|
|
112
|
+
func noUnnecessaryConditionReport(ctx *Context, expr *shimast.Node) {
|
|
113
|
+
if expr == nil {
|
|
114
|
+
return
|
|
115
|
+
}
|
|
116
|
+
expr = stripParens(expr)
|
|
117
|
+
if expr == nil {
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
if expr.Kind == shimast.KindBinaryExpression {
|
|
121
|
+
bin := expr.AsBinaryExpression()
|
|
122
|
+
if bin != nil && bin.OperatorToken != nil {
|
|
123
|
+
switch bin.OperatorToken.Kind {
|
|
124
|
+
case shimast.KindAmpersandAmpersandToken, shimast.KindBarBarToken:
|
|
125
|
+
noUnnecessaryConditionReport(ctx, bin.Left)
|
|
126
|
+
noUnnecessaryConditionReport(ctx, bin.Right)
|
|
127
|
+
return
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
t := ctx.Checker.GetTypeAtLocation(expr)
|
|
132
|
+
if t == nil {
|
|
133
|
+
return
|
|
134
|
+
}
|
|
135
|
+
switch noUnnecessaryConditionEvaluate(ctx.Checker, t) {
|
|
136
|
+
case truthStateAlwaysTruthy:
|
|
137
|
+
ctx.Report(expr, "Unnecessary conditional, value is always truthy.")
|
|
138
|
+
case truthStateAlwaysFalsy:
|
|
139
|
+
ctx.Report(expr, "Unnecessary conditional, value is always falsy.")
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// noUnnecessaryConditionEvaluate folds a type into a single truthState by
|
|
144
|
+
// combining each constituent's state under union semantics: any
|
|
145
|
+
// unknowable constituent forces unknowable, otherwise the combined state
|
|
146
|
+
// is the unique truthy / falsy / mixed reading of every constituent.
|
|
147
|
+
// Intersections are not analyzed structurally — they bail to unknowable
|
|
148
|
+
// because the Checker may resolve them into shapes (e.g. branded
|
|
149
|
+
// primitives) the rule cannot reason about safely.
|
|
150
|
+
func noUnnecessaryConditionEvaluate(checker *shimchecker.Checker, t *shimchecker.Type) truthState {
|
|
151
|
+
if checker == nil || t == nil {
|
|
152
|
+
return truthStateUnknowable
|
|
153
|
+
}
|
|
154
|
+
flags := t.Flags()
|
|
155
|
+
if flags&(shimchecker.TypeFlagsAny|shimchecker.TypeFlagsUnknown|shimchecker.TypeFlagsNever) != 0 {
|
|
156
|
+
return truthStateUnknowable
|
|
157
|
+
}
|
|
158
|
+
if flags&shimchecker.TypeFlagsIntersection != 0 {
|
|
159
|
+
// Intersections such as `Foo & { brand: "x" }` carry semantics the
|
|
160
|
+
// rule cannot prove without a deeper Checker walk, so we keep the
|
|
161
|
+
// conservative bail.
|
|
162
|
+
return truthStateUnknowable
|
|
163
|
+
}
|
|
164
|
+
if flags&shimchecker.TypeFlagsUnion != 0 {
|
|
165
|
+
parts := t.Types()
|
|
166
|
+
if len(parts) == 0 {
|
|
167
|
+
return truthStateUnknowable
|
|
168
|
+
}
|
|
169
|
+
combined := truthState(-1)
|
|
170
|
+
for _, part := range parts {
|
|
171
|
+
if part == nil {
|
|
172
|
+
return truthStateUnknowable
|
|
173
|
+
}
|
|
174
|
+
state := noUnnecessaryConditionEvaluate(checker, part)
|
|
175
|
+
if state == truthStateUnknowable || state == truthStateMixed {
|
|
176
|
+
// A union with even one constituent we can't pin breaks the
|
|
177
|
+
// "always X" guarantee — bail.
|
|
178
|
+
return state
|
|
179
|
+
}
|
|
180
|
+
if combined == truthState(-1) {
|
|
181
|
+
combined = state
|
|
182
|
+
continue
|
|
183
|
+
}
|
|
184
|
+
if combined != state {
|
|
185
|
+
// `string | null` has both a falsy ("") and a always-falsy
|
|
186
|
+
// (null) outcome that disagree across constituents — fall
|
|
187
|
+
// back to mixed so the rule stays silent.
|
|
188
|
+
return truthStateMixed
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
if combined == truthState(-1) {
|
|
192
|
+
return truthStateUnknowable
|
|
193
|
+
}
|
|
194
|
+
return combined
|
|
195
|
+
}
|
|
196
|
+
// Atomic types.
|
|
197
|
+
if flags&(shimchecker.TypeFlagsNull|shimchecker.TypeFlagsUndefined|shimchecker.TypeFlagsVoid) != 0 {
|
|
198
|
+
return truthStateAlwaysFalsy
|
|
199
|
+
}
|
|
200
|
+
if flags&shimchecker.TypeFlagsBooleanLiteral != 0 {
|
|
201
|
+
text := checker.TypeToString(t)
|
|
202
|
+
if strings.TrimSpace(text) == "false" {
|
|
203
|
+
return truthStateAlwaysFalsy
|
|
204
|
+
}
|
|
205
|
+
if strings.TrimSpace(text) == "true" {
|
|
206
|
+
return truthStateAlwaysTruthy
|
|
207
|
+
}
|
|
208
|
+
return truthStateUnknowable
|
|
209
|
+
}
|
|
210
|
+
if flags&shimchecker.TypeFlagsStringLiteral != 0 {
|
|
211
|
+
text := strings.TrimSpace(checker.TypeToString(t))
|
|
212
|
+
if text == `""` || text == `''` {
|
|
213
|
+
return truthStateAlwaysFalsy
|
|
214
|
+
}
|
|
215
|
+
return truthStateAlwaysTruthy
|
|
216
|
+
}
|
|
217
|
+
if flags&shimchecker.TypeFlagsNumberLiteral != 0 {
|
|
218
|
+
text := strings.TrimSpace(checker.TypeToString(t))
|
|
219
|
+
// `0`, `0.0`, `-0` all stringify as `0`; everything else is truthy.
|
|
220
|
+
// `NaN` is not representable as a literal type, so it cannot reach
|
|
221
|
+
// this branch.
|
|
222
|
+
if text == "0" {
|
|
223
|
+
return truthStateAlwaysFalsy
|
|
224
|
+
}
|
|
225
|
+
return truthStateAlwaysTruthy
|
|
226
|
+
}
|
|
227
|
+
if flags&shimchecker.TypeFlagsBigIntLiteral != 0 {
|
|
228
|
+
text := strings.TrimSpace(checker.TypeToString(t))
|
|
229
|
+
if text == "0n" {
|
|
230
|
+
return truthStateAlwaysFalsy
|
|
231
|
+
}
|
|
232
|
+
return truthStateAlwaysTruthy
|
|
233
|
+
}
|
|
234
|
+
if flags&shimchecker.TypeFlagsObject != 0 {
|
|
235
|
+
// A non-nullable object value is always truthy. `{}`, arrays,
|
|
236
|
+
// class instances, functions, and structural records all share
|
|
237
|
+
// this contract; only `null` / `undefined` make an object position
|
|
238
|
+
// falsy and those flags route to the always-falsy branch above.
|
|
239
|
+
return truthStateAlwaysTruthy
|
|
240
|
+
}
|
|
241
|
+
// Plain `string` / `number` / `boolean` / `bigint` / enum / symbol /
|
|
242
|
+
// type parameter / index / template literal — every one of these can
|
|
243
|
+
// hold both truthy and falsy values (or escapes static reasoning), so
|
|
244
|
+
// the rule must stay silent.
|
|
245
|
+
return truthStateMixed
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
func init() {
|
|
249
|
+
Register(noUnnecessaryCondition{})
|
|
250
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// typescript/no-unnecessary-qualifier: a qualified reference like
|
|
2
|
+
// `Foo.Bar` written inside `namespace Foo { ... }` (or `enum Foo { ...,
|
|
3
|
+
// X = Foo.Y, ... }`) names the same scope the reference is already in.
|
|
4
|
+
// The qualifier adds no information; dropping `Foo.` leaves the
|
|
5
|
+
// identical binding lookup. typescript-eslint:
|
|
6
|
+
// https://typescript-eslint.io/rules/no-unnecessary-qualifier/
|
|
7
|
+
package linthost
|
|
8
|
+
|
|
9
|
+
import (
|
|
10
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
// noUnnecessaryQualifier inspects every two-segment qualified reference
|
|
14
|
+
// whose head is a plain identifier — `QualifiedName` shows up in type
|
|
15
|
+
// position (`Foo.Bar` inside a type annotation) and
|
|
16
|
+
// `PropertyAccessExpression` shows up in value position. The check is
|
|
17
|
+
// AST-only: it walks the ancestor chain for an enclosing `namespace
|
|
18
|
+
// <head> { ... }` or `enum <head> { ... }` declaration and reports when
|
|
19
|
+
// one is found. The rule deliberately does not consult the Checker
|
|
20
|
+
// because the upstream rule operates on lexical scope identity, which
|
|
21
|
+
// the AST already encodes via declaration ancestry.
|
|
22
|
+
type noUnnecessaryQualifier struct{}
|
|
23
|
+
|
|
24
|
+
func (noUnnecessaryQualifier) Name() string {
|
|
25
|
+
return "typescript/no-unnecessary-qualifier"
|
|
26
|
+
}
|
|
27
|
+
func (noUnnecessaryQualifier) Visits() []shimast.Kind {
|
|
28
|
+
return []shimast.Kind{
|
|
29
|
+
shimast.KindQualifiedName,
|
|
30
|
+
shimast.KindPropertyAccessExpression,
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
func (noUnnecessaryQualifier) Check(ctx *Context, node *shimast.Node) {
|
|
34
|
+
head := noUnnecessaryQualifierHead(node)
|
|
35
|
+
if head == "" {
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
if !noUnnecessaryQualifierHasEnclosingScope(node, head) {
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
ctx.Report(node, "Qualifier `"+head+"` is the enclosing namespace or enum — drop the qualifier.")
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// noUnnecessaryQualifierHead returns the LHS identifier text when the
|
|
45
|
+
// node is a two-segment qualified reference (`A.B`) whose head is a
|
|
46
|
+
// plain identifier. Returns "" for nested chains (`A.B.C`), computed
|
|
47
|
+
// accesses, or non-identifier heads — those shapes don't match the
|
|
48
|
+
// "qualifier names the enclosing scope" pattern.
|
|
49
|
+
func noUnnecessaryQualifierHead(node *shimast.Node) string {
|
|
50
|
+
if node == nil {
|
|
51
|
+
return ""
|
|
52
|
+
}
|
|
53
|
+
switch node.Kind {
|
|
54
|
+
case shimast.KindQualifiedName:
|
|
55
|
+
qn := node.AsQualifiedName()
|
|
56
|
+
if qn == nil || qn.Left == nil {
|
|
57
|
+
return ""
|
|
58
|
+
}
|
|
59
|
+
if qn.Left.Kind != shimast.KindIdentifier {
|
|
60
|
+
return ""
|
|
61
|
+
}
|
|
62
|
+
return identifierText(qn.Left)
|
|
63
|
+
case shimast.KindPropertyAccessExpression:
|
|
64
|
+
pa := node.AsPropertyAccessExpression()
|
|
65
|
+
if pa == nil || pa.Expression == nil || pa.Name() == nil {
|
|
66
|
+
return ""
|
|
67
|
+
}
|
|
68
|
+
// Optional chains (`Foo?.Bar`) aren't redundant in the same
|
|
69
|
+
// sense — the `?.` changes runtime behavior, so leave them be.
|
|
70
|
+
if pa.QuestionDotToken != nil {
|
|
71
|
+
return ""
|
|
72
|
+
}
|
|
73
|
+
if pa.Expression.Kind != shimast.KindIdentifier {
|
|
74
|
+
return ""
|
|
75
|
+
}
|
|
76
|
+
return identifierText(pa.Expression)
|
|
77
|
+
}
|
|
78
|
+
return ""
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// noUnnecessaryQualifierHasEnclosingScope reports whether `node`
|
|
82
|
+
// appears inside a `namespace <head> { ... }` or `enum <head> { ... }`
|
|
83
|
+
// declaration body. The walk climbs `Parent` links until it finds a
|
|
84
|
+
// matching block or hits the SourceFile root.
|
|
85
|
+
func noUnnecessaryQualifierHasEnclosingScope(node *shimast.Node, head string) bool {
|
|
86
|
+
for cur := node.Parent; cur != nil; cur = cur.Parent {
|
|
87
|
+
switch cur.Kind {
|
|
88
|
+
case shimast.KindModuleDeclaration:
|
|
89
|
+
decl := cur.AsModuleDeclaration()
|
|
90
|
+
if decl == nil || decl.Name() == nil {
|
|
91
|
+
continue
|
|
92
|
+
}
|
|
93
|
+
// `declare module "fs"` carries a string-literal name and
|
|
94
|
+
// does not bind an identifier in the surrounding scope —
|
|
95
|
+
// skip those entirely. The rule only fires when the head
|
|
96
|
+
// matches the enclosing namespace's identifier name.
|
|
97
|
+
if decl.Name().Kind != shimast.KindIdentifier {
|
|
98
|
+
continue
|
|
99
|
+
}
|
|
100
|
+
if identifierText(decl.Name()) == head {
|
|
101
|
+
return true
|
|
102
|
+
}
|
|
103
|
+
case shimast.KindEnumDeclaration:
|
|
104
|
+
decl := cur.AsEnumDeclaration()
|
|
105
|
+
if decl == nil || decl.Name() == nil {
|
|
106
|
+
continue
|
|
107
|
+
}
|
|
108
|
+
if identifierText(decl.Name()) == head {
|
|
109
|
+
return true
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return false
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
func init() {
|
|
117
|
+
Register(noUnnecessaryQualifier{})
|
|
118
|
+
}
|