@ttsc/lint 0.13.0 → 0.14.0-dev.20260528
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +948 -69
- package/lib/defaultFormat.d.ts +9 -6
- package/lib/defaultFormat.js +9 -6
- package/lib/defaultFormat.js.map +1 -1
- package/lib/index.d.ts +46 -0
- package/lib/index.js +60 -37
- package/lib/index.js.map +1 -1
- package/lib/structures/ITtscLintConfig.d.ts +12 -6
- package/lib/structures/{ITtscLintFormatConfig.d.ts → ITtscLintFormat.d.ts} +2 -2
- package/lib/structures/{TtscLintRuleMap.js → ITtscLintFormat.js} +1 -1
- package/lib/structures/ITtscLintFormat.js.map +1 -0
- package/lib/structures/TtscLintRuleSetting.d.ts +49 -0
- package/lib/structures/{TtscLintRuleOptions.js → TtscLintRuleSetting.js} +1 -1
- package/lib/structures/TtscLintRuleSetting.js.map +1 -0
- package/lib/structures/index.d.ts +3 -4
- package/lib/structures/index.js +3 -4
- package/lib/structures/index.js.map +1 -1
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.d.ts +104 -0
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js +14 -0
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintBoundariesRules.d.ts +79 -0
- package/lib/structures/rules/ITtscLintBoundariesRules.js +3 -0
- package/lib/structures/rules/ITtscLintBoundariesRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintContributorRules.d.ts +17 -0
- package/lib/structures/rules/ITtscLintContributorRules.js +3 -0
- package/lib/structures/rules/ITtscLintContributorRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintCoreRules.d.ts +1257 -0
- package/lib/structures/{ITtscLintFormatConfig.js → rules/ITtscLintCoreRules.js} +1 -1
- package/lib/structures/rules/ITtscLintCoreRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintCypressRuleOptions.d.ts +17 -0
- package/lib/structures/rules/ITtscLintCypressRuleOptions.js +10 -0
- package/lib/structures/rules/ITtscLintCypressRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintCypressRules.d.ts +129 -0
- package/lib/structures/rules/ITtscLintCypressRules.js +3 -0
- package/lib/structures/rules/ITtscLintCypressRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintFunctionalRuleOptions.d.ts +157 -0
- package/lib/structures/rules/ITtscLintFunctionalRuleOptions.js +13 -0
- package/lib/structures/rules/ITtscLintFunctionalRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintFunctionalRules.d.ts +167 -0
- package/lib/structures/rules/ITtscLintFunctionalRules.js +3 -0
- package/lib/structures/rules/ITtscLintFunctionalRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintJestRules.d.ts +201 -0
- package/lib/structures/rules/ITtscLintJestRules.js +3 -0
- package/lib/structures/rules/ITtscLintJestRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintJsdocRules.d.ts +140 -0
- package/lib/structures/rules/ITtscLintJsdocRules.js +3 -0
- package/lib/structures/rules/ITtscLintJsdocRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintJsxA11yRules.d.ts +302 -0
- package/lib/structures/rules/ITtscLintJsxA11yRules.js +3 -0
- package/lib/structures/rules/ITtscLintJsxA11yRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintNextjsRules.d.ts +185 -0
- package/lib/structures/rules/ITtscLintNextjsRules.js +3 -0
- package/lib/structures/rules/ITtscLintNextjsRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintPlaywrightRules.d.ts +330 -0
- package/lib/structures/rules/ITtscLintPlaywrightRules.js +3 -0
- package/lib/structures/rules/ITtscLintPlaywrightRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintPromiseRules.d.ts +188 -0
- package/lib/structures/rules/ITtscLintPromiseRules.js +3 -0
- package/lib/structures/rules/ITtscLintPromiseRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintReactPerfRuleOptions.d.ts +18 -0
- package/lib/structures/rules/ITtscLintReactPerfRuleOptions.js +8 -0
- package/lib/structures/rules/ITtscLintReactPerfRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintReactPerfRules.d.ts +51 -0
- package/lib/structures/rules/ITtscLintReactPerfRules.js +3 -0
- package/lib/structures/rules/ITtscLintReactPerfRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintReactRuleOptions.d.ts +39 -0
- package/lib/structures/rules/ITtscLintReactRuleOptions.js +12 -0
- package/lib/structures/rules/ITtscLintReactRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintReactRules.d.ts +289 -0
- package/lib/structures/rules/ITtscLintReactRules.js +3 -0
- package/lib/structures/rules/ITtscLintReactRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintRegexpRules.d.ts +190 -0
- package/lib/structures/rules/ITtscLintRegexpRules.js +3 -0
- package/lib/structures/rules/ITtscLintRegexpRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintRuleOptionsMap.d.ts +66 -0
- package/lib/structures/rules/ITtscLintRuleOptionsMap.js +3 -0
- package/lib/structures/rules/ITtscLintRuleOptionsMap.js.map +1 -0
- package/lib/structures/rules/ITtscLintRules.d.ts +55 -0
- package/lib/structures/{TtscLintRule.js → rules/ITtscLintRules.js} +1 -1
- package/lib/structures/rules/ITtscLintRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintSecurityRules.d.ts +148 -0
- package/lib/structures/rules/ITtscLintSecurityRules.js +3 -0
- package/lib/structures/rules/ITtscLintSecurityRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintSolidRules.d.ts +181 -0
- package/lib/structures/rules/ITtscLintSolidRules.js +3 -0
- package/lib/structures/rules/ITtscLintSolidRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintStorybookRuleOptions.d.ts +21 -0
- package/lib/structures/rules/ITtscLintStorybookRuleOptions.js +9 -0
- package/lib/structures/rules/ITtscLintStorybookRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintStorybookRules.d.ts +174 -0
- package/lib/structures/rules/ITtscLintStorybookRules.js +3 -0
- package/lib/structures/rules/ITtscLintStorybookRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintTanstackQueryRules.d.ts +94 -0
- package/lib/structures/rules/ITtscLintTanstackQueryRules.js +3 -0
- package/lib/structures/rules/ITtscLintTanstackQueryRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.d.ts +22 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.js +10 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRules.d.ts +310 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRules.js +3 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintTypeScriptRules.d.ts +1132 -0
- package/lib/structures/rules/ITtscLintTypeScriptRules.js +3 -0
- package/lib/structures/rules/ITtscLintTypeScriptRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintUnicornRules.d.ts +997 -0
- package/lib/structures/rules/ITtscLintUnicornRules.js +3 -0
- package/lib/structures/rules/ITtscLintUnicornRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintVitestRules.d.ts +141 -0
- package/lib/structures/rules/ITtscLintVitestRules.js +3 -0
- package/lib/structures/rules/ITtscLintVitestRules.js.map +1 -0
- package/lib/structures/rules/index.d.ts +31 -0
- package/lib/structures/rules/index.js +48 -0
- package/lib/structures/rules/index.js.map +1 -0
- package/linthost/ast_helpers.go +30 -5
- package/linthost/compile.go +33 -2
- package/linthost/config.go +48 -17
- package/linthost/config_format.go +9 -9
- package/linthost/directives.go +67 -25
- package/linthost/dispatch.go +14 -3
- package/linthost/engine.go +160 -40
- package/linthost/fix.go +2 -2
- package/linthost/flags_gen.go +17 -15
- package/linthost/host.go +40 -3
- package/linthost/lsp.go +747 -0
- package/linthost/print_dispatch.go +2 -2
- package/linthost/print_nodes_function.go +2 -2
- package/linthost/print_nodes_object.go +1 -1
- package/linthost/rule_names.go +14 -0
- package/linthost/rules_arrays.go +2 -2
- package/linthost/rules_boundaries.go +532 -0
- package/linthost/rules_camelcase.go +133 -0
- package/linthost/rules_complexity.go +94 -0
- package/linthost/rules_consistent_return.go +130 -0
- package/linthost/rules_console.go +1 -1
- package/linthost/rules_core_extra.go +739 -0
- package/linthost/rules_curly.go +70 -0
- package/linthost/rules_cypress.go +608 -0
- package/linthost/rules_debugger.go +2 -2
- package/linthost/rules_default_case.go +39 -0
- package/linthost/rules_default_case_last.go +46 -0
- package/linthost/rules_dupes.go +3 -3
- package/linthost/rules_empty.go +3 -3
- package/linthost/rules_escape.go +44 -24
- package/linthost/rules_eval.go +2 -2
- package/linthost/rules_finally.go +2 -2
- package/linthost/rules_format_jsdoc.go +1 -1
- package/linthost/rules_format_print_width.go +9 -9
- package/linthost/rules_format_quotes.go +1 -1
- package/linthost/rules_format_semi.go +1 -1
- package/linthost/rules_format_sort_imports.go +1 -1
- package/linthost/rules_format_trailing_comma.go +1 -1
- package/linthost/rules_functional.go +967 -0
- package/linthost/rules_gap.go +24 -45
- package/linthost/rules_grouped_accessor_pairs.go +87 -0
- package/linthost/rules_guard_for_in.go +198 -0
- package/linthost/rules_id_length.go +77 -0
- package/linthost/rules_imports.go +70 -2
- package/linthost/rules_init_declarations.go +53 -0
- package/linthost/rules_jest.go +618 -0
- package/linthost/rules_jsdoc.go +502 -0
- package/linthost/rules_jsx_a11y.go +1264 -0
- package/linthost/rules_logic.go +12 -12
- package/linthost/rules_loops.go +1 -1
- package/linthost/rules_max_classes_per_file.go +58 -0
- package/linthost/rules_max_depth.go +83 -0
- package/linthost/rules_max_lines.go +101 -0
- package/linthost/rules_max_lines_per_function.go +57 -0
- package/linthost/rules_max_nested_callbacks.go +61 -0
- package/linthost/rules_max_params.go +49 -0
- package/linthost/rules_max_statements.go +59 -0
- package/linthost/rules_misc.go +1 -1
- package/linthost/rules_nextjs.go +697 -0
- package/linthost/rules_no_else_return.go +75 -0
- package/linthost/rules_no_empty_named_blocks.go +91 -0
- package/linthost/rules_no_extend_native.go +51 -0
- package/linthost/rules_no_import_assign.go +140 -0
- package/linthost/rules_no_invalid_this.go +52 -0
- package/linthost/rules_no_loop_func.go +85 -0
- package/linthost/rules_no_magic_numbers.go +123 -0
- package/linthost/rules_no_mixed_operators.go +80 -0
- package/linthost/rules_no_param_reassign.go +98 -0
- package/linthost/rules_no_redeclare.go +270 -0
- package/linthost/rules_no_restricted_imports.go +105 -0
- package/linthost/rules_no_restricted_syntax.go +49 -0
- package/linthost/rules_no_shadow.go +147 -0
- package/linthost/rules_no_unreachable.go +77 -0
- package/linthost/rules_no_useless_assignment.go +120 -0
- package/linthost/rules_no_useless_constructor.go +245 -0
- package/linthost/rules_no_useless_return.go +51 -0
- package/linthost/rules_params.go +1 -1
- package/linthost/rules_playwright.go +788 -0
- package/linthost/rules_prefer_arrow_callback.go +124 -0
- package/linthost/rules_prefer_destructuring.go +98 -0
- package/linthost/rules_prefer_named_capture_group.go +129 -0
- package/linthost/rules_prefer_rest_params.go +94 -0
- package/linthost/rules_problems.go +41 -30
- package/linthost/rules_promise.go +1128 -73
- package/linthost/rules_protos.go +2 -2
- package/linthost/rules_react.go +773 -0
- package/linthost/rules_react_extras.go +227 -0
- package/linthost/rules_react_hooks.go +848 -0
- package/linthost/rules_react_perf.go +293 -0
- package/linthost/rules_react_refresh.go +583 -0
- package/linthost/rules_regexp.go +410 -0
- package/linthost/rules_security.go +830 -0
- package/linthost/rules_self.go +2 -2
- package/linthost/rules_solid.go +1073 -0
- package/linthost/rules_sort_imports.go +69 -0
- package/linthost/rules_sort_keys.go +134 -0
- package/linthost/rules_storybook.go +1176 -0
- package/linthost/rules_strings.go +4 -4
- package/linthost/rules_suggestions.go +38 -38
- package/linthost/rules_tanstack_query.go +844 -0
- package/linthost/rules_testing_library.go +1204 -0
- package/linthost/rules_throw.go +1 -1
- package/linthost/rules_ts.go +19 -19
- package/linthost/rules_ts_async.go +399 -0
- package/linthost/rules_ts_class_literal_property_style.go +115 -0
- package/linthost/rules_ts_consistent_type_exports.go +256 -0
- package/linthost/rules_ts_explicit_function_return_type.go +67 -0
- package/linthost/rules_ts_extra.go +155 -36
- package/linthost/rules_ts_no_base_to_string.go +218 -0
- package/linthost/rules_ts_no_confusing_void.go +72 -0
- package/linthost/rules_ts_no_deprecated.go +195 -0
- package/linthost/rules_ts_no_for_in_array.go +84 -0
- package/linthost/rules_ts_no_magic_numbers.go +124 -0
- package/linthost/rules_ts_no_meaningless_void_operator.go +84 -0
- package/linthost/rules_ts_no_misused_spread.go +104 -0
- package/linthost/rules_ts_no_redundant_type_constituents.go +113 -0
- package/linthost/rules_ts_no_restricted_types.go +62 -0
- package/linthost/rules_ts_no_unnecessary_boolean_literal_compare.go +129 -0
- package/linthost/rules_ts_no_unnecessary_condition.go +250 -0
- package/linthost/rules_ts_no_unnecessary_qualifier.go +118 -0
- package/linthost/rules_ts_no_unnecessary_template_expression.go +178 -0
- package/linthost/rules_ts_no_unnecessary_type_arguments.go +234 -0
- package/linthost/rules_ts_no_unnecessary_type_assertion.go +157 -0
- package/linthost/rules_ts_no_unsafe_argument.go +82 -0
- package/linthost/rules_ts_no_unsafe_assignment.go +102 -0
- package/linthost/rules_ts_no_unsafe_call.go +82 -0
- package/linthost/rules_ts_no_unsafe_enum_comparison.go +235 -0
- package/linthost/rules_ts_no_unsafe_member_access.go +58 -0
- package/linthost/rules_ts_no_unsafe_return.go +126 -0
- package/linthost/rules_ts_no_unsafe_unary_minus.go +81 -0
- package/linthost/rules_ts_no_useless_constructor.go +52 -0
- package/linthost/rules_ts_non_nullable_type_assertion_style.go +108 -0
- package/linthost/rules_ts_parameter_properties.go +38 -0
- package/linthost/rules_ts_prefer_find.go +178 -0
- package/linthost/rules_ts_prefer_includes.go +255 -0
- package/linthost/rules_ts_prefer_nullish_coalescing.go +104 -0
- package/linthost/rules_ts_prefer_optional_chain.go +228 -0
- package/linthost/rules_ts_prefer_promise_reject_errors.go +176 -0
- package/linthost/rules_ts_prefer_readonly.go +73 -0
- package/linthost/rules_ts_prefer_reduce_type_parameter.go +116 -0
- package/linthost/rules_ts_prefer_regexp_exec.go +122 -0
- package/linthost/rules_ts_prefer_return_this_type.go +135 -0
- package/linthost/rules_ts_prefer_string_starts_ends_with.go +360 -0
- package/linthost/rules_ts_promise_function_async.go +77 -0
- package/linthost/rules_ts_related_getter_setter_pairs.go +113 -0
- package/linthost/rules_ts_require_array_sort_compare.go +96 -0
- package/linthost/rules_ts_restrict_plus_operands.go +127 -0
- package/linthost/rules_ts_restrict_template_expressions.go +95 -0
- package/linthost/rules_ts_simple.go +387 -0
- package/linthost/rules_ts_sort_type_constituents.go +144 -0
- package/linthost/rules_ts_strict_boolean_expressions.go +157 -0
- package/linthost/rules_ts_switch_exhaustiveness_check.go +147 -0
- package/linthost/rules_ts_unbound_method.go +126 -0
- package/linthost/rules_tsdoc.go +136 -0
- package/linthost/rules_unicorn_better_regex.go +27 -0
- package/linthost/rules_unicorn_catch_error_name.go +46 -0
- package/linthost/rules_unicorn_consistent_assert.go +47 -0
- package/linthost/rules_unicorn_consistent_date_clone.go +54 -0
- package/linthost/rules_unicorn_consistent_destructuring.go +25 -0
- package/linthost/rules_unicorn_consistent_empty_array_spread.go +62 -0
- package/linthost/rules_unicorn_consistent_existence_index_check.go +80 -0
- package/linthost/rules_unicorn_consistent_function_scoping.go +25 -0
- package/linthost/rules_unicorn_consistent_template_literal_escape.go +25 -0
- package/linthost/rules_unicorn_custom_error_definition.go +138 -0
- package/linthost/rules_unicorn_empty_brace_spaces.go +73 -0
- package/linthost/rules_unicorn_error_message.go +64 -0
- package/linthost/rules_unicorn_escape_case.go +51 -0
- package/linthost/rules_unicorn_expiring_todo_comments.go +78 -0
- package/linthost/rules_unicorn_explicit_length_check.go +88 -0
- package/linthost/rules_unicorn_filename_case.go +29 -0
- package/linthost/rules_unicorn_import_style.go +28 -0
- package/linthost/rules_unicorn_isolated_functions.go +29 -0
- package/linthost/rules_unicorn_new_for_builtins.go +87 -0
- package/linthost/rules_unicorn_no_abusive_eslint_disable.go +63 -0
- package/linthost/rules_unicorn_no_accessor_recursion.go +115 -0
- package/linthost/rules_unicorn_no_anonymous_default_export.go +74 -0
- package/linthost/rules_unicorn_no_array_callback_reference.go +65 -0
- package/linthost/rules_unicorn_no_array_for_each.go +40 -0
- package/linthost/rules_unicorn_no_array_method_this_argument.go +61 -0
- package/linthost/rules_unicorn_no_array_reduce.go +41 -0
- package/linthost/rules_unicorn_no_array_reverse.go +44 -0
- package/linthost/rules_unicorn_no_array_sort.go +43 -0
- package/linthost/rules_unicorn_no_await_expression_member.go +40 -0
- package/linthost/rules_unicorn_no_await_in_promise_methods.go +69 -0
- package/linthost/rules_unicorn_no_console_spaces.go +61 -0
- package/linthost/rules_unicorn_no_document_cookie.go +41 -0
- package/linthost/rules_unicorn_no_empty_file.go +44 -0
- package/linthost/rules_unicorn_no_for_loop.go +102 -0
- package/linthost/rules_unicorn_no_hex_escape.go +42 -0
- package/linthost/rules_unicorn_no_immediate_mutation.go +90 -0
- package/linthost/rules_unicorn_no_instanceof_builtins.go +66 -0
- package/linthost/rules_unicorn_no_invalid_fetch_options.go +79 -0
- package/linthost/rules_unicorn_no_invalid_remove_event_listener.go +51 -0
- package/linthost/rules_unicorn_no_keyword_prefix.go +101 -0
- package/linthost/rules_unicorn_no_lonely_if.go +44 -0
- package/linthost/rules_unicorn_no_magic_array_flat_depth.go +51 -0
- package/linthost/rules_unicorn_no_named_default.go +54 -0
- package/linthost/rules_unicorn_no_negated_condition.go +85 -0
- package/linthost/rules_unicorn_no_negation_in_equality_check.go +50 -0
- package/linthost/rules_unicorn_no_nested_ternary.go +43 -0
- package/linthost/rules_unicorn_no_new_array.go +30 -0
- package/linthost/rules_unicorn_no_new_buffer.go +31 -0
- package/linthost/rules_unicorn_no_null.go +24 -0
- package/linthost/rules_unicorn_no_object_as_default_parameter.go +48 -0
- package/linthost/rules_unicorn_no_process_exit.go +43 -0
- package/linthost/rules_unicorn_no_single_promise_in_promise_methods.go +59 -0
- package/linthost/rules_unicorn_no_static_only_class.go +56 -0
- package/linthost/rules_unicorn_no_thenable.go +74 -0
- package/linthost/rules_unicorn_no_this_assignment.go +35 -0
- package/linthost/rules_unicorn_no_typeof_undefined.go +58 -0
- package/linthost/rules_unicorn_no_unnecessary_array_flat_depth.go +49 -0
- package/linthost/rules_unicorn_no_unnecessary_array_splice_count.go +70 -0
- package/linthost/rules_unicorn_no_unnecessary_await.go +51 -0
- package/linthost/rules_unicorn_no_unnecessary_polyfills.go +32 -0
- package/linthost/rules_unicorn_no_unnecessary_slice_end.go +48 -0
- package/linthost/rules_unicorn_no_unreadable_array_destructuring.go +115 -0
- package/linthost/rules_unicorn_no_unreadable_iife.go +50 -0
- package/linthost/rules_unicorn_no_unused_properties.go +30 -0
- package/linthost/rules_unicorn_no_useless_collection_argument.go +63 -0
- package/linthost/rules_unicorn_no_useless_error_capture_stack_trace.go +46 -0
- package/linthost/rules_unicorn_no_useless_fallback_in_spread.go +81 -0
- package/linthost/rules_unicorn_no_useless_iterator_to_array.go +72 -0
- package/linthost/rules_unicorn_no_useless_length_check.go +144 -0
- package/linthost/rules_unicorn_no_useless_promise_resolve_reject.go +81 -0
- package/linthost/rules_unicorn_no_useless_spread.go +67 -0
- package/linthost/rules_unicorn_no_useless_switch_case.go +55 -0
- package/linthost/rules_unicorn_no_useless_undefined.go +55 -0
- package/linthost/rules_unicorn_no_zero_fractions.go +52 -0
- package/linthost/rules_unicorn_number_literal_case.go +69 -0
- package/linthost/rules_unicorn_numeric_separators_style.go +75 -0
- package/linthost/rules_unicorn_prefer_add_event_listener.go +66 -0
- package/linthost/rules_unicorn_prefer_array_find.go +51 -0
- package/linthost/rules_unicorn_prefer_array_flat.go +52 -0
- package/linthost/rules_unicorn_prefer_array_flat_map.go +63 -0
- package/linthost/rules_unicorn_prefer_array_index_of.go +147 -0
- package/linthost/rules_unicorn_prefer_array_some.go +67 -0
- package/linthost/rules_unicorn_prefer_at.go +77 -0
- package/linthost/rules_unicorn_prefer_bigint_literals.go +77 -0
- package/linthost/rules_unicorn_prefer_blob_reading_methods.go +44 -0
- package/linthost/rules_unicorn_prefer_class_fields.go +93 -0
- package/linthost/rules_unicorn_prefer_classlist_toggle.go +120 -0
- package/linthost/rules_unicorn_prefer_code_point.go +49 -0
- package/linthost/rules_unicorn_prefer_date_now.go +78 -0
- package/linthost/rules_unicorn_prefer_default_parameters.go +144 -0
- package/linthost/rules_unicorn_prefer_dom_node_append.go +40 -0
- package/linthost/rules_unicorn_prefer_dom_node_dataset.go +55 -0
- package/linthost/rules_unicorn_prefer_dom_node_remove.go +41 -0
- package/linthost/rules_unicorn_prefer_dom_node_text_content.go +37 -0
- package/linthost/rules_unicorn_prefer_event_target.go +36 -0
- package/linthost/rules_unicorn_prefer_export_from.go +129 -0
- package/linthost/rules_unicorn_prefer_global_this.go +127 -0
- package/linthost/rules_unicorn_prefer_import_meta_properties.go +66 -0
- package/linthost/rules_unicorn_prefer_includes.go +149 -0
- package/linthost/rules_unicorn_prefer_json_parse_buffer.go +65 -0
- package/linthost/rules_unicorn_prefer_keyboard_event_key.go +38 -0
- package/linthost/rules_unicorn_prefer_logical_operator_over_ternary.go +48 -0
- package/linthost/rules_unicorn_prefer_math_min_max.go +60 -0
- package/linthost/rules_unicorn_prefer_math_trunc.go +62 -0
- package/linthost/rules_unicorn_prefer_modern_dom_apis.go +47 -0
- package/linthost/rules_unicorn_prefer_modern_math_apis.go +70 -0
- package/linthost/rules_unicorn_prefer_module.go +50 -0
- package/linthost/rules_unicorn_prefer_native_coercion_functions.go +114 -0
- package/linthost/rules_unicorn_prefer_negative_index.go +74 -0
- package/linthost/rules_unicorn_prefer_node_protocol.go +122 -0
- package/linthost/rules_unicorn_prefer_number_properties.go +88 -0
- package/linthost/rules_unicorn_prefer_object_from_entries.go +55 -0
- package/linthost/rules_unicorn_prefer_optional_catch_binding.go +62 -0
- package/linthost/rules_unicorn_prefer_prototype_methods.go +54 -0
- package/linthost/rules_unicorn_prefer_query_selector.go +56 -0
- package/linthost/rules_unicorn_prefer_reflect_apply.go +36 -0
- package/linthost/rules_unicorn_prefer_regexp_test_rule.go +80 -0
- package/linthost/rules_unicorn_prefer_response_static_json.go +53 -0
- package/linthost/rules_unicorn_prefer_set_has.go +42 -0
- package/linthost/rules_unicorn_prefer_set_size.go +48 -0
- package/linthost/rules_unicorn_prefer_simple_condition_first.go +34 -0
- package/linthost/rules_unicorn_prefer_single_call.go +96 -0
- package/linthost/rules_unicorn_prefer_spread.go +51 -0
- package/linthost/rules_unicorn_prefer_string_raw.go +43 -0
- package/linthost/rules_unicorn_prefer_string_replace_all.go +95 -0
- package/linthost/rules_unicorn_prefer_string_slice.go +43 -0
- package/linthost/rules_unicorn_prefer_string_starts_ends_with.go +148 -0
- package/linthost/rules_unicorn_prefer_string_trim_start_end.go +48 -0
- package/linthost/rules_unicorn_prefer_structured_clone.go +71 -0
- package/linthost/rules_unicorn_prefer_switch.go +103 -0
- package/linthost/rules_unicorn_prefer_ternary.go +71 -0
- package/linthost/rules_unicorn_prefer_top_level_await.go +72 -0
- package/linthost/rules_unicorn_prefer_type_error.go +127 -0
- package/linthost/rules_unicorn_prevent_abbreviations.go +127 -0
- package/linthost/rules_unicorn_relative_url_style.go +49 -0
- package/linthost/rules_unicorn_require_array_join_separator.go +45 -0
- package/linthost/rules_unicorn_require_module_attributes.go +54 -0
- package/linthost/rules_unicorn_require_module_specifiers.go +55 -0
- package/linthost/rules_unicorn_require_number_to_fixed_digits_argument.go +43 -0
- package/linthost/rules_unicorn_require_post_message_target_origin.go +44 -0
- package/linthost/rules_unicorn_string_content.go +27 -0
- package/linthost/rules_unicorn_switch_case_braces.go +42 -0
- package/linthost/rules_unicorn_switch_case_break_position.go +31 -0
- package/linthost/rules_unicorn_template_indent.go +28 -0
- package/linthost/rules_unicorn_text_encoding_identifier_case.go +72 -0
- package/linthost/rules_unicorn_throw_new_error.go +61 -0
- package/linthost/rules_var.go +10 -4
- package/linthost/rules_vitest.go +568 -0
- package/package.json +3 -3
- package/plugin/main.go +49 -3
- package/rule/astutil/astutil.go +10 -3
- package/rule/rule.go +12 -10
- package/src/defaultFormat.ts +11 -8
- package/src/index.ts +65 -43
- package/src/structures/ITtscLintConfig.ts +12 -6
- package/src/structures/{ITtscLintFormatConfig.ts → ITtscLintFormat.ts} +2 -2
- package/src/structures/TtscLintRuleSetting.ts +55 -0
- package/src/structures/index.ts +3 -4
- package/src/structures/rules/ITtscLintBoundariesRuleOptions.ts +128 -0
- package/src/structures/rules/ITtscLintBoundariesRules.ts +95 -0
- package/src/structures/rules/ITtscLintContributorRules.ts +21 -0
- package/src/structures/rules/ITtscLintCoreRules.ts +1406 -0
- package/src/structures/rules/ITtscLintCypressRuleOptions.ts +18 -0
- package/src/structures/rules/ITtscLintCypressRules.ts +145 -0
- package/src/structures/rules/ITtscLintFunctionalRuleOptions.ts +213 -0
- package/src/structures/rules/ITtscLintFunctionalRules.ts +202 -0
- package/src/structures/rules/ITtscLintJestRules.ts +220 -0
- package/src/structures/rules/ITtscLintJsdocRules.ts +153 -0
- package/src/structures/rules/ITtscLintJsxA11yRules.ts +339 -0
- package/src/structures/rules/ITtscLintNextjsRules.ts +206 -0
- package/src/structures/rules/ITtscLintPlaywrightRules.ts +361 -0
- package/src/structures/rules/ITtscLintPromiseRules.ts +205 -0
- package/src/structures/rules/ITtscLintReactPerfRuleOptions.ts +19 -0
- package/src/structures/rules/ITtscLintReactPerfRules.ts +55 -0
- package/src/structures/rules/ITtscLintReactRuleOptions.ts +43 -0
- package/src/structures/rules/ITtscLintReactRules.ts +321 -0
- package/src/structures/rules/ITtscLintRegexpRules.ts +212 -0
- package/src/structures/rules/ITtscLintRuleOptionsMap.ts +89 -0
- package/src/structures/rules/ITtscLintRules.ts +77 -0
- package/src/structures/rules/ITtscLintSecurityRules.ts +162 -0
- package/src/structures/rules/ITtscLintSolidRules.ts +202 -0
- package/src/structures/rules/ITtscLintStorybookRuleOptions.ts +23 -0
- package/src/structures/rules/ITtscLintStorybookRules.ts +193 -0
- package/src/structures/rules/ITtscLintTanstackQueryRules.ts +102 -0
- package/src/structures/rules/ITtscLintTestingLibraryRuleOptions.ts +24 -0
- package/src/structures/rules/ITtscLintTestingLibraryRules.ts +342 -0
- package/src/structures/rules/ITtscLintTypeScriptRules.ts +1230 -0
- package/src/structures/rules/ITtscLintUnicornRules.ts +1143 -0
- package/src/structures/rules/ITtscLintVitestRules.ts +154 -0
- package/src/structures/rules/index.ts +31 -0
- package/lib/structures/ITtscLintFormatConfig.js.map +0 -1
- package/lib/structures/TtscLintRule.d.ts +0 -17
- package/lib/structures/TtscLintRule.js.map +0 -1
- package/lib/structures/TtscLintRuleMap.d.ts +0 -46
- package/lib/structures/TtscLintRuleMap.js.map +0 -1
- package/lib/structures/TtscLintRuleOptions.d.ts +0 -137
- package/lib/structures/TtscLintRuleOptions.js.map +0 -1
- package/src/structures/TtscLintRule.ts +0 -160
- package/src/structures/TtscLintRuleMap.ts +0 -55
- package/src/structures/TtscLintRuleOptions.ts +0 -151
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
// Additional AST-only `typescript/*` rules from
|
|
2
|
+
// typescript-eslint. Each rule is a small pattern match — no Checker,
|
|
3
|
+
// no scope analysis — and corresponds 1:1 with the upstream rule of
|
|
4
|
+
// the same name.
|
|
5
|
+
//
|
|
6
|
+
// Implemented here:
|
|
7
|
+
// - typescript/no-array-for-each
|
|
8
|
+
// - typescript/no-extraneous-class
|
|
9
|
+
// - typescript/no-invalid-void-type
|
|
10
|
+
package linthost
|
|
11
|
+
|
|
12
|
+
import (
|
|
13
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
// noArrayForEach reports `arr.forEach(...)` calls and suggests
|
|
17
|
+
// `for ... of` instead. The for-of form supports early termination
|
|
18
|
+
// (`break`/`return`) and `await`, while `forEach` swallows both. The
|
|
19
|
+
// rule does not confirm that the receiver is actually an array — the
|
|
20
|
+
// syntactic shape is the signal, matching the upstream rule's behavior.
|
|
21
|
+
// https://typescript-eslint.io/rules/no-array-for-each/
|
|
22
|
+
type noArrayForEach struct{}
|
|
23
|
+
|
|
24
|
+
func (noArrayForEach) Name() string { return "typescript/no-array-for-each" }
|
|
25
|
+
func (noArrayForEach) Visits() []shimast.Kind {
|
|
26
|
+
return []shimast.Kind{shimast.KindCallExpression}
|
|
27
|
+
}
|
|
28
|
+
func (noArrayForEach) Check(ctx *Context, node *shimast.Node) {
|
|
29
|
+
call := node.AsCallExpression()
|
|
30
|
+
if call == nil || call.Expression == nil {
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
_, method, ok := promisePropertyAccessParts(call.Expression)
|
|
34
|
+
if !ok || method != "forEach" {
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
ctx.Report(node, "Prefer `for ... of` over `Array.forEach()` — `forEach` does not support `await` or `break`.")
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// noExtraneousClass reports class declarations that exist purely as a
|
|
41
|
+
// namespace for static members or are entirely empty. A namespace
|
|
42
|
+
// import or a plain function is almost always clearer than `class Util
|
|
43
|
+
// { static foo() { … } }`, and the class adds a layer of indirection
|
|
44
|
+
// without providing any instance behavior.
|
|
45
|
+
// https://typescript-eslint.io/rules/no-extraneous-class/
|
|
46
|
+
//
|
|
47
|
+
// Trigger:
|
|
48
|
+
// - the class has no `extends` heritage,
|
|
49
|
+
// - no constructor with a non-empty body, and
|
|
50
|
+
// - every member is `static` (or the class has no members at all).
|
|
51
|
+
type noExtraneousClass struct{}
|
|
52
|
+
|
|
53
|
+
func (noExtraneousClass) Name() string { return "typescript/no-extraneous-class" }
|
|
54
|
+
func (noExtraneousClass) Visits() []shimast.Kind {
|
|
55
|
+
return []shimast.Kind{shimast.KindClassDeclaration, shimast.KindClassExpression}
|
|
56
|
+
}
|
|
57
|
+
func (noExtraneousClass) Check(ctx *Context, node *shimast.Node) {
|
|
58
|
+
if classExtendsAnother(node) {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
if classImplementsAnInterface(node) {
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
members := classMembers(node)
|
|
65
|
+
if len(members) == 0 {
|
|
66
|
+
ctx.Report(node, "Empty class — prefer a plain function or namespace.")
|
|
67
|
+
return
|
|
68
|
+
}
|
|
69
|
+
hasInstanceMember := false
|
|
70
|
+
hasNonTrivialConstructor := false
|
|
71
|
+
for _, member := range members {
|
|
72
|
+
if member == nil {
|
|
73
|
+
continue
|
|
74
|
+
}
|
|
75
|
+
if member.Kind == shimast.KindConstructor {
|
|
76
|
+
ctor := member.AsConstructorDeclaration()
|
|
77
|
+
if ctor != nil && ctor.Body != nil && len(ctor.Body.Statements()) > 0 {
|
|
78
|
+
hasNonTrivialConstructor = true
|
|
79
|
+
}
|
|
80
|
+
continue
|
|
81
|
+
}
|
|
82
|
+
if !hasModifier(member, shimast.KindStaticKeyword) {
|
|
83
|
+
hasInstanceMember = true
|
|
84
|
+
break
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if !hasInstanceMember && !hasNonTrivialConstructor {
|
|
88
|
+
ctx.Report(node, "Class only declares static members — prefer a namespace or top-level functions.")
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// classImplementsAnInterface reports whether the class has an
|
|
93
|
+
// `implements …` heritage clause. Classes that implement an interface
|
|
94
|
+
// are intentionally polymorphic at runtime, so noExtraneousClass
|
|
95
|
+
// should not fire on them.
|
|
96
|
+
func classImplementsAnInterface(class *shimast.Node) bool {
|
|
97
|
+
var clauses []*shimast.Node
|
|
98
|
+
switch class.Kind {
|
|
99
|
+
case shimast.KindClassDeclaration:
|
|
100
|
+
decl := class.AsClassDeclaration()
|
|
101
|
+
if decl == nil || decl.HeritageClauses == nil {
|
|
102
|
+
return false
|
|
103
|
+
}
|
|
104
|
+
clauses = decl.HeritageClauses.Nodes
|
|
105
|
+
case shimast.KindClassExpression:
|
|
106
|
+
expr := class.AsClassExpression()
|
|
107
|
+
if expr == nil || expr.HeritageClauses == nil {
|
|
108
|
+
return false
|
|
109
|
+
}
|
|
110
|
+
clauses = expr.HeritageClauses.Nodes
|
|
111
|
+
default:
|
|
112
|
+
return false
|
|
113
|
+
}
|
|
114
|
+
for _, clause := range clauses {
|
|
115
|
+
if clause == nil {
|
|
116
|
+
continue
|
|
117
|
+
}
|
|
118
|
+
hc := clause.AsHeritageClause()
|
|
119
|
+
if hc == nil || hc.Token != shimast.KindImplementsKeyword {
|
|
120
|
+
continue
|
|
121
|
+
}
|
|
122
|
+
if hc.Types != nil && len(hc.Types.Nodes) > 0 {
|
|
123
|
+
return true
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return false
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// noInvalidVoidType reports a `void` type used as a union constituent
|
|
130
|
+
// or as a generic-type argument. `void` is meaningful only as the sole
|
|
131
|
+
// return type of a function — `void | string` and `Promise<void>` are
|
|
132
|
+
// fine, but `string | void` is almost always a confusion with
|
|
133
|
+
// `undefined`.
|
|
134
|
+
// https://typescript-eslint.io/rules/no-invalid-void-type/
|
|
135
|
+
//
|
|
136
|
+
// Allowed positions:
|
|
137
|
+
// - the return type annotation of a function-like (Function/Method/
|
|
138
|
+
// Arrow/Constructor/CallSignature/MethodSignature/FunctionType);
|
|
139
|
+
// - inside `Promise<void>`, `Generator<void, …, …>`, etc. — these
|
|
140
|
+
// are the established generic exceptions in typescript-eslint.
|
|
141
|
+
type noInvalidVoidType struct{}
|
|
142
|
+
|
|
143
|
+
func (noInvalidVoidType) Name() string { return "typescript/no-invalid-void-type" }
|
|
144
|
+
func (noInvalidVoidType) Visits() []shimast.Kind {
|
|
145
|
+
return []shimast.Kind{shimast.KindVoidKeyword}
|
|
146
|
+
}
|
|
147
|
+
func (noInvalidVoidType) Check(ctx *Context, node *shimast.Node) {
|
|
148
|
+
// The `void` keyword shows up both as a type node and as the unary
|
|
149
|
+
// `void X` expression operator. Filter by parent kind — the
|
|
150
|
+
// expression operator's parent is VoidExpression, not a type position.
|
|
151
|
+
parent := node.Parent
|
|
152
|
+
if parent == nil || parent.Kind == shimast.KindVoidExpression {
|
|
153
|
+
return
|
|
154
|
+
}
|
|
155
|
+
if isValidVoidPosition(node) {
|
|
156
|
+
return
|
|
157
|
+
}
|
|
158
|
+
ctx.Report(node, "`void` is only valid as the return type annotation of a function or as a known generic argument.")
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// isValidVoidPosition reports whether a `void` type node sits in one
|
|
162
|
+
// of the approved positions: a function return type or an
|
|
163
|
+
// allow-listed generic type argument (Promise/Generator/AsyncGenerator/
|
|
164
|
+
// Iterator/AsyncIterator/IterableIterator).
|
|
165
|
+
func isValidVoidPosition(node *shimast.Node) bool {
|
|
166
|
+
parent := node.Parent
|
|
167
|
+
if parent == nil {
|
|
168
|
+
return false
|
|
169
|
+
}
|
|
170
|
+
switch parent.Kind {
|
|
171
|
+
case shimast.KindFunctionDeclaration,
|
|
172
|
+
shimast.KindFunctionExpression,
|
|
173
|
+
shimast.KindArrowFunction,
|
|
174
|
+
shimast.KindMethodDeclaration,
|
|
175
|
+
shimast.KindMethodSignature,
|
|
176
|
+
shimast.KindConstructor,
|
|
177
|
+
shimast.KindGetAccessor,
|
|
178
|
+
shimast.KindSetAccessor,
|
|
179
|
+
shimast.KindCallSignature,
|
|
180
|
+
shimast.KindConstructSignature,
|
|
181
|
+
shimast.KindFunctionType,
|
|
182
|
+
shimast.KindConstructorType,
|
|
183
|
+
shimast.KindIndexSignature:
|
|
184
|
+
return parent.Type() == node
|
|
185
|
+
case shimast.KindTypeReference:
|
|
186
|
+
// `void` as a generic argument — allowed inside the typescript-
|
|
187
|
+
// eslint approved set.
|
|
188
|
+
grand := parent.Parent
|
|
189
|
+
if grand == nil {
|
|
190
|
+
return false
|
|
191
|
+
}
|
|
192
|
+
if grand.Kind == shimast.KindTypeReference {
|
|
193
|
+
ref := grand.AsTypeReferenceNode()
|
|
194
|
+
if ref == nil {
|
|
195
|
+
return false
|
|
196
|
+
}
|
|
197
|
+
name := identifierText(ref.TypeName)
|
|
198
|
+
switch name {
|
|
199
|
+
case "Promise", "Generator", "AsyncGenerator", "Iterator", "AsyncIterator", "IterableIterator", "AsyncIterableIterator":
|
|
200
|
+
return true
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// Walk up: if the parent chain leads directly to an allow-listed
|
|
205
|
+
// generic type reference's typeArguments list, accept.
|
|
206
|
+
for cur := parent; cur != nil; cur = cur.Parent {
|
|
207
|
+
if cur.Kind == shimast.KindTypeReference {
|
|
208
|
+
ref := cur.AsTypeReferenceNode()
|
|
209
|
+
if ref == nil {
|
|
210
|
+
return false
|
|
211
|
+
}
|
|
212
|
+
name := identifierText(ref.TypeName)
|
|
213
|
+
switch name {
|
|
214
|
+
case "Promise", "Generator", "AsyncGenerator", "Iterator", "AsyncIterator", "IterableIterator", "AsyncIterableIterator":
|
|
215
|
+
return true
|
|
216
|
+
}
|
|
217
|
+
return false
|
|
218
|
+
}
|
|
219
|
+
// Stop walking past statement boundaries — `void` in
|
|
220
|
+
// `let x: string | void;` should still fire.
|
|
221
|
+
switch cur.Kind {
|
|
222
|
+
case shimast.KindVariableDeclaration,
|
|
223
|
+
shimast.KindParameter,
|
|
224
|
+
shimast.KindPropertyDeclaration,
|
|
225
|
+
shimast.KindPropertySignature:
|
|
226
|
+
return false
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return false
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// explicitMemberAccessibility requires every class member declaration
|
|
233
|
+
// to carry a `public` / `private` / `protected` modifier. Implicit
|
|
234
|
+
// public is permitted by TypeScript but obscures intent — explicit
|
|
235
|
+
// keywords make the encapsulation contract self-documenting and
|
|
236
|
+
// catch the common bug of "I forgot to make this private."
|
|
237
|
+
// https://typescript-eslint.io/rules/explicit-member-accessibility/
|
|
238
|
+
//
|
|
239
|
+
// Class fields whose name starts with `#` are exempt — the private
|
|
240
|
+
// hash already carries the same meaning. The constructor is exempt;
|
|
241
|
+
// upstream allows omitting accessibility on the constructor itself.
|
|
242
|
+
type explicitMemberAccessibility struct{}
|
|
243
|
+
|
|
244
|
+
func (explicitMemberAccessibility) Name() string {
|
|
245
|
+
return "typescript/explicit-member-accessibility"
|
|
246
|
+
}
|
|
247
|
+
func (explicitMemberAccessibility) Visits() []shimast.Kind {
|
|
248
|
+
return []shimast.Kind{
|
|
249
|
+
shimast.KindMethodDeclaration,
|
|
250
|
+
shimast.KindPropertyDeclaration,
|
|
251
|
+
shimast.KindGetAccessor,
|
|
252
|
+
shimast.KindSetAccessor,
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
func (explicitMemberAccessibility) Check(ctx *Context, node *shimast.Node) {
|
|
256
|
+
// Skip non-class-scoped members.
|
|
257
|
+
parent := node.Parent
|
|
258
|
+
if parent == nil ||
|
|
259
|
+
(parent.Kind != shimast.KindClassDeclaration && parent.Kind != shimast.KindClassExpression) {
|
|
260
|
+
return
|
|
261
|
+
}
|
|
262
|
+
// Skip private hash identifiers.
|
|
263
|
+
if name := node.Name(); name != nil && name.Kind == shimast.KindPrivateIdentifier {
|
|
264
|
+
return
|
|
265
|
+
}
|
|
266
|
+
if classMemberHasAccessibility(node) {
|
|
267
|
+
return
|
|
268
|
+
}
|
|
269
|
+
ctx.Report(node, "Class member is missing an explicit accessibility modifier (`public`, `private`, or `protected`).")
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// classMemberHasAccessibility reports whether the member carries an
|
|
273
|
+
// explicit `public` / `private` / `protected` modifier.
|
|
274
|
+
func classMemberHasAccessibility(node *shimast.Node) bool {
|
|
275
|
+
if node == nil {
|
|
276
|
+
return false
|
|
277
|
+
}
|
|
278
|
+
mods := node.Modifiers()
|
|
279
|
+
if mods == nil {
|
|
280
|
+
return false
|
|
281
|
+
}
|
|
282
|
+
for _, m := range mods.Nodes {
|
|
283
|
+
if m == nil {
|
|
284
|
+
continue
|
|
285
|
+
}
|
|
286
|
+
switch m.Kind {
|
|
287
|
+
case shimast.KindPublicKeyword,
|
|
288
|
+
shimast.KindPrivateKeyword,
|
|
289
|
+
shimast.KindProtectedKeyword:
|
|
290
|
+
return true
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return false
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// consistentGenericConstructors reports the redundant pattern where a
|
|
297
|
+
// variable is annotated with a generic type AND the same generic
|
|
298
|
+
// arguments are repeated on the constructor call:
|
|
299
|
+
//
|
|
300
|
+
// const m: Map<string, number> = new Map<string, number>();
|
|
301
|
+
//
|
|
302
|
+
// One of the two type-argument lists is enough. The upstream default
|
|
303
|
+
// prefers the constructor form; the annotation form is also valid but
|
|
304
|
+
// stating both is noise.
|
|
305
|
+
// https://typescript-eslint.io/rules/consistent-generic-constructors/
|
|
306
|
+
type consistentGenericConstructors struct{}
|
|
307
|
+
|
|
308
|
+
func (consistentGenericConstructors) Name() string {
|
|
309
|
+
return "typescript/consistent-generic-constructors"
|
|
310
|
+
}
|
|
311
|
+
func (consistentGenericConstructors) Visits() []shimast.Kind {
|
|
312
|
+
return []shimast.Kind{shimast.KindVariableDeclaration}
|
|
313
|
+
}
|
|
314
|
+
func (consistentGenericConstructors) Check(ctx *Context, node *shimast.Node) {
|
|
315
|
+
decl := node.AsVariableDeclaration()
|
|
316
|
+
if decl == nil || decl.Type == nil || decl.Initializer == nil {
|
|
317
|
+
return
|
|
318
|
+
}
|
|
319
|
+
if decl.Type.Kind != shimast.KindTypeReference {
|
|
320
|
+
return
|
|
321
|
+
}
|
|
322
|
+
typeRef := decl.Type.AsTypeReferenceNode()
|
|
323
|
+
if typeRef == nil || typeRef.TypeArguments == nil {
|
|
324
|
+
return
|
|
325
|
+
}
|
|
326
|
+
initializer := stripParens(decl.Initializer)
|
|
327
|
+
if initializer == nil || initializer.Kind != shimast.KindNewExpression {
|
|
328
|
+
return
|
|
329
|
+
}
|
|
330
|
+
ne := initializer.AsNewExpression()
|
|
331
|
+
if ne == nil || ne.TypeArguments == nil {
|
|
332
|
+
return
|
|
333
|
+
}
|
|
334
|
+
ctx.Report(initializer, "Redundant generic arguments — the annotation already pins the type parameters; drop them from the constructor or vice versa.")
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// preferNumericLiterals reports `parseInt(literal, radix)` calls that
|
|
338
|
+
// could be written as an ES2015+ numeric literal (binary `0b…`, octal
|
|
339
|
+
// `0o…`, hex `0x…`). The literal form is shorter, type-safe, and not
|
|
340
|
+
// subject to runtime radix mismatches.
|
|
341
|
+
// https://eslint.org/docs/latest/rules/prefer-numeric-literals
|
|
342
|
+
type preferNumericLiterals struct{}
|
|
343
|
+
|
|
344
|
+
func (preferNumericLiterals) Name() string { return "prefer-numeric-literals" }
|
|
345
|
+
func (preferNumericLiterals) Visits() []shimast.Kind {
|
|
346
|
+
return []shimast.Kind{shimast.KindCallExpression}
|
|
347
|
+
}
|
|
348
|
+
func (preferNumericLiterals) Check(ctx *Context, node *shimast.Node) {
|
|
349
|
+
call := node.AsCallExpression()
|
|
350
|
+
if call == nil || call.Expression == nil || call.Arguments == nil {
|
|
351
|
+
return
|
|
352
|
+
}
|
|
353
|
+
calleeName := identifierText(call.Expression)
|
|
354
|
+
if calleeName != "parseInt" && calleeName != "Number" {
|
|
355
|
+
return
|
|
356
|
+
}
|
|
357
|
+
args := call.Arguments.Nodes
|
|
358
|
+
if calleeName == "parseInt" && len(args) != 2 {
|
|
359
|
+
return
|
|
360
|
+
}
|
|
361
|
+
if calleeName == "Number" && len(args) != 1 {
|
|
362
|
+
return
|
|
363
|
+
}
|
|
364
|
+
first := stripParens(args[0])
|
|
365
|
+
if first == nil || first.Kind != shimast.KindStringLiteral {
|
|
366
|
+
return
|
|
367
|
+
}
|
|
368
|
+
if calleeName == "parseInt" {
|
|
369
|
+
radix := stripParens(args[1])
|
|
370
|
+
if radix == nil || radix.Kind != shimast.KindNumericLiteral {
|
|
371
|
+
return
|
|
372
|
+
}
|
|
373
|
+
switch numericLiteralText(radix) {
|
|
374
|
+
case "2", "8", "16":
|
|
375
|
+
ctx.Report(node, "Use a numeric literal (`0b…` / `0o…` / `0x…`) instead of `parseInt(\""+stringLiteralText(first)+"\", "+numericLiteralText(radix)+")`.")
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
func init() {
|
|
381
|
+
Register(noArrayForEach{})
|
|
382
|
+
Register(noExtraneousClass{})
|
|
383
|
+
Register(noInvalidVoidType{})
|
|
384
|
+
Register(explicitMemberAccessibility{})
|
|
385
|
+
Register(consistentGenericConstructors{})
|
|
386
|
+
Register(preferNumericLiterals{})
|
|
387
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// typescript/sort-type-constituents: union and intersection type
|
|
2
|
+
// constituents render the same set of values regardless of the order
|
|
3
|
+
// the author chose, so two authors writing the same type can disagree
|
|
4
|
+
// on the spelling. The rule pins one canonical ordering — primitives
|
|
5
|
+
// alphabetized first, then named / object types alphabetized, then
|
|
6
|
+
// `null` / `undefined` last — so reviewers don't have to argue about
|
|
7
|
+
// which spelling to land. typescript-eslint:
|
|
8
|
+
// https://typescript-eslint.io/rules/sort-type-constituents/
|
|
9
|
+
package linthost
|
|
10
|
+
|
|
11
|
+
import (
|
|
12
|
+
"sort"
|
|
13
|
+
"strings"
|
|
14
|
+
|
|
15
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
// sortTypeConstituents fires on `UnionType` and `IntersectionType` when
|
|
19
|
+
// the constituent order does not match the canonical ordering. The
|
|
20
|
+
// check is AST-only: ordering is decided by syntactic group (keyword
|
|
21
|
+
// primitive vs. named reference vs. nullish) and a within-group source
|
|
22
|
+
// sort, none of which need the Checker.
|
|
23
|
+
//
|
|
24
|
+
// The diagnostic anchors to the union / intersection node so the
|
|
25
|
+
// rendered location names the whole type, not just one constituent.
|
|
26
|
+
// One report per misordered type is enough — the autofixer would
|
|
27
|
+
// rewrite the entire list together anyway.
|
|
28
|
+
type sortTypeConstituents struct{}
|
|
29
|
+
|
|
30
|
+
func (sortTypeConstituents) Name() string {
|
|
31
|
+
return "typescript/sort-type-constituents"
|
|
32
|
+
}
|
|
33
|
+
func (sortTypeConstituents) Visits() []shimast.Kind {
|
|
34
|
+
return []shimast.Kind{
|
|
35
|
+
shimast.KindUnionType,
|
|
36
|
+
shimast.KindIntersectionType,
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
func (sortTypeConstituents) Check(ctx *Context, node *shimast.Node) {
|
|
40
|
+
types := unionOrIntersectionTypes(node)
|
|
41
|
+
if len(types) < 2 {
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
// Skip nested unions/intersections — the outermost shape is the one
|
|
45
|
+
// the user wrote, and reporting on every nesting level would
|
|
46
|
+
// double-fire on `(A | B) | C` shapes.
|
|
47
|
+
if node.Parent != nil &&
|
|
48
|
+
(node.Parent.Kind == shimast.KindUnionType || node.Parent.Kind == shimast.KindIntersectionType) {
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
entries := make([]sortTypeConstituentsEntry, len(types))
|
|
52
|
+
for i, t := range types {
|
|
53
|
+
entries[i] = sortTypeConstituentsEntry{
|
|
54
|
+
index: i,
|
|
55
|
+
group: sortTypeConstituentsClassify(t),
|
|
56
|
+
text: strings.TrimSpace(nodeText(ctx.File, t)),
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
sorted := make([]sortTypeConstituentsEntry, len(entries))
|
|
60
|
+
copy(sorted, entries)
|
|
61
|
+
sort.SliceStable(sorted, func(i, j int) bool {
|
|
62
|
+
if sorted[i].group != sorted[j].group {
|
|
63
|
+
return sorted[i].group < sorted[j].group
|
|
64
|
+
}
|
|
65
|
+
return sorted[i].text < sorted[j].text
|
|
66
|
+
})
|
|
67
|
+
for i := range entries {
|
|
68
|
+
if entries[i].index != sorted[i].index {
|
|
69
|
+
label := "union"
|
|
70
|
+
if node.Kind == shimast.KindIntersectionType {
|
|
71
|
+
label = "intersection"
|
|
72
|
+
}
|
|
73
|
+
ctx.Report(node, "Constituents of the "+label+" are not in the canonical order — primitives alphabetized first, named types alphabetized next, `null` / `undefined` last.")
|
|
74
|
+
return
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// sortTypeConstituentsEntry is one constituent's sort key. `index`
|
|
80
|
+
// records the original position so the reorder check can compare the
|
|
81
|
+
// before/after sequences without losing identity.
|
|
82
|
+
type sortTypeConstituentsEntry struct {
|
|
83
|
+
index int
|
|
84
|
+
group int
|
|
85
|
+
text string
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// sortTypeConstituentsClassify buckets a constituent into one of the
|
|
89
|
+
// canonical groups. Smaller numbers come first in the canonical order.
|
|
90
|
+
func sortTypeConstituentsClassify(node *shimast.Node) int {
|
|
91
|
+
if node == nil {
|
|
92
|
+
return sortTypeConstituentsGroupNamed
|
|
93
|
+
}
|
|
94
|
+
switch node.Kind {
|
|
95
|
+
case shimast.KindStringKeyword,
|
|
96
|
+
shimast.KindNumberKeyword,
|
|
97
|
+
shimast.KindBooleanKeyword,
|
|
98
|
+
shimast.KindBigIntKeyword,
|
|
99
|
+
shimast.KindSymbolKeyword,
|
|
100
|
+
shimast.KindAnyKeyword,
|
|
101
|
+
shimast.KindUnknownKeyword,
|
|
102
|
+
shimast.KindVoidKeyword,
|
|
103
|
+
shimast.KindNeverKeyword,
|
|
104
|
+
shimast.KindObjectKeyword:
|
|
105
|
+
return sortTypeConstituentsGroupPrimitive
|
|
106
|
+
case shimast.KindLiteralType:
|
|
107
|
+
// `null` and `undefined` parse as LiteralType / undefined
|
|
108
|
+
// keyword inside type position — surface them as the nullish
|
|
109
|
+
// group so the canonical order keeps them at the end.
|
|
110
|
+
if sortTypeConstituentsIsNullish(node) {
|
|
111
|
+
return sortTypeConstituentsGroupNullish
|
|
112
|
+
}
|
|
113
|
+
return sortTypeConstituentsGroupLiteral
|
|
114
|
+
case shimast.KindUndefinedKeyword, shimast.KindNullKeyword:
|
|
115
|
+
return sortTypeConstituentsGroupNullish
|
|
116
|
+
}
|
|
117
|
+
return sortTypeConstituentsGroupNamed
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const (
|
|
121
|
+
sortTypeConstituentsGroupPrimitive = iota
|
|
122
|
+
sortTypeConstituentsGroupLiteral
|
|
123
|
+
sortTypeConstituentsGroupNamed
|
|
124
|
+
sortTypeConstituentsGroupNullish
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
// sortTypeConstituentsIsNullish reports whether a LiteralType node
|
|
128
|
+
// wraps the `null` keyword token. The `undefined` keyword in type
|
|
129
|
+
// position is a regular Identifier-shaped reference and is handled by
|
|
130
|
+
// the named group, not by this helper.
|
|
131
|
+
func sortTypeConstituentsIsNullish(node *shimast.Node) bool {
|
|
132
|
+
if node == nil || node.Kind != shimast.KindLiteralType {
|
|
133
|
+
return false
|
|
134
|
+
}
|
|
135
|
+
lit := node.AsLiteralTypeNode()
|
|
136
|
+
if lit == nil || lit.Literal == nil {
|
|
137
|
+
return false
|
|
138
|
+
}
|
|
139
|
+
return lit.Literal.Kind == shimast.KindNullKeyword
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
func init() {
|
|
143
|
+
Register(sortTypeConstituents{})
|
|
144
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// strictBooleanExpressions fires when a non-boolean value is used in
|
|
2
|
+
// a boolean context — the test of an `if` / `while` / `do` / `for` /
|
|
3
|
+
// ternary, the operand of `!`, or either side of `&&` / `||`.
|
|
4
|
+
// JavaScript coerces every truthy / falsy shape silently:
|
|
5
|
+
//
|
|
6
|
+
// - numbers: `0`, `-0`, and `NaN` are falsy; every other number is
|
|
7
|
+
// truthy. `if (count)` therefore skips a legitimate zero.
|
|
8
|
+
// - strings: `""` is falsy; every other string is truthy.
|
|
9
|
+
// `if (name)` therefore skips a legitimate empty string.
|
|
10
|
+
// - nullable objects: `null` / `undefined` are falsy, the object is
|
|
11
|
+
// truthy. `if (obj)` collapses the present-vs-absent and
|
|
12
|
+
// present-but-empty cases together.
|
|
13
|
+
//
|
|
14
|
+
// The fix is always an explicit comparison naming the intent —
|
|
15
|
+
// `count !== 0`, `str.length > 0`, `obj != null`. typescript-eslint:
|
|
16
|
+
// https://typescript-eslint.io/rules/strict-boolean-expressions/
|
|
17
|
+
//
|
|
18
|
+
// Type-aware. Without a Checker the rule cannot tell a `boolean` apart
|
|
19
|
+
// from a `string`, so Context.Checker == nil short-circuits each Check
|
|
20
|
+
// to a no-op the way `no-for-in-array` and `no-misused-promises` do.
|
|
21
|
+
package linthost
|
|
22
|
+
|
|
23
|
+
import (
|
|
24
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
25
|
+
shimchecker "github.com/microsoft/typescript-go/shim/checker"
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
type strictBooleanExpressions struct{}
|
|
29
|
+
|
|
30
|
+
func (strictBooleanExpressions) Name() string { return "typescript/strict-boolean-expressions" }
|
|
31
|
+
func (strictBooleanExpressions) NeedsTypeChecker() bool {
|
|
32
|
+
return true
|
|
33
|
+
}
|
|
34
|
+
func (strictBooleanExpressions) Visits() []shimast.Kind {
|
|
35
|
+
return []shimast.Kind{
|
|
36
|
+
shimast.KindIfStatement,
|
|
37
|
+
shimast.KindWhileStatement,
|
|
38
|
+
shimast.KindDoStatement,
|
|
39
|
+
shimast.KindForStatement,
|
|
40
|
+
shimast.KindConditionalExpression,
|
|
41
|
+
shimast.KindPrefixUnaryExpression,
|
|
42
|
+
shimast.KindBinaryExpression,
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
func (strictBooleanExpressions) Check(ctx *Context, node *shimast.Node) {
|
|
46
|
+
if ctx.Checker == nil {
|
|
47
|
+
return
|
|
48
|
+
}
|
|
49
|
+
switch node.Kind {
|
|
50
|
+
case shimast.KindIfStatement:
|
|
51
|
+
if stmt := node.AsIfStatement(); stmt != nil {
|
|
52
|
+
strictBooleanExpressionsReport(ctx, stmt.Expression)
|
|
53
|
+
}
|
|
54
|
+
case shimast.KindWhileStatement:
|
|
55
|
+
if stmt := node.AsWhileStatement(); stmt != nil {
|
|
56
|
+
strictBooleanExpressionsReport(ctx, stmt.Expression)
|
|
57
|
+
}
|
|
58
|
+
case shimast.KindDoStatement:
|
|
59
|
+
if stmt := node.AsDoStatement(); stmt != nil {
|
|
60
|
+
strictBooleanExpressionsReport(ctx, stmt.Expression)
|
|
61
|
+
}
|
|
62
|
+
case shimast.KindForStatement:
|
|
63
|
+
if stmt := node.AsForStatement(); stmt != nil {
|
|
64
|
+
strictBooleanExpressionsReport(ctx, stmt.Condition)
|
|
65
|
+
}
|
|
66
|
+
case shimast.KindConditionalExpression:
|
|
67
|
+
if expr := node.AsConditionalExpression(); expr != nil {
|
|
68
|
+
strictBooleanExpressionsReport(ctx, expr.Condition)
|
|
69
|
+
}
|
|
70
|
+
case shimast.KindPrefixUnaryExpression:
|
|
71
|
+
expr := node.AsPrefixUnaryExpression()
|
|
72
|
+
if expr != nil && expr.Operator == shimast.KindExclamationToken {
|
|
73
|
+
strictBooleanExpressionsReport(ctx, expr.Operand)
|
|
74
|
+
}
|
|
75
|
+
case shimast.KindBinaryExpression:
|
|
76
|
+
bin := node.AsBinaryExpression()
|
|
77
|
+
if bin == nil || bin.OperatorToken == nil {
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
// Only `&&` / `||` test their left operand for truthiness.
|
|
81
|
+
// `??` short-circuits on nullish, not on falsy, so a non-boolean
|
|
82
|
+
// left operand is exactly the point of `??` and is not flagged.
|
|
83
|
+
switch bin.OperatorToken.Kind {
|
|
84
|
+
case shimast.KindAmpersandAmpersandToken, shimast.KindBarBarToken:
|
|
85
|
+
strictBooleanExpressionsReport(ctx, bin.Left)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// strictBooleanExpressionsReport flags `expr` when its static type is
|
|
91
|
+
// not pure boolean-like. The recursion arm peels through `&&` / `||`
|
|
92
|
+
// chains so `if (a && b)` reports both `a` and `b`, mirroring the
|
|
93
|
+
// upstream rule. Parenthesized wrappers are skipped via stripParens
|
|
94
|
+
// so `if ((x))` resolves to `x`.
|
|
95
|
+
func strictBooleanExpressionsReport(ctx *Context, expr *shimast.Node) {
|
|
96
|
+
if expr == nil {
|
|
97
|
+
return
|
|
98
|
+
}
|
|
99
|
+
expr = stripParens(expr)
|
|
100
|
+
if expr == nil {
|
|
101
|
+
return
|
|
102
|
+
}
|
|
103
|
+
// Descend through `&&` / `||` — each conjunct/disjunct sits in
|
|
104
|
+
// boolean position too. The outer BinaryExpression visit only
|
|
105
|
+
// checks Left; the descent here finds Right as well.
|
|
106
|
+
if expr.Kind == shimast.KindBinaryExpression {
|
|
107
|
+
bin := expr.AsBinaryExpression()
|
|
108
|
+
if bin != nil && bin.OperatorToken != nil {
|
|
109
|
+
switch bin.OperatorToken.Kind {
|
|
110
|
+
case shimast.KindAmpersandAmpersandToken, shimast.KindBarBarToken:
|
|
111
|
+
strictBooleanExpressionsReport(ctx, bin.Left)
|
|
112
|
+
strictBooleanExpressionsReport(ctx, bin.Right)
|
|
113
|
+
return
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
t := ctx.Checker.GetTypeAtLocation(expr)
|
|
118
|
+
if t == nil {
|
|
119
|
+
return
|
|
120
|
+
}
|
|
121
|
+
if strictBooleanExpressionsIsBoolean(t) {
|
|
122
|
+
return
|
|
123
|
+
}
|
|
124
|
+
ctx.Report(expr, "Unexpected non-boolean value in a boolean conditional position. Use an explicit comparison (`!== 0`, `.length > 0`, `!= null`) to name the intent.")
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// strictBooleanExpressionsIsBoolean reports whether t is pure
|
|
128
|
+
// boolean-like. `any` / `unknown` / `never` are intentionally NOT
|
|
129
|
+
// considered boolean — they leak through generic helpers and would
|
|
130
|
+
// suppress the rule everywhere a value of unknown origin lands in a
|
|
131
|
+
// conditional. Union and intersection types must have every
|
|
132
|
+
// constituent boolean for the whole type to count.
|
|
133
|
+
func strictBooleanExpressionsIsBoolean(t *shimchecker.Type) bool {
|
|
134
|
+
if t == nil {
|
|
135
|
+
return false
|
|
136
|
+
}
|
|
137
|
+
flags := t.Flags()
|
|
138
|
+
if flags&(shimchecker.TypeFlagsAny|shimchecker.TypeFlagsUnknown|shimchecker.TypeFlagsNever) != 0 {
|
|
139
|
+
return false
|
|
140
|
+
}
|
|
141
|
+
if flags&(shimchecker.TypeFlagsUnion|shimchecker.TypeFlagsIntersection) != 0 {
|
|
142
|
+
for _, part := range t.Types() {
|
|
143
|
+
if part == nil {
|
|
144
|
+
continue
|
|
145
|
+
}
|
|
146
|
+
if !strictBooleanExpressionsIsBoolean(part) {
|
|
147
|
+
return false
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return true
|
|
151
|
+
}
|
|
152
|
+
return flags&shimchecker.TypeFlagsBooleanLike != 0
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
func init() {
|
|
156
|
+
Register(strictBooleanExpressions{})
|
|
157
|
+
}
|