@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,104 @@
|
|
|
1
|
+
// AST-only baseline of typescript-eslint's `prefer-nullish-coalescing`.
|
|
2
|
+
//
|
|
3
|
+
// The rule discourages `x || y`, `x ||= y`, and the ternary `x ? x : y`
|
|
4
|
+
// pattern when the intent is to substitute a default for `null` /
|
|
5
|
+
// `undefined`. `||` short-circuits on every falsy value (0, "", false,
|
|
6
|
+
// NaN), so what reads as "default this if missing" silently coerces
|
|
7
|
+
// legitimate zeros and empty strings. The ES2020 `??` operator
|
|
8
|
+
// short-circuits only on nullish values and is almost always what the
|
|
9
|
+
// author meant.
|
|
10
|
+
//
|
|
11
|
+
// Without the Checker the rule cannot prove `x` actually admits
|
|
12
|
+
// `null | undefined`, so the conservative AST-only baseline skips
|
|
13
|
+
// operands that the surrounding context already coerces to boolean —
|
|
14
|
+
// `if (a || b)`, `!(a || b)`, `cond ? a || b : …`, etc. — and fires on
|
|
15
|
+
// the remaining value-producing positions. This mirrors the upstream
|
|
16
|
+
// rule's behavior on plain JS where strictNullChecks is off and the
|
|
17
|
+
// rule still flags the same shapes.
|
|
18
|
+
// https://typescript-eslint.io/rules/prefer-nullish-coalescing/
|
|
19
|
+
package linthost
|
|
20
|
+
|
|
21
|
+
import (
|
|
22
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
type preferNullishCoalescing struct{}
|
|
26
|
+
|
|
27
|
+
func (preferNullishCoalescing) Name() string { return "typescript/prefer-nullish-coalescing" }
|
|
28
|
+
func (preferNullishCoalescing) Visits() []shimast.Kind {
|
|
29
|
+
return []shimast.Kind{
|
|
30
|
+
shimast.KindBinaryExpression,
|
|
31
|
+
shimast.KindConditionalExpression,
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
func (preferNullishCoalescing) Check(ctx *Context, node *shimast.Node) {
|
|
35
|
+
switch node.Kind {
|
|
36
|
+
case shimast.KindBinaryExpression:
|
|
37
|
+
expr := node.AsBinaryExpression()
|
|
38
|
+
if expr == nil || expr.OperatorToken == nil {
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
switch expr.OperatorToken.Kind {
|
|
42
|
+
case shimast.KindBarBarToken:
|
|
43
|
+
if isInBooleanContext(node) {
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
reportPreferNullishCoalescing(ctx, expr.OperatorToken, "Prefer `??` over `||` when the intent is to default `null` / `undefined` — `||` also short-circuits on falsy values like 0, \"\", and false.")
|
|
47
|
+
case shimast.KindBarBarEqualsToken:
|
|
48
|
+
reportPreferNullishCoalescing(ctx, expr.OperatorToken, "Prefer `??=` over `||=` when the intent is to default `null` / `undefined` — `||=` also assigns on falsy values like 0, \"\", and false.")
|
|
49
|
+
}
|
|
50
|
+
case shimast.KindConditionalExpression:
|
|
51
|
+
cond := node.AsConditionalExpression()
|
|
52
|
+
if cond == nil || cond.Condition == nil || cond.WhenTrue == nil {
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
// `x ? x : y` — the `whenTrue` branch is the same expression as
|
|
56
|
+
// the test. Compare canonical text after stripping parentheses
|
|
57
|
+
// from both sides so `(x) ? x : y` still matches.
|
|
58
|
+
if !ternarySelfTest(ctx, cond) {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
ctx.Report(node, "Prefer `??` over `x ? x : y` when the intent is to default `null` / `undefined` — the ternary form also falls through on falsy values like 0, \"\", and false.")
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// reportPreferNullishCoalescing pins the diagnostic range to the
|
|
66
|
+
// operator token (`||` / `||=`) rather than the whole binary expression
|
|
67
|
+
// so the squiggle highlights the offending operator and editor "go to
|
|
68
|
+
// fix" actions hover over the token the rule is about.
|
|
69
|
+
func reportPreferNullishCoalescing(ctx *Context, operator *shimast.Node, message string) {
|
|
70
|
+
pos, end := tokenRange(ctx.File, operator)
|
|
71
|
+
if pos < 0 {
|
|
72
|
+
ctx.Report(operator, message)
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
ctx.ReportRange(pos, end, message)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ternarySelfTest reports whether `cond ? whenTrue : whenFalse` has the
|
|
79
|
+
// shape `x ? x : y` — i.e. the truthy branch repeats the condition. The
|
|
80
|
+
// comparison uses `nodeText` so parenthesized variants (`(x) ? x : y`)
|
|
81
|
+
// and member-access chains (`a.b ? a.b : c`) both match. Side-effecting
|
|
82
|
+
// expressions are intentionally not excluded here: the upstream rule
|
|
83
|
+
// fires on `f() ? f() : g()` too and lets the author decide whether the
|
|
84
|
+
// transform is safe.
|
|
85
|
+
func ternarySelfTest(ctx *Context, cond *shimast.ConditionalExpression) bool {
|
|
86
|
+
if ctx == nil || ctx.File == nil || cond == nil {
|
|
87
|
+
return false
|
|
88
|
+
}
|
|
89
|
+
test := stripParens(cond.Condition)
|
|
90
|
+
whenTrue := stripParens(cond.WhenTrue)
|
|
91
|
+
if test == nil || whenTrue == nil {
|
|
92
|
+
return false
|
|
93
|
+
}
|
|
94
|
+
testText := nodeText(ctx.File, test)
|
|
95
|
+
whenTrueText := nodeText(ctx.File, whenTrue)
|
|
96
|
+
if testText == "" || whenTrueText == "" {
|
|
97
|
+
return false
|
|
98
|
+
}
|
|
99
|
+
return testText == whenTrueText
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
func init() {
|
|
103
|
+
Register(preferNullishCoalescing{})
|
|
104
|
+
}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
// preferOptionalChain reports `a && a.b` / `a && a.b && a.b.c` and
|
|
2
|
+
// `a != null && a.b` chained boolean patterns and suggests `a?.b?.c`.
|
|
3
|
+
// The optional-chain form is shorter and short-circuits to `undefined`
|
|
4
|
+
// instead of the leftmost falsy value, which is almost always what the
|
|
5
|
+
// author wanted when guarding a property access against a nullish base.
|
|
6
|
+
//
|
|
7
|
+
// This is the AST-only baseline: the rule fires when the receiver of
|
|
8
|
+
// the right-hand member access textually starts with the left-hand
|
|
9
|
+
// guard expression. Cases where the chain crosses through a call
|
|
10
|
+
// expression with arguments are skipped — those have observable side
|
|
11
|
+
// effects, so the `?.` form is not equivalent.
|
|
12
|
+
// https://typescript-eslint.io/rules/prefer-optional-chain/
|
|
13
|
+
package linthost
|
|
14
|
+
|
|
15
|
+
import (
|
|
16
|
+
"strings"
|
|
17
|
+
|
|
18
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
type preferOptionalChain struct{}
|
|
22
|
+
|
|
23
|
+
func (preferOptionalChain) Name() string { return "typescript/prefer-optional-chain" }
|
|
24
|
+
func (preferOptionalChain) Visits() []shimast.Kind {
|
|
25
|
+
return []shimast.Kind{shimast.KindBinaryExpression}
|
|
26
|
+
}
|
|
27
|
+
func (preferOptionalChain) Check(ctx *Context, node *shimast.Node) {
|
|
28
|
+
expr := node.AsBinaryExpression()
|
|
29
|
+
if expr == nil || expr.OperatorToken == nil {
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
if expr.OperatorToken.Kind != shimast.KindAmpersandAmpersandToken {
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
// Skip when the binary expression is itself the left side of an
|
|
36
|
+
// outer `&&` — the outer node will be visited and report the full
|
|
37
|
+
// chain. Reporting at every inner conjunct would flood `a && a.b
|
|
38
|
+
// && a.b.c` with two diagnostics on the same chain.
|
|
39
|
+
if parent := node.Parent; parent != nil && parent.Kind == shimast.KindBinaryExpression {
|
|
40
|
+
pe := parent.AsBinaryExpression()
|
|
41
|
+
if pe != nil && pe.OperatorToken != nil &&
|
|
42
|
+
pe.OperatorToken.Kind == shimast.KindAmpersandAmpersandToken &&
|
|
43
|
+
pe.Left == node {
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
guardText, ok := preferOptionalChainGuardText(ctx, expr.Left)
|
|
48
|
+
if !ok {
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
right := stripParens(expr.Right)
|
|
52
|
+
if !preferOptionalChainRightMatches(ctx, right, guardText) {
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
ctx.Report(node, "Prefer an optional chain (`a?.b`) over `a && a.b` — shorter and short-circuits to `undefined` instead of the leftmost falsy value.")
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// preferOptionalChainRightmostConjunct returns the rightmost operand
|
|
59
|
+
// of a left-associative `&&` chain. For `(a && a.b) && a.b.c` the
|
|
60
|
+
// rightmost conjunct of the left is `a.b`, which is the immediate
|
|
61
|
+
// guard the outer `&&` was extending.
|
|
62
|
+
func preferOptionalChainRightmostConjunct(node *shimast.Node) *shimast.Node {
|
|
63
|
+
node = stripParens(node)
|
|
64
|
+
for node != nil && node.Kind == shimast.KindBinaryExpression {
|
|
65
|
+
inner := node.AsBinaryExpression()
|
|
66
|
+
if inner == nil || inner.OperatorToken == nil ||
|
|
67
|
+
inner.OperatorToken.Kind != shimast.KindAmpersandAmpersandToken ||
|
|
68
|
+
inner.Right == nil {
|
|
69
|
+
return node
|
|
70
|
+
}
|
|
71
|
+
node = stripParens(inner.Right)
|
|
72
|
+
}
|
|
73
|
+
return node
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// preferOptionalChainGuardText returns the textual identity of the
|
|
77
|
+
// guard expression on the left of `&&`. The guard may be an identifier
|
|
78
|
+
// (`a && a.b`), a property access (`a.b && a.b.c`), or a `!= null` /
|
|
79
|
+
// `!== null` / `!== undefined` comparison (`a != null && a.b`). For the
|
|
80
|
+
// comparison form, the returned text is the non-null side, which is
|
|
81
|
+
// what the right-hand access must start with.
|
|
82
|
+
func preferOptionalChainGuardText(ctx *Context, left *shimast.Node) (string, bool) {
|
|
83
|
+
left = stripParens(left)
|
|
84
|
+
if left == nil {
|
|
85
|
+
return "", false
|
|
86
|
+
}
|
|
87
|
+
switch left.Kind {
|
|
88
|
+
case shimast.KindIdentifier, shimast.KindPropertyAccessExpression:
|
|
89
|
+
text := nodeText(ctx.File, left)
|
|
90
|
+
return text, text != ""
|
|
91
|
+
case shimast.KindBinaryExpression:
|
|
92
|
+
inner := left.AsBinaryExpression()
|
|
93
|
+
if inner == nil || inner.OperatorToken == nil {
|
|
94
|
+
return "", false
|
|
95
|
+
}
|
|
96
|
+
// Chain extension: `(x && a.b) && a.b.c` — peel down to the
|
|
97
|
+
// rightmost conjunct (`a.b`) and use it as the guard against
|
|
98
|
+
// the outer right side.
|
|
99
|
+
if inner.OperatorToken.Kind == shimast.KindAmpersandAmpersandToken {
|
|
100
|
+
conjunct := preferOptionalChainRightmostConjunct(left)
|
|
101
|
+
if conjunct == nil {
|
|
102
|
+
return "", false
|
|
103
|
+
}
|
|
104
|
+
switch conjunct.Kind {
|
|
105
|
+
case shimast.KindIdentifier, shimast.KindPropertyAccessExpression:
|
|
106
|
+
text := nodeText(ctx.File, conjunct)
|
|
107
|
+
return text, text != ""
|
|
108
|
+
}
|
|
109
|
+
return "", false
|
|
110
|
+
}
|
|
111
|
+
if inner.OperatorToken.Kind != shimast.KindExclamationEqualsToken &&
|
|
112
|
+
inner.OperatorToken.Kind != shimast.KindExclamationEqualsEqualsToken {
|
|
113
|
+
return "", false
|
|
114
|
+
}
|
|
115
|
+
lhs := stripParens(inner.Left)
|
|
116
|
+
rhs := stripParens(inner.Right)
|
|
117
|
+
if subject, ok := preferOptionalChainNullishCompareSubject(ctx, lhs, rhs); ok {
|
|
118
|
+
return subject, true
|
|
119
|
+
}
|
|
120
|
+
if subject, ok := preferOptionalChainNullishCompareSubject(ctx, rhs, lhs); ok {
|
|
121
|
+
return subject, true
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return "", false
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// preferOptionalChainNullishCompareSubject returns the textual identity
|
|
128
|
+
// of `subject` when `nullish` is `null` or `undefined` and `subject` is
|
|
129
|
+
// an identifier or property access. Returns the empty text otherwise.
|
|
130
|
+
func preferOptionalChainNullishCompareSubject(
|
|
131
|
+
ctx *Context,
|
|
132
|
+
subject, nullish *shimast.Node,
|
|
133
|
+
) (string, bool) {
|
|
134
|
+
if subject == nil || nullish == nil {
|
|
135
|
+
return "", false
|
|
136
|
+
}
|
|
137
|
+
if !preferOptionalChainIsNullOrUndefined(nullish) {
|
|
138
|
+
return "", false
|
|
139
|
+
}
|
|
140
|
+
switch subject.Kind {
|
|
141
|
+
case shimast.KindIdentifier, shimast.KindPropertyAccessExpression:
|
|
142
|
+
text := nodeText(ctx.File, subject)
|
|
143
|
+
return text, text != ""
|
|
144
|
+
}
|
|
145
|
+
return "", false
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// preferOptionalChainIsNullOrUndefined reports whether node is the
|
|
149
|
+
// `null` keyword or the `undefined` identifier.
|
|
150
|
+
func preferOptionalChainIsNullOrUndefined(node *shimast.Node) bool {
|
|
151
|
+
if node == nil {
|
|
152
|
+
return false
|
|
153
|
+
}
|
|
154
|
+
if node.Kind == shimast.KindNullKeyword {
|
|
155
|
+
return true
|
|
156
|
+
}
|
|
157
|
+
if node.Kind == shimast.KindIdentifier {
|
|
158
|
+
return identifierText(node) == "undefined"
|
|
159
|
+
}
|
|
160
|
+
return false
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// preferOptionalChainRightMatches reports whether `right` is a
|
|
164
|
+
// property access or call expression whose receiver textually starts
|
|
165
|
+
// with `guardText` followed by `.` or `[`. Calls with arguments are
|
|
166
|
+
// rejected — the `?.` rewrite would not preserve side-effect ordering
|
|
167
|
+
// when the arguments themselves can have side effects.
|
|
168
|
+
func preferOptionalChainRightMatches(
|
|
169
|
+
ctx *Context,
|
|
170
|
+
right *shimast.Node,
|
|
171
|
+
guardText string,
|
|
172
|
+
) bool {
|
|
173
|
+
if right == nil || guardText == "" {
|
|
174
|
+
return false
|
|
175
|
+
}
|
|
176
|
+
switch right.Kind {
|
|
177
|
+
case shimast.KindPropertyAccessExpression:
|
|
178
|
+
access := right.AsPropertyAccessExpression()
|
|
179
|
+
if access == nil || access.Expression == nil {
|
|
180
|
+
return false
|
|
181
|
+
}
|
|
182
|
+
return preferOptionalChainHasPrefix(ctx, right, guardText)
|
|
183
|
+
case shimast.KindCallExpression:
|
|
184
|
+
call := right.AsCallExpression()
|
|
185
|
+
if call == nil || call.Expression == nil {
|
|
186
|
+
return false
|
|
187
|
+
}
|
|
188
|
+
// Skip calls with arguments — their evaluation cannot be
|
|
189
|
+
// observed identically through `?.()`.
|
|
190
|
+
if call.Arguments != nil && len(call.Arguments.Nodes) > 0 {
|
|
191
|
+
return false
|
|
192
|
+
}
|
|
193
|
+
// The callee receiver must itself be a property access; a
|
|
194
|
+
// bare identifier call (`a()`) has no chain to fold.
|
|
195
|
+
callee := stripParens(call.Expression)
|
|
196
|
+
if callee == nil || callee.Kind != shimast.KindPropertyAccessExpression {
|
|
197
|
+
return false
|
|
198
|
+
}
|
|
199
|
+
return preferOptionalChainHasPrefix(ctx, right, guardText)
|
|
200
|
+
}
|
|
201
|
+
return false
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// preferOptionalChainHasPrefix returns whether the textual form of
|
|
205
|
+
// `node` begins with `guard` followed by a `.` or `[` — the only
|
|
206
|
+
// continuations that mean "a property of the guarded value".
|
|
207
|
+
func preferOptionalChainHasPrefix(
|
|
208
|
+
ctx *Context,
|
|
209
|
+
node *shimast.Node,
|
|
210
|
+
guard string,
|
|
211
|
+
) bool {
|
|
212
|
+
text := nodeText(ctx.File, node)
|
|
213
|
+
if !strings.HasPrefix(text, guard) {
|
|
214
|
+
return false
|
|
215
|
+
}
|
|
216
|
+
if len(text) == len(guard) {
|
|
217
|
+
return false
|
|
218
|
+
}
|
|
219
|
+
switch text[len(guard)] {
|
|
220
|
+
case '.', '[', '(':
|
|
221
|
+
return true
|
|
222
|
+
}
|
|
223
|
+
return false
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
func init() {
|
|
227
|
+
Register(preferOptionalChain{})
|
|
228
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
// TypeScript-aware analog of typescript/only-throw-error for Promise
|
|
2
|
+
// rejection sites: `Promise.reject(value)` should hand callers an Error
|
|
3
|
+
// instance, not a primitive or other non-Error value. A non-Error
|
|
4
|
+
// rejection loses the structured stack trace and breaks downstream
|
|
5
|
+
// `instanceof Error` checks in `.catch(...)` / `try { await … } catch
|
|
6
|
+
// (err)` handlers. typescript-eslint:
|
|
7
|
+
// https://typescript-eslint.io/rules/prefer-promise-reject-errors/
|
|
8
|
+
package linthost
|
|
9
|
+
|
|
10
|
+
import (
|
|
11
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
12
|
+
shimchecker "github.com/microsoft/typescript-go/shim/checker"
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
// preferPromiseRejectErrors reports `Promise.reject(arg)`, `p.reject(arg)`
|
|
16
|
+
// on a Promise-typed receiver, and `reject(arg)` calls to the second
|
|
17
|
+
// parameter of a `new Promise((_, reject) => …)` executor when `arg`'s
|
|
18
|
+
// static type is a primitive (string / number / boolean / bigint / void
|
|
19
|
+
// / undefined / null). Mirrors `onlyThrowError` for `throw` statements.
|
|
20
|
+
//
|
|
21
|
+
// Type-aware. `any` / `unknown` / `never` pass through — they propagate
|
|
22
|
+
// from generic helpers and a strict rejection would explode at every
|
|
23
|
+
// re-reject of a caught `unknown`. Object types (including plain object
|
|
24
|
+
// literals) are conservatively allowed by this baseline; the practical
|
|
25
|
+
// effect is that `Promise.reject("boom")` and `Promise.reject(42)` are
|
|
26
|
+
// caught but `Promise.reject({ code: 1 })` slips through.
|
|
27
|
+
type preferPromiseRejectErrors struct{}
|
|
28
|
+
|
|
29
|
+
func (preferPromiseRejectErrors) Name() string {
|
|
30
|
+
return "typescript/prefer-promise-reject-errors"
|
|
31
|
+
}
|
|
32
|
+
func (preferPromiseRejectErrors) NeedsTypeChecker() bool {
|
|
33
|
+
return true
|
|
34
|
+
}
|
|
35
|
+
func (preferPromiseRejectErrors) Visits() []shimast.Kind {
|
|
36
|
+
return []shimast.Kind{shimast.KindCallExpression}
|
|
37
|
+
}
|
|
38
|
+
func (preferPromiseRejectErrors) Check(ctx *Context, node *shimast.Node) {
|
|
39
|
+
if ctx.Checker == nil {
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
call := node.AsCallExpression()
|
|
43
|
+
if call == nil || call.Expression == nil {
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
if !preferPromiseRejectErrorsIsRejectCall(ctx, call, node) {
|
|
47
|
+
return
|
|
48
|
+
}
|
|
49
|
+
if call.Arguments == nil || len(call.Arguments.Nodes) == 0 {
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
arg := stripParens(call.Arguments.Nodes[0])
|
|
53
|
+
if arg == nil {
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
t := ctx.Checker.GetTypeAtLocation(arg)
|
|
57
|
+
if t == nil {
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
if preferPromiseRejectErrorsIsNonError(ctx.Checker, t) {
|
|
61
|
+
ctx.Report(node, "Reject promises with an Error object instead of a non-Error value.")
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// preferPromiseRejectErrorsIsRejectCall returns true when `call` is one of
|
|
66
|
+
// - `Promise.reject(arg)`
|
|
67
|
+
// - `<promise-typed-receiver>.reject(arg)`
|
|
68
|
+
// - a bare `reject(arg)` call to the second parameter name of an
|
|
69
|
+
// enclosing `new Promise((_, reject) => …)` executor.
|
|
70
|
+
//
|
|
71
|
+
// `node` is the AST node form of `call`, used for the parent walk.
|
|
72
|
+
func preferPromiseRejectErrorsIsRejectCall(ctx *Context, call *shimast.CallExpression, node *shimast.Node) bool {
|
|
73
|
+
receiver, method, ok := promisePropertyAccessParts(call.Expression)
|
|
74
|
+
if ok && method == "reject" {
|
|
75
|
+
if identifierText(receiver) == "Promise" {
|
|
76
|
+
return true
|
|
77
|
+
}
|
|
78
|
+
if ctx.Checker != nil && receiver != nil {
|
|
79
|
+
if t := ctx.Checker.GetTypeAtLocation(receiver); t != nil &&
|
|
80
|
+
isPromiseTypedExpression(ctx.Checker, t) {
|
|
81
|
+
return true
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return false
|
|
85
|
+
}
|
|
86
|
+
// Bare identifier call — check Promise executor binding.
|
|
87
|
+
name := callCalleeName(call)
|
|
88
|
+
if name == "" {
|
|
89
|
+
return false
|
|
90
|
+
}
|
|
91
|
+
return preferPromiseRejectErrorsIsExecutorReject(node, name)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// preferPromiseRejectErrorsIsExecutorReject walks parent function-like
|
|
95
|
+
// scopes from `node` and reports true when one of those scopes is the
|
|
96
|
+
// executor parameter of `new Promise(...)` and the executor's second
|
|
97
|
+
// parameter is named `name`. Mirrors the param walking used by
|
|
98
|
+
// `promiseNoMultipleResolved`.
|
|
99
|
+
func preferPromiseRejectErrorsIsExecutorReject(node *shimast.Node, name string) bool {
|
|
100
|
+
for fn := nearestFunctionLike(node); fn != nil; fn = nearestFunctionLike(fn) {
|
|
101
|
+
if !preferPromiseRejectErrorsIsPromiseExecutorFn(fn) {
|
|
102
|
+
continue
|
|
103
|
+
}
|
|
104
|
+
params := fn.Parameters()
|
|
105
|
+
if len(params) < 2 {
|
|
106
|
+
continue
|
|
107
|
+
}
|
|
108
|
+
if parameterIdentifierName(params[1]) == name {
|
|
109
|
+
return true
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return false
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// preferPromiseRejectErrorsIsPromiseExecutorFn reports whether `fn` is
|
|
116
|
+
// the first argument of an enclosing `new Promise(...)` expression. The
|
|
117
|
+
// walk strips parentheses the same way `isPromiseCallbackFunctionFor`
|
|
118
|
+
// does in rules_promise.go so `new Promise(((_, reject) => …))` still
|
|
119
|
+
// matches.
|
|
120
|
+
func preferPromiseRejectErrorsIsPromiseExecutorFn(fn *shimast.Node) bool {
|
|
121
|
+
if fn == nil || !isFunctionLikeKind(fn) {
|
|
122
|
+
return false
|
|
123
|
+
}
|
|
124
|
+
cur := fn
|
|
125
|
+
for parent := cur.Parent; parent != nil && parent.Kind == shimast.KindParenthesizedExpression; parent = parent.Parent {
|
|
126
|
+
cur = parent
|
|
127
|
+
}
|
|
128
|
+
newExpr := cur.Parent
|
|
129
|
+
if newExpr == nil || newExpr.Kind != shimast.KindNewExpression {
|
|
130
|
+
return false
|
|
131
|
+
}
|
|
132
|
+
ne := newExpr.AsNewExpression()
|
|
133
|
+
if ne == nil || identifierText(ne.Expression) != "Promise" || ne.Arguments == nil || len(ne.Arguments.Nodes) == 0 {
|
|
134
|
+
return false
|
|
135
|
+
}
|
|
136
|
+
return stripParens(ne.Arguments.Nodes[0]) == fn
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// preferPromiseRejectErrorsIsNonError mirrors `onlyThrowErrorIsPrimitive`
|
|
140
|
+
// in rules_ts_async.go. `any` / `unknown` / `never` are intentionally
|
|
141
|
+
// NOT flagged because they propagate from generic helpers; an Error
|
|
142
|
+
// instance fed through such a helper would otherwise produce noise.
|
|
143
|
+
// Union and intersection types recurse: a constituent that is primitive
|
|
144
|
+
// is enough to fire, matching the throw-side baseline.
|
|
145
|
+
func preferPromiseRejectErrorsIsNonError(checker *shimchecker.Checker, t *shimchecker.Type) bool {
|
|
146
|
+
if checker == nil || t == nil {
|
|
147
|
+
return false
|
|
148
|
+
}
|
|
149
|
+
flags := t.Flags()
|
|
150
|
+
if flags&(shimchecker.TypeFlagsAny|shimchecker.TypeFlagsUnknown|shimchecker.TypeFlagsNever) != 0 {
|
|
151
|
+
return false
|
|
152
|
+
}
|
|
153
|
+
if flags&(shimchecker.TypeFlagsUnion|shimchecker.TypeFlagsIntersection) != 0 {
|
|
154
|
+
for _, part := range t.Types() {
|
|
155
|
+
if part == nil {
|
|
156
|
+
continue
|
|
157
|
+
}
|
|
158
|
+
if preferPromiseRejectErrorsIsNonError(checker, part) {
|
|
159
|
+
return true
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return false
|
|
163
|
+
}
|
|
164
|
+
const primitiveMask = shimchecker.TypeFlagsStringLike |
|
|
165
|
+
shimchecker.TypeFlagsNumberLike |
|
|
166
|
+
shimchecker.TypeFlagsBigIntLike |
|
|
167
|
+
shimchecker.TypeFlagsBooleanLike |
|
|
168
|
+
shimchecker.TypeFlagsVoid |
|
|
169
|
+
shimchecker.TypeFlagsUndefined |
|
|
170
|
+
shimchecker.TypeFlagsNull
|
|
171
|
+
return flags&primitiveMask != 0
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
func init() {
|
|
175
|
+
Register(preferPromiseRejectErrors{})
|
|
176
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// preferReadonly reports private class fields that are initialized at
|
|
2
|
+
// the declaration site (so the constructor has nothing left to assign)
|
|
3
|
+
// and could safely carry the `readonly` modifier. Locking the field as
|
|
4
|
+
// readonly catches accidental reassignments and signals the field's
|
|
5
|
+
// intent to readers without changing runtime behavior.
|
|
6
|
+
//
|
|
7
|
+
// AST-only baseline. Without a full body walk the rule cannot prove that
|
|
8
|
+
// no other method writes to the field, so the conservative trigger is:
|
|
9
|
+
//
|
|
10
|
+
// - the member is a PropertyDeclaration sitting in a class body,
|
|
11
|
+
// - it carries `private` or uses the `#name` private-hash form,
|
|
12
|
+
// - it does not already carry `readonly`,
|
|
13
|
+
// - it has a value initializer at declaration time.
|
|
14
|
+
//
|
|
15
|
+
// A property initialized at declaration time gets its value before the
|
|
16
|
+
// constructor runs, and a field that is also reassigned elsewhere
|
|
17
|
+
// usually does not bother to initialize at the declaration site. The
|
|
18
|
+
// pattern is the noisy upstream subset of the rule that is safe to
|
|
19
|
+
// flag without scope analysis.
|
|
20
|
+
// https://typescript-eslint.io/rules/prefer-readonly/
|
|
21
|
+
package linthost
|
|
22
|
+
|
|
23
|
+
import (
|
|
24
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
type preferReadonly struct{}
|
|
28
|
+
|
|
29
|
+
func (preferReadonly) Name() string { return "typescript/prefer-readonly" }
|
|
30
|
+
func (preferReadonly) Visits() []shimast.Kind {
|
|
31
|
+
return []shimast.Kind{shimast.KindPropertyDeclaration}
|
|
32
|
+
}
|
|
33
|
+
func (preferReadonly) Check(ctx *Context, node *shimast.Node) {
|
|
34
|
+
// Skip non-class-scoped properties; PropertyDeclaration also appears
|
|
35
|
+
// inside object literals in some grammars, but the readonly modifier
|
|
36
|
+
// is a class-only concern.
|
|
37
|
+
parent := node.Parent
|
|
38
|
+
if parent == nil ||
|
|
39
|
+
(parent.Kind != shimast.KindClassDeclaration && parent.Kind != shimast.KindClassExpression) {
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
if hasModifier(node, shimast.KindReadonlyKeyword) {
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
if !preferReadonlyIsPrivate(node) {
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
decl := node.AsPropertyDeclaration()
|
|
49
|
+
if decl == nil || decl.Initializer == nil {
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
// Static fields are still candidates — `private static readonly` is
|
|
53
|
+
// the canonical form for class-scoped constants.
|
|
54
|
+
ctx.Report(node, "Private field is only initialized at declaration time — mark it `readonly`.")
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// preferReadonlyIsPrivate reports whether the property is private either
|
|
58
|
+
// through the `private` modifier or through the `#name` private-hash
|
|
59
|
+
// identifier form. Both make the field inaccessible from outside the
|
|
60
|
+
// class, so `readonly` is a safe local refinement.
|
|
61
|
+
func preferReadonlyIsPrivate(node *shimast.Node) bool {
|
|
62
|
+
if hasModifier(node, shimast.KindPrivateKeyword) {
|
|
63
|
+
return true
|
|
64
|
+
}
|
|
65
|
+
if name := node.Name(); name != nil && name.Kind == shimast.KindPrivateIdentifier {
|
|
66
|
+
return true
|
|
67
|
+
}
|
|
68
|
+
return false
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
func init() {
|
|
72
|
+
Register(preferReadonly{})
|
|
73
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// typescript/prefer-reduce-type-parameter: when `arr.reduce(cb, init)`
|
|
2
|
+
// is called with an `as`-asserted initial value, fix the accumulator
|
|
3
|
+
// type at the call site via `arr.reduce<T>(cb, init)` instead. The
|
|
4
|
+
// type-parameter form binds the accumulator before the callback infers
|
|
5
|
+
// its parameter types from the seed, so the callback sees the intended
|
|
6
|
+
// type instead of the seed's widened literal shape. typescript-eslint:
|
|
7
|
+
// https://typescript-eslint.io/rules/prefer-reduce-type-parameter/
|
|
8
|
+
//
|
|
9
|
+
// Type-aware. Without a Checker the rule cannot prove the receiver of
|
|
10
|
+
// `.reduce` is an array or tuple — user types named `reduce` are
|
|
11
|
+
// common (`Map#reduce`, custom accumulators, etc.) and assertion-on-
|
|
12
|
+
// initial-value is occasionally idiomatic there. The receiver must be
|
|
13
|
+
// a provable array or tuple; generics, `any`, `unknown`, and `never`
|
|
14
|
+
// pass through to keep generic helpers quiet.
|
|
15
|
+
package linthost
|
|
16
|
+
|
|
17
|
+
import (
|
|
18
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
19
|
+
shimchecker "github.com/microsoft/typescript-go/shim/checker"
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
type preferReduceTypeParameter struct{}
|
|
23
|
+
|
|
24
|
+
func (preferReduceTypeParameter) Name() string {
|
|
25
|
+
return "typescript/prefer-reduce-type-parameter"
|
|
26
|
+
}
|
|
27
|
+
func (preferReduceTypeParameter) NeedsTypeChecker() bool {
|
|
28
|
+
return true
|
|
29
|
+
}
|
|
30
|
+
func (preferReduceTypeParameter) Visits() []shimast.Kind {
|
|
31
|
+
return []shimast.Kind{shimast.KindCallExpression}
|
|
32
|
+
}
|
|
33
|
+
func (preferReduceTypeParameter) Check(ctx *Context, node *shimast.Node) {
|
|
34
|
+
if ctx.Checker == nil {
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
call := node.AsCallExpression()
|
|
38
|
+
if call == nil || call.Expression == nil {
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
// `arr.reduce<T>(...)` already pins the accumulator at the call
|
|
42
|
+
// site — the rule has nothing left to suggest.
|
|
43
|
+
if call.TypeArguments != nil && len(call.TypeArguments.Nodes) > 0 {
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
// The call must be `<receiver>.reduce(callback, initial)` — the
|
|
47
|
+
// two-argument form whose seed is the accumulator. The single-
|
|
48
|
+
// argument `arr.reduce(cb)` shape has no seed to assert against.
|
|
49
|
+
if call.Arguments == nil || len(call.Arguments.Nodes) != 2 {
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
receiver, method, ok := promisePropertyAccessParts(call.Expression)
|
|
53
|
+
if !ok || method != "reduce" {
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
initial := stripParens(call.Arguments.Nodes[1])
|
|
57
|
+
if initial == nil {
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
// The initial value must carry an explicit type assertion that the
|
|
61
|
+
// rule can hoist into the call's type parameter list. Both the
|
|
62
|
+
// canonical `init as T` form and the legacy `<T>init` form qualify.
|
|
63
|
+
if initial.Kind != shimast.KindAsExpression && initial.Kind != shimast.KindTypeAssertionExpression {
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
if receiver == nil {
|
|
67
|
+
return
|
|
68
|
+
}
|
|
69
|
+
t := ctx.Checker.GetTypeAtLocation(receiver)
|
|
70
|
+
if t == nil {
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
if !preferReduceIsArrayOrTuple(ctx.Checker, t) {
|
|
74
|
+
return
|
|
75
|
+
}
|
|
76
|
+
ctx.Report(initial, preferReduceMessage)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const preferReduceMessage = "Pass the accumulator type to `reduce` as a type parameter — `arr.reduce<T>(cb, init)` — instead of asserting on the initial value."
|
|
80
|
+
|
|
81
|
+
// preferReduceIsArrayOrTuple reports whether t is provably an array or
|
|
82
|
+
// tuple. Mirrors `preferIncludesIsArrayOrString` but excludes strings
|
|
83
|
+
// (which have no `.reduce`). Generics, `any`, `unknown`, and `never`
|
|
84
|
+
// intentionally fail closed so the rule does not blow up on generic
|
|
85
|
+
// helpers whose receiver type leaks downward.
|
|
86
|
+
func preferReduceIsArrayOrTuple(checker *shimchecker.Checker, t *shimchecker.Type) bool {
|
|
87
|
+
if checker == nil || t == nil {
|
|
88
|
+
return false
|
|
89
|
+
}
|
|
90
|
+
flags := t.Flags()
|
|
91
|
+
if flags&(shimchecker.TypeFlagsAny|shimchecker.TypeFlagsUnknown|shimchecker.TypeFlagsNever) != 0 {
|
|
92
|
+
return false
|
|
93
|
+
}
|
|
94
|
+
if flags&(shimchecker.TypeFlagsUnion|shimchecker.TypeFlagsIntersection) != 0 {
|
|
95
|
+
for _, part := range t.Types() {
|
|
96
|
+
if part == nil {
|
|
97
|
+
continue
|
|
98
|
+
}
|
|
99
|
+
if !preferReduceIsArrayOrTuple(checker, part) {
|
|
100
|
+
return false
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return true
|
|
104
|
+
}
|
|
105
|
+
if shimchecker.Checker_isArrayType(checker, t) {
|
|
106
|
+
return true
|
|
107
|
+
}
|
|
108
|
+
if shimchecker.IsTupleType(t) {
|
|
109
|
+
return true
|
|
110
|
+
}
|
|
111
|
+
return false
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
func init() {
|
|
115
|
+
Register(preferReduceTypeParameter{})
|
|
116
|
+
}
|