@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,124 @@
|
|
|
1
|
+
// preferArrowCallback: a `function() { … }` expression passed as a
|
|
2
|
+
// callback argument predates ES2015 arrow functions. The arrow form is
|
|
3
|
+
// shorter, captures `this` lexically (the usual intent for a callback),
|
|
4
|
+
// and avoids the named-binding hoisting of `function` expressions.
|
|
5
|
+
// https://eslint.org/docs/latest/rules/prefer-arrow-callback
|
|
6
|
+
//
|
|
7
|
+
// AST-only: visit every `CallExpression`/`NewExpression` and check
|
|
8
|
+
// whether any of its arguments is a `FunctionExpression`. A few shapes
|
|
9
|
+
// are skipped because converting them would change behaviour:
|
|
10
|
+
//
|
|
11
|
+
// - generators (`function* () {}`) cannot be arrows at all.
|
|
12
|
+
// - bodies that read `this` or `arguments` rely on the function
|
|
13
|
+
// expression's own binding; an arrow would capture the surrounding
|
|
14
|
+
// binding instead.
|
|
15
|
+
// - functions immediately followed by `.bind(…)` opt the caller into
|
|
16
|
+
// an explicit `this` binding that an arrow cannot honour.
|
|
17
|
+
//
|
|
18
|
+
// Named function expressions (`function name() { … }`) still flag —
|
|
19
|
+
// ESLint's default `allowNamedFunctions` is `false` — but a body that
|
|
20
|
+
// references the function's own name through the inner binding is left
|
|
21
|
+
// alone so the recursion stays valid.
|
|
22
|
+
package linthost
|
|
23
|
+
|
|
24
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
25
|
+
|
|
26
|
+
type preferArrowCallback struct{}
|
|
27
|
+
|
|
28
|
+
func (preferArrowCallback) Name() string { return "prefer-arrow-callback" }
|
|
29
|
+
func (preferArrowCallback) Visits() []shimast.Kind {
|
|
30
|
+
return []shimast.Kind{shimast.KindCallExpression, shimast.KindNewExpression}
|
|
31
|
+
}
|
|
32
|
+
func (preferArrowCallback) Check(ctx *Context, node *shimast.Node) {
|
|
33
|
+
args := callArgumentsList(node)
|
|
34
|
+
if args == nil {
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
for _, arg := range args.Nodes {
|
|
38
|
+
fn := stripParens(arg)
|
|
39
|
+
if fn == nil || fn.Kind != shimast.KindFunctionExpression {
|
|
40
|
+
continue
|
|
41
|
+
}
|
|
42
|
+
if !preferArrowCallbackEligible(fn) {
|
|
43
|
+
continue
|
|
44
|
+
}
|
|
45
|
+
ctx.Report(fn, "Unexpected function expression. Use an arrow function instead.")
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// callArgumentsList returns the argument NodeList of a CallExpression or
|
|
50
|
+
// NewExpression, or nil when the node either lacks arguments or is not a
|
|
51
|
+
// call/new shape.
|
|
52
|
+
func callArgumentsList(node *shimast.Node) *shimast.NodeList {
|
|
53
|
+
switch node.Kind {
|
|
54
|
+
case shimast.KindCallExpression:
|
|
55
|
+
call := node.AsCallExpression()
|
|
56
|
+
if call == nil {
|
|
57
|
+
return nil
|
|
58
|
+
}
|
|
59
|
+
return call.Arguments
|
|
60
|
+
case shimast.KindNewExpression:
|
|
61
|
+
newExpr := node.AsNewExpression()
|
|
62
|
+
if newExpr == nil {
|
|
63
|
+
return nil
|
|
64
|
+
}
|
|
65
|
+
return newExpr.Arguments
|
|
66
|
+
}
|
|
67
|
+
return nil
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// preferArrowCallbackEligible reports whether `fn` (a FunctionExpression)
|
|
71
|
+
// can be converted to an arrow without changing observable behaviour.
|
|
72
|
+
// The function must not be a generator, must not read `this` or
|
|
73
|
+
// `arguments` outside any nested function-like, and must not reference
|
|
74
|
+
// its own inner name (a self-recursion handle that an arrow cannot
|
|
75
|
+
// reproduce).
|
|
76
|
+
func preferArrowCallbackEligible(fn *shimast.Node) bool {
|
|
77
|
+
expr := fn.AsFunctionExpression()
|
|
78
|
+
if expr == nil {
|
|
79
|
+
return false
|
|
80
|
+
}
|
|
81
|
+
if expr.AsteriskToken != nil {
|
|
82
|
+
return false
|
|
83
|
+
}
|
|
84
|
+
innerName := identifierText(expr.Name())
|
|
85
|
+
body := expr.Body
|
|
86
|
+
if body == nil {
|
|
87
|
+
return true
|
|
88
|
+
}
|
|
89
|
+
usesForbidden := false
|
|
90
|
+
walkFunctionBody(body, func(child *shimast.Node) {
|
|
91
|
+
if usesForbidden || child == nil {
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
switch child.Kind {
|
|
95
|
+
case shimast.KindThisKeyword:
|
|
96
|
+
usesForbidden = true
|
|
97
|
+
case shimast.KindIdentifier:
|
|
98
|
+
text := identifierText(child)
|
|
99
|
+
if text == "arguments" {
|
|
100
|
+
// Skip `obj.arguments` — that's an unrelated member access.
|
|
101
|
+
if parent := child.Parent; parent != nil && parent.Kind == shimast.KindPropertyAccessExpression {
|
|
102
|
+
if access := parent.AsPropertyAccessExpression(); access != nil && access.Name() == child {
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
usesForbidden = true
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
if innerName != "" && text == innerName {
|
|
110
|
+
if parent := child.Parent; parent != nil && parent.Kind == shimast.KindPropertyAccessExpression {
|
|
111
|
+
if access := parent.AsPropertyAccessExpression(); access != nil && access.Name() == child {
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
usesForbidden = true
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
})
|
|
119
|
+
return !usesForbidden
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
func init() {
|
|
123
|
+
Register(preferArrowCallback{})
|
|
124
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// preferDestructuring: a variable declaration whose initializer is a
|
|
2
|
+
// single property or index access (`const a = obj.a;`, `const x =
|
|
3
|
+
// arr[0];`) is just longhand for the destructuring form (`const { a }
|
|
4
|
+
// = obj;`, `const [x] = arr;`). The destructuring form reads at the
|
|
5
|
+
// site as "extracts this from that", names the source object once, and
|
|
6
|
+
// scales to multi-field extraction without retyping the receiver.
|
|
7
|
+
// https://eslint.org/docs/latest/rules/prefer-destructuring
|
|
8
|
+
//
|
|
9
|
+
// AST-only: each visited `VariableDeclaration` is checked for an
|
|
10
|
+
// initializer shape that destructuring would replace verbatim:
|
|
11
|
+
//
|
|
12
|
+
// - `obj.<name>` where the variable name matches `<name>`
|
|
13
|
+
// - `arr[<n>]` where `<n>` is a numeric literal
|
|
14
|
+
//
|
|
15
|
+
// Computed string-literal access (`obj["a"]`) is skipped — that idiom
|
|
16
|
+
// is usually deliberate (e.g. key with hyphens or reserved-word
|
|
17
|
+
// keys). The receiver must be a plain identifier or property access;
|
|
18
|
+
// call expressions and other compound shapes are not flagged because
|
|
19
|
+
// the receiver would be re-evaluated under destructuring.
|
|
20
|
+
package linthost
|
|
21
|
+
|
|
22
|
+
import (
|
|
23
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
type preferDestructuring struct{}
|
|
27
|
+
|
|
28
|
+
func (preferDestructuring) Name() string { return "prefer-destructuring" }
|
|
29
|
+
func (preferDestructuring) Visits() []shimast.Kind {
|
|
30
|
+
return []shimast.Kind{shimast.KindVariableDeclaration}
|
|
31
|
+
}
|
|
32
|
+
func (preferDestructuring) Check(ctx *Context, node *shimast.Node) {
|
|
33
|
+
decl := node.AsVariableDeclaration()
|
|
34
|
+
if decl == nil || decl.Initializer == nil {
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
// Only fire on plain identifier bindings — destructuring already
|
|
38
|
+
// happens on `const { a } = obj;`.
|
|
39
|
+
name := decl.Name()
|
|
40
|
+
if name == nil || name.Kind != shimast.KindIdentifier {
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
varName := identifierText(name)
|
|
44
|
+
if varName == "" {
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
init := stripParens(decl.Initializer)
|
|
48
|
+
if init == nil {
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
switch init.Kind {
|
|
52
|
+
case shimast.KindPropertyAccessExpression:
|
|
53
|
+
access := init.AsPropertyAccessExpression()
|
|
54
|
+
if access == nil || access.Expression == nil || !preferDestructuringSimpleReceiver(access.Expression) {
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
propName := access.Name()
|
|
58
|
+
if propName == nil || propName.Kind != shimast.KindIdentifier {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
if identifierText(propName) != varName {
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
ctx.Report(node, "Use object destructuring (`const { "+varName+" } = obj`).")
|
|
65
|
+
case shimast.KindElementAccessExpression:
|
|
66
|
+
access := init.AsElementAccessExpression()
|
|
67
|
+
if access == nil || access.Expression == nil || access.ArgumentExpression == nil {
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
if !preferDestructuringSimpleReceiver(access.Expression) {
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
// Only numeric-literal index — array destructuring.
|
|
74
|
+
idx := stripParens(access.ArgumentExpression)
|
|
75
|
+
if idx == nil || idx.Kind != shimast.KindNumericLiteral {
|
|
76
|
+
return
|
|
77
|
+
}
|
|
78
|
+
ctx.Report(node, "Use array destructuring (`const ["+varName+"] = arr`).")
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
func preferDestructuringSimpleReceiver(node *shimast.Node) bool {
|
|
83
|
+
n := stripParens(node)
|
|
84
|
+
if n == nil {
|
|
85
|
+
return false
|
|
86
|
+
}
|
|
87
|
+
switch n.Kind {
|
|
88
|
+
case shimast.KindIdentifier,
|
|
89
|
+
shimast.KindThisKeyword,
|
|
90
|
+
shimast.KindPropertyAccessExpression:
|
|
91
|
+
return true
|
|
92
|
+
}
|
|
93
|
+
return false
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
func init() {
|
|
97
|
+
Register(preferDestructuring{})
|
|
98
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// preferNamedCaptureGroup: an unnamed capturing group `(…)` in a
|
|
2
|
+
// regular-expression literal has to be referenced by ordinal number.
|
|
3
|
+
// Named groups `(?<name>…)` document the captured value at the
|
|
4
|
+
// definition site and survive pattern edits that would otherwise renumber
|
|
5
|
+
// the groups silently.
|
|
6
|
+
// https://eslint.org/docs/latest/rules/prefer-named-capture-group
|
|
7
|
+
//
|
|
8
|
+
// AST-only: scan the pattern of every `RegularExpressionLiteral`,
|
|
9
|
+
// stepping past escapes and character classes (where `(` is a literal
|
|
10
|
+
// '(' rather than a group opener). Each `(` that is not followed by `?:`,
|
|
11
|
+
// `?<name>`, `?<=`, `?<!`, `?=`, or `?!` is an unnamed capture group and
|
|
12
|
+
// fires the rule. Character-class contents are skipped because '(' there
|
|
13
|
+
// is a literal byte, never a group opener.
|
|
14
|
+
package linthost
|
|
15
|
+
|
|
16
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
17
|
+
|
|
18
|
+
type preferNamedCaptureGroup struct{}
|
|
19
|
+
|
|
20
|
+
func (preferNamedCaptureGroup) Name() string { return "prefer-named-capture-group" }
|
|
21
|
+
func (preferNamedCaptureGroup) Visits() []shimast.Kind {
|
|
22
|
+
return []shimast.Kind{shimast.KindRegularExpressionLiteral}
|
|
23
|
+
}
|
|
24
|
+
func (preferNamedCaptureGroup) Check(ctx *Context, node *shimast.Node) {
|
|
25
|
+
raw := nodeText(ctx.File, node)
|
|
26
|
+
if len(raw) < 2 || raw[0] != '/' {
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
closing := lastSlashOutsideClass(raw)
|
|
30
|
+
if closing <= 0 {
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
pattern := raw[1:closing]
|
|
34
|
+
if regexpHasUnnamedCapture(pattern) {
|
|
35
|
+
ctx.Report(node, "Capture group should be named.")
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// regexpHasUnnamedCapture reports whether `pattern` contains at least
|
|
40
|
+
// one capturing group that is neither a non-capturing group (`(?:…)`),
|
|
41
|
+
// a named group (`(?<name>…)`), nor a lookaround assertion (`(?=…)`,
|
|
42
|
+
// `(?!…)`, `(?<=…)`, `(?<!…)`). The scan skips escape sequences and
|
|
43
|
+
// character-class contents because `(` is a literal byte in those
|
|
44
|
+
// positions and never opens a group.
|
|
45
|
+
func regexpHasUnnamedCapture(pattern string) bool {
|
|
46
|
+
inClass := false
|
|
47
|
+
for i := 0; i < len(pattern); i++ {
|
|
48
|
+
ch := pattern[i]
|
|
49
|
+
if ch == '\\' {
|
|
50
|
+
i++
|
|
51
|
+
continue
|
|
52
|
+
}
|
|
53
|
+
if inClass {
|
|
54
|
+
if ch == ']' {
|
|
55
|
+
inClass = false
|
|
56
|
+
}
|
|
57
|
+
continue
|
|
58
|
+
}
|
|
59
|
+
if ch == '[' {
|
|
60
|
+
inClass = true
|
|
61
|
+
continue
|
|
62
|
+
}
|
|
63
|
+
if ch != '(' {
|
|
64
|
+
continue
|
|
65
|
+
}
|
|
66
|
+
// `(` is a group opener; classify what follows.
|
|
67
|
+
if i+1 >= len(pattern) || pattern[i+1] != '?' {
|
|
68
|
+
return true
|
|
69
|
+
}
|
|
70
|
+
if i+2 >= len(pattern) {
|
|
71
|
+
// `(?` with nothing after — treat as malformed but not flagged;
|
|
72
|
+
// the parser would have rejected this regex if it was truly
|
|
73
|
+
// invalid, so leave it alone.
|
|
74
|
+
continue
|
|
75
|
+
}
|
|
76
|
+
switch pattern[i+2] {
|
|
77
|
+
case ':', '=', '!':
|
|
78
|
+
// non-capturing or lookahead
|
|
79
|
+
continue
|
|
80
|
+
case '<':
|
|
81
|
+
if i+3 < len(pattern) && (pattern[i+3] == '=' || pattern[i+3] == '!') {
|
|
82
|
+
// lookbehind `(?<=` / `(?<!`
|
|
83
|
+
continue
|
|
84
|
+
}
|
|
85
|
+
// named capture `(?<name>…)`
|
|
86
|
+
continue
|
|
87
|
+
}
|
|
88
|
+
// `(?` followed by something else (e.g. an inline flag group).
|
|
89
|
+
// Treat as unnamed; ESLint flags these too because they still
|
|
90
|
+
// capture under the standard regex semantics they target.
|
|
91
|
+
return true
|
|
92
|
+
}
|
|
93
|
+
return false
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// lastSlashOutsideClass returns the index of the closing `/` of a regex
|
|
97
|
+
// literal, accounting for `/` characters that appear inside escapes or
|
|
98
|
+
// character classes. Returns -1 when no closing slash is found.
|
|
99
|
+
func lastSlashOutsideClass(raw string) int {
|
|
100
|
+
if len(raw) < 2 || raw[0] != '/' {
|
|
101
|
+
return -1
|
|
102
|
+
}
|
|
103
|
+
inClass := false
|
|
104
|
+
for i := 1; i < len(raw); i++ {
|
|
105
|
+
ch := raw[i]
|
|
106
|
+
if ch == '\\' {
|
|
107
|
+
i++
|
|
108
|
+
continue
|
|
109
|
+
}
|
|
110
|
+
if inClass {
|
|
111
|
+
if ch == ']' {
|
|
112
|
+
inClass = false
|
|
113
|
+
}
|
|
114
|
+
continue
|
|
115
|
+
}
|
|
116
|
+
if ch == '[' {
|
|
117
|
+
inClass = true
|
|
118
|
+
continue
|
|
119
|
+
}
|
|
120
|
+
if ch == '/' {
|
|
121
|
+
return i
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return -1
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
func init() {
|
|
128
|
+
Register(preferNamedCaptureGroup{})
|
|
129
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// preferRestParams: a non-arrow function body that reads from
|
|
2
|
+
// `arguments` is using the legacy variadic-argument shape that predates
|
|
3
|
+
// ES6 rest parameters. Replacing the `arguments` access with
|
|
4
|
+
// `(...args)` declares the variadic contract on the signature, makes
|
|
5
|
+
// the parameter list iterable like every other JS array, and lets a
|
|
6
|
+
// reader see the variadic intent without reading the body.
|
|
7
|
+
// https://eslint.org/docs/latest/rules/prefer-rest-params
|
|
8
|
+
//
|
|
9
|
+
// AST-only: each visited function-like that owns its own `arguments`
|
|
10
|
+
// binding (function declaration, function expression, method, accessor,
|
|
11
|
+
// constructor — i.e. NOT an arrow function) is scanned for an
|
|
12
|
+
// `Identifier(arguments)` use inside its body. The walk stops at nested
|
|
13
|
+
// function-like boundaries via the shared `walkFunctionBody` helper.
|
|
14
|
+
// Property names like `obj.arguments` are skipped because they
|
|
15
|
+
// reference an unrelated member; only bare identifier reads count.
|
|
16
|
+
package linthost
|
|
17
|
+
|
|
18
|
+
import (
|
|
19
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
type preferRestParams struct{}
|
|
23
|
+
|
|
24
|
+
func (preferRestParams) Name() string { return "prefer-rest-params" }
|
|
25
|
+
func (preferRestParams) Visits() []shimast.Kind {
|
|
26
|
+
return []shimast.Kind{
|
|
27
|
+
shimast.KindFunctionDeclaration,
|
|
28
|
+
shimast.KindFunctionExpression,
|
|
29
|
+
shimast.KindMethodDeclaration,
|
|
30
|
+
shimast.KindGetAccessor,
|
|
31
|
+
shimast.KindSetAccessor,
|
|
32
|
+
shimast.KindConstructor,
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
func (preferRestParams) Check(ctx *Context, node *shimast.Node) {
|
|
36
|
+
body := preferRestParamsBody(node)
|
|
37
|
+
if body == nil {
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
reported := false
|
|
41
|
+
walkFunctionBody(body, func(child *shimast.Node) {
|
|
42
|
+
if reported || child == nil {
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
if child.Kind != shimast.KindIdentifier {
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
if identifierText(child) != "arguments" {
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
// Skip `obj.arguments` — that's an unrelated member access.
|
|
52
|
+
if parent := child.Parent; parent != nil && parent.Kind == shimast.KindPropertyAccessExpression {
|
|
53
|
+
if access := parent.AsPropertyAccessExpression(); access != nil && access.Name() == child {
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
reported = true
|
|
58
|
+
ctx.Report(child, "Use rest parameters (`...args`) instead of `arguments`.")
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
func preferRestParamsBody(node *shimast.Node) *shimast.Node {
|
|
63
|
+
switch node.Kind {
|
|
64
|
+
case shimast.KindFunctionDeclaration:
|
|
65
|
+
if fn := node.AsFunctionDeclaration(); fn != nil {
|
|
66
|
+
return fn.Body
|
|
67
|
+
}
|
|
68
|
+
case shimast.KindFunctionExpression:
|
|
69
|
+
if fn := node.AsFunctionExpression(); fn != nil {
|
|
70
|
+
return fn.Body
|
|
71
|
+
}
|
|
72
|
+
case shimast.KindMethodDeclaration:
|
|
73
|
+
if m := node.AsMethodDeclaration(); m != nil {
|
|
74
|
+
return m.Body
|
|
75
|
+
}
|
|
76
|
+
case shimast.KindGetAccessor:
|
|
77
|
+
if a := node.AsGetAccessorDeclaration(); a != nil {
|
|
78
|
+
return a.Body
|
|
79
|
+
}
|
|
80
|
+
case shimast.KindSetAccessor:
|
|
81
|
+
if a := node.AsSetAccessorDeclaration(); a != nil {
|
|
82
|
+
return a.Body
|
|
83
|
+
}
|
|
84
|
+
case shimast.KindConstructor:
|
|
85
|
+
if c := node.AsConstructorDeclaration(); c != nil {
|
|
86
|
+
return c.Body
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return nil
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
func init() {
|
|
93
|
+
Register(preferRestParams{})
|
|
94
|
+
}
|
|
@@ -8,12 +8,13 @@
|
|
|
8
8
|
package linthost
|
|
9
9
|
|
|
10
10
|
import (
|
|
11
|
+
"strconv"
|
|
11
12
|
"strings"
|
|
12
13
|
|
|
13
14
|
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
14
15
|
)
|
|
15
16
|
|
|
16
|
-
//
|
|
17
|
+
// noDupeElseIf: `if (a) {} else if (a) {}` — the second branch is
|
|
17
18
|
// unreachable.
|
|
18
19
|
type noDupeElseIf struct{}
|
|
19
20
|
|
|
@@ -49,7 +50,7 @@ func (noDupeElseIf) Check(ctx *Context, node *shimast.Node) {
|
|
|
49
50
|
}
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
//
|
|
53
|
+
// noExAssign: `try { } catch (e) { e = 1; }` — reassigning the catch
|
|
53
54
|
// binding silently throws away the error.
|
|
54
55
|
type noExAssign struct{}
|
|
55
56
|
|
|
@@ -74,8 +75,8 @@ func (noExAssign) Check(ctx *Context, node *shimast.Node) {
|
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
// walkAssignments invokes `report` on every `<name> = ...` shape inside
|
|
77
|
-
// `root`. Used by
|
|
78
|
-
// file-wide
|
|
78
|
+
// `root`. Used by noExAssign to scan a single catch block; the
|
|
79
|
+
// file-wide noFuncAssign / noClassAssign scans go through
|
|
79
80
|
// reportAssignmentsToDeclarations instead.
|
|
80
81
|
func walkAssignments(root *shimast.Node, name string, report func(*shimast.Node)) {
|
|
81
82
|
if root == nil {
|
|
@@ -98,7 +99,7 @@ func walkAssignments(root *shimast.Node, name string, report func(*shimast.Node)
|
|
|
98
99
|
})
|
|
99
100
|
}
|
|
100
101
|
|
|
101
|
-
//
|
|
102
|
+
// noEmptyCharacterClass: `/[]/` matches nothing.
|
|
102
103
|
type noEmptyCharacterClass struct{}
|
|
103
104
|
|
|
104
105
|
func (noEmptyCharacterClass) Name() string { return "no-empty-character-class" }
|
|
@@ -133,7 +134,7 @@ func hasEmptyCharClass(src string) bool {
|
|
|
133
134
|
return false
|
|
134
135
|
}
|
|
135
136
|
|
|
136
|
-
//
|
|
137
|
+
// noMisleadingCharacterClass: `/[👍]/` — surrogate pairs in regex.
|
|
137
138
|
type noMisleadingCharacterClass struct{}
|
|
138
139
|
|
|
139
140
|
func (noMisleadingCharacterClass) Name() string { return "no-misleading-character-class" }
|
|
@@ -178,10 +179,10 @@ func regexHasSurrogatePair(src string) bool {
|
|
|
178
179
|
return false
|
|
179
180
|
}
|
|
180
181
|
|
|
181
|
-
//
|
|
182
|
-
//
|
|
183
|
-
// normalized .Text, which has already lost
|
|
184
|
-
//
|
|
182
|
+
// noLossOfPrecision: `9007199254740993` — decimal numeric literal whose
|
|
183
|
+
// source text changes when parsed as a JavaScript Number. We read the source
|
|
184
|
+
// form instead of the parser's normalized .Text, which has already lost
|
|
185
|
+
// precision.
|
|
185
186
|
type noLossOfPrecision struct{}
|
|
186
187
|
|
|
187
188
|
func (noLossOfPrecision) Name() string { return "no-loss-of-precision" }
|
|
@@ -196,10 +197,10 @@ func (noLossOfPrecision) Check(ctx *Context, node *shimast.Node) {
|
|
|
196
197
|
}
|
|
197
198
|
}
|
|
198
199
|
|
|
199
|
-
// numericLiteralLosesPrecision reports whether the decimal integer literal
|
|
200
|
-
//
|
|
201
|
-
//
|
|
202
|
-
//
|
|
200
|
+
// numericLiteralLosesPrecision reports whether the decimal integer literal text
|
|
201
|
+
// changes when parsed as a JavaScript Number. Non-decimal literals (hex, octal,
|
|
202
|
+
// binary) and literals with exponents or decimal points are exempt because
|
|
203
|
+
// their precision loss is caller-visible and intentional.
|
|
203
204
|
func numericLiteralLosesPrecision(text string) bool {
|
|
204
205
|
// Strip underscore separators, exponents, decimal/hex/oct/binary
|
|
205
206
|
// markers — for the simple-base-10 integer case the round-trip
|
|
@@ -216,19 +217,29 @@ func numericLiteralLosesPrecision(text string) bool {
|
|
|
216
217
|
if trimmed == "" {
|
|
217
218
|
return false
|
|
218
219
|
}
|
|
219
|
-
//
|
|
220
|
-
//
|
|
221
|
-
const
|
|
222
|
-
if len(trimmed) < len(
|
|
220
|
+
// 2^53 is unsafe for arithmetic comparisons but still exactly representable.
|
|
221
|
+
// 2^53+1 is the first plain decimal integer that changes when parsed.
|
|
222
|
+
const firstPossibleLoss = "9007199254740993"
|
|
223
|
+
if len(trimmed) < len(firstPossibleLoss) {
|
|
223
224
|
return false
|
|
224
225
|
}
|
|
225
|
-
if len(trimmed)
|
|
226
|
+
if len(trimmed) == len(firstPossibleLoss) && trimmed < firstPossibleLoss {
|
|
227
|
+
return false
|
|
228
|
+
}
|
|
229
|
+
// Number.MAX_VALUE is around 1.79e308, so any integer with more than 309
|
|
230
|
+
// decimal digits cannot round-trip through a finite JavaScript Number.
|
|
231
|
+
const maxFiniteDecimalDigits = 309
|
|
232
|
+
if len(trimmed) > maxFiniteDecimalDigits {
|
|
226
233
|
return true
|
|
227
234
|
}
|
|
228
|
-
|
|
235
|
+
parsed, err := strconv.ParseFloat(trimmed, 64)
|
|
236
|
+
if err != nil && parsed == 0 {
|
|
237
|
+
return false
|
|
238
|
+
}
|
|
239
|
+
return strconv.FormatFloat(parsed, 'f', 0, 64) != trimmed
|
|
229
240
|
}
|
|
230
241
|
|
|
231
|
-
//
|
|
242
|
+
// noClassAssign: assigning to a class declaration's name.
|
|
232
243
|
type noClassAssign struct{}
|
|
233
244
|
|
|
234
245
|
func (noClassAssign) Name() string { return "no-class-assign" }
|
|
@@ -237,7 +248,7 @@ func (noClassAssign) Check(ctx *Context, node *shimast.Node) {
|
|
|
237
248
|
reportAssignmentsToDeclarations(ctx, node, shimast.KindClassDeclaration, "is a class.")
|
|
238
249
|
}
|
|
239
250
|
|
|
240
|
-
//
|
|
251
|
+
// noFuncAssign: same idea, but for function declarations.
|
|
241
252
|
type noFuncAssign struct{}
|
|
242
253
|
|
|
243
254
|
func (noFuncAssign) Name() string { return "no-func-assign" }
|
|
@@ -308,7 +319,7 @@ func declarationName(n *shimast.Node) string {
|
|
|
308
319
|
return ""
|
|
309
320
|
}
|
|
310
321
|
|
|
311
|
-
//
|
|
322
|
+
// noPrototypeBuiltins: `obj.hasOwnProperty(x)` — should be
|
|
312
323
|
// `Object.prototype.hasOwnProperty.call(obj, x)` or `Object.hasOwn`.
|
|
313
324
|
type noPrototypeBuiltins struct{}
|
|
314
325
|
|
|
@@ -333,7 +344,7 @@ func (noPrototypeBuiltins) Check(ctx *Context, node *shimast.Node) {
|
|
|
333
344
|
}
|
|
334
345
|
}
|
|
335
346
|
|
|
336
|
-
//
|
|
347
|
+
// noAsyncPromiseExecutor: `new Promise(async (resolve) => {...})`.
|
|
337
348
|
type noAsyncPromiseExecutor struct{}
|
|
338
349
|
|
|
339
350
|
func (noAsyncPromiseExecutor) Name() string { return "no-async-promise-executor" }
|
|
@@ -360,7 +371,7 @@ func (noAsyncPromiseExecutor) Check(ctx *Context, node *shimast.Node) {
|
|
|
360
371
|
}
|
|
361
372
|
}
|
|
362
373
|
|
|
363
|
-
//
|
|
374
|
+
// noPromiseExecutorReturn: `new Promise(() => 1)` — the value is
|
|
364
375
|
// thrown away.
|
|
365
376
|
type noPromiseExecutorReturn struct{}
|
|
366
377
|
|
|
@@ -390,7 +401,7 @@ func (noPromiseExecutorReturn) Check(ctx *Context, node *shimast.Node) {
|
|
|
390
401
|
}
|
|
391
402
|
}
|
|
392
403
|
|
|
393
|
-
//
|
|
404
|
+
// noControlRegex: `/\x00/` — control characters in regex are usually
|
|
394
405
|
// the result of accidentally typing the escape rather than the printable
|
|
395
406
|
// counterpart.
|
|
396
407
|
type noControlRegex struct{}
|
|
@@ -454,7 +465,7 @@ func hexDigit(b byte) int {
|
|
|
454
465
|
return -1
|
|
455
466
|
}
|
|
456
467
|
|
|
457
|
-
//
|
|
468
|
+
// noIrregularWhitespace: zero-width spaces, NBSP, etc. The TS parser
|
|
458
469
|
// accepts them but copy-paste into source is almost always a mistake.
|
|
459
470
|
type noIrregularWhitespace struct{}
|
|
460
471
|
|
|
@@ -491,7 +502,7 @@ func isIrregularWhitespace(r rune) bool {
|
|
|
491
502
|
return false
|
|
492
503
|
}
|
|
493
504
|
|
|
494
|
-
//
|
|
505
|
+
// noFallthrough: `switch` cases that fall through to the next label
|
|
495
506
|
// without an explicit `break` / `return` / `throw` / `continue`.
|
|
496
507
|
type noFallthrough struct{}
|
|
497
508
|
|
|
@@ -549,7 +560,7 @@ func isTerminating(stmt *shimast.Node) bool {
|
|
|
549
560
|
return false
|
|
550
561
|
}
|
|
551
562
|
|
|
552
|
-
//
|
|
563
|
+
// noInnerDeclarations: `function foo() { if (x) { function bar() {} } }`
|
|
553
564
|
// — inner function declarations are hoisted differently in strict mode
|
|
554
565
|
// vs sloppy and are confusing.
|
|
555
566
|
type noInnerDeclarations struct{}
|
|
@@ -592,7 +603,7 @@ func (noInnerDeclarations) Check(ctx *Context, node *shimast.Node) {
|
|
|
592
603
|
ctx.Report(node, "Move "+what+" declaration to the function scope.")
|
|
593
604
|
}
|
|
594
605
|
|
|
595
|
-
//
|
|
606
|
+
// noObjCalls: `Math()`, `JSON()` — these globals are objects, not
|
|
596
607
|
// callables. ESLint catches a small list.
|
|
597
608
|
type noObjCalls struct{}
|
|
598
609
|
|