@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,75 @@
|
|
|
1
|
+
// noElseReturn: when an `if` block ends in a `return` / `throw` /
|
|
2
|
+
// `break` / `continue` statement, the matching `else` block is
|
|
3
|
+
// redundant — control already left the function (or loop), so flatten
|
|
4
|
+
// the `else` body into the surrounding scope to keep one less level of
|
|
5
|
+
// nesting and one less branch to read.
|
|
6
|
+
// https://eslint.org/docs/latest/rules/no-else-return
|
|
7
|
+
//
|
|
8
|
+
// AST-only: each visited `IfStatement` whose `ThenStatement` provably
|
|
9
|
+
// terminates control flow on every branch reports on the `else`
|
|
10
|
+
// keyword. A `then` branch terminates when:
|
|
11
|
+
//
|
|
12
|
+
// - it is itself a terminating statement (`return`, `throw`, etc.), or
|
|
13
|
+
// - it is a `Block` whose final statement terminates AND every
|
|
14
|
+
// `if/else if/else` chain inside it terminates on every leaf, or
|
|
15
|
+
// - it is an `IfStatement` whose `then` AND `else` both terminate
|
|
16
|
+
// (chained early returns).
|
|
17
|
+
//
|
|
18
|
+
// The analysis is conservative; ambiguous shapes (e.g. an `if` with no
|
|
19
|
+
// `else`, or a loop with `break` only) are left alone.
|
|
20
|
+
package linthost
|
|
21
|
+
|
|
22
|
+
import (
|
|
23
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
type noElseReturn struct{}
|
|
27
|
+
|
|
28
|
+
func (noElseReturn) Name() string { return "no-else-return" }
|
|
29
|
+
func (noElseReturn) Visits() []shimast.Kind {
|
|
30
|
+
return []shimast.Kind{shimast.KindIfStatement}
|
|
31
|
+
}
|
|
32
|
+
func (noElseReturn) Check(ctx *Context, node *shimast.Node) {
|
|
33
|
+
ifStmt := node.AsIfStatement()
|
|
34
|
+
if ifStmt == nil || ifStmt.ElseStatement == nil {
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
if !noElseReturnTerminates(ifStmt.ThenStatement) {
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
ctx.Report(ifStmt.ElseStatement, "Remove the `else` — the preceding branch already terminates.")
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
func noElseReturnTerminates(stmt *shimast.Node) bool {
|
|
44
|
+
if stmt == nil {
|
|
45
|
+
return false
|
|
46
|
+
}
|
|
47
|
+
switch stmt.Kind {
|
|
48
|
+
case shimast.KindReturnStatement,
|
|
49
|
+
shimast.KindThrowStatement,
|
|
50
|
+
shimast.KindBreakStatement,
|
|
51
|
+
shimast.KindContinueStatement:
|
|
52
|
+
return true
|
|
53
|
+
case shimast.KindBlock:
|
|
54
|
+
block := stmt.AsBlock()
|
|
55
|
+
if block == nil || block.Statements == nil {
|
|
56
|
+
return false
|
|
57
|
+
}
|
|
58
|
+
stmts := block.Statements.Nodes
|
|
59
|
+
if len(stmts) == 0 {
|
|
60
|
+
return false
|
|
61
|
+
}
|
|
62
|
+
return noElseReturnTerminates(stmts[len(stmts)-1])
|
|
63
|
+
case shimast.KindIfStatement:
|
|
64
|
+
inner := stmt.AsIfStatement()
|
|
65
|
+
if inner == nil || inner.ElseStatement == nil {
|
|
66
|
+
return false
|
|
67
|
+
}
|
|
68
|
+
return noElseReturnTerminates(inner.ThenStatement) && noElseReturnTerminates(inner.ElseStatement)
|
|
69
|
+
}
|
|
70
|
+
return false
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
func init() {
|
|
74
|
+
Register(noElseReturn{})
|
|
75
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// no-empty-named-blocks: empty `{}` clauses on import or export
|
|
2
|
+
// declarations bind nothing and almost always indicate a mid-edit
|
|
3
|
+
// mistake or a leftover marker. ESLint suggestions / extra-rules:
|
|
4
|
+
// https://eslint.org/docs/latest/rules/no-empty-named-blocks
|
|
5
|
+
//
|
|
6
|
+
// Three shapes fire the rule:
|
|
7
|
+
//
|
|
8
|
+
// - `import {} from "x"` — only the side-effect load remains; write
|
|
9
|
+
// `import "x"` instead if that is the intent.
|
|
10
|
+
// - `import name, {} from "x"` — once a default binding is present the
|
|
11
|
+
// `{}` adds nothing; drop the empty clause.
|
|
12
|
+
// - `export {}` — restates module-ness redundantly, or marks an
|
|
13
|
+
// otherwise non-module file in a way that has cleaner alternatives
|
|
14
|
+
// (`no-useless-empty-export` is the stricter sibling that fires
|
|
15
|
+
// only when another module-syntax statement is already present).
|
|
16
|
+
//
|
|
17
|
+
// AST-only; the rule never consults the Checker.
|
|
18
|
+
package linthost
|
|
19
|
+
|
|
20
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
21
|
+
|
|
22
|
+
type noEmptyNamedBlocks struct{}
|
|
23
|
+
|
|
24
|
+
func (noEmptyNamedBlocks) Name() string { return "no-empty-named-blocks" }
|
|
25
|
+
func (noEmptyNamedBlocks) Visits() []shimast.Kind {
|
|
26
|
+
return []shimast.Kind{shimast.KindImportDeclaration, shimast.KindExportDeclaration}
|
|
27
|
+
}
|
|
28
|
+
func (noEmptyNamedBlocks) Check(ctx *Context, node *shimast.Node) {
|
|
29
|
+
switch node.Kind {
|
|
30
|
+
case shimast.KindImportDeclaration:
|
|
31
|
+
noEmptyNamedBlocksCheckImport(ctx, node)
|
|
32
|
+
case shimast.KindExportDeclaration:
|
|
33
|
+
noEmptyNamedBlocksCheckExport(ctx, node)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// noEmptyNamedBlocksCheckImport flags `import {} from "x"` and
|
|
38
|
+
// `import name, {} from "x"`. The empty-clause-only form should become
|
|
39
|
+
// a bare `import "x"`; the default-plus-empty form should drop the
|
|
40
|
+
// empty clause and keep the default binding.
|
|
41
|
+
func noEmptyNamedBlocksCheckImport(ctx *Context, node *shimast.Node) {
|
|
42
|
+
decl := node.AsImportDeclaration()
|
|
43
|
+
if decl == nil || decl.ImportClause == nil {
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
clause := decl.ImportClause.AsImportClause()
|
|
47
|
+
if clause == nil {
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
if clause.NamedBindings == nil {
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
if clause.NamedBindings.Kind != shimast.KindNamedImports {
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
named := clause.NamedBindings.AsNamedImports()
|
|
57
|
+
if named == nil || named.Elements == nil || len(named.Elements.Nodes) > 0 {
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
// Two shapes both reach here:
|
|
61
|
+
// `import {} from "x"` — clause.Name() == nil
|
|
62
|
+
// `import name, {} from "x"` — clause.Name() != nil
|
|
63
|
+
// Either way the empty `{}` is what the rule blames; the report
|
|
64
|
+
// target is the empty named-imports node so the highlight points at
|
|
65
|
+
// the `{}` token, not the whole declaration.
|
|
66
|
+
ctx.Report(clause.NamedBindings, "Unexpected empty named import block.")
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// noEmptyNamedBlocksCheckExport flags `export {}` (with or without a
|
|
70
|
+
// `from "x"` source). The form is always rewritable to either nothing
|
|
71
|
+
// or a bare side-effect `import "x"`; the rule's role is to surface it
|
|
72
|
+
// uniformly across both module and non-module sources, leaving
|
|
73
|
+
// `no-useless-empty-export` to gate the narrower redundant-marker case.
|
|
74
|
+
func noEmptyNamedBlocksCheckExport(ctx *Context, node *shimast.Node) {
|
|
75
|
+
decl := node.AsExportDeclaration()
|
|
76
|
+
if decl == nil || decl.ExportClause == nil {
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
if decl.ExportClause.Kind != shimast.KindNamedExports {
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
named := decl.ExportClause.AsNamedExports()
|
|
83
|
+
if named == nil || named.Elements == nil || len(named.Elements.Nodes) > 0 {
|
|
84
|
+
return
|
|
85
|
+
}
|
|
86
|
+
ctx.Report(node, "Unexpected empty named export block.")
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
func init() {
|
|
90
|
+
Register(noEmptyNamedBlocks{})
|
|
91
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
package linthost
|
|
2
|
+
|
|
3
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
4
|
+
|
|
5
|
+
// noExtendNative: forbid assignments to `<Builtin>.prototype.<key>`,
|
|
6
|
+
// which mutate a shared global and leak across the entire realm.
|
|
7
|
+
// https://eslint.org/docs/latest/rules/no-extend-native
|
|
8
|
+
type noExtendNative struct{}
|
|
9
|
+
|
|
10
|
+
func (noExtendNative) Name() string { return "no-extend-native" }
|
|
11
|
+
func (noExtendNative) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindBinaryExpression} }
|
|
12
|
+
func (noExtendNative) Check(ctx *Context, node *shimast.Node) {
|
|
13
|
+
expr := node.AsBinaryExpression()
|
|
14
|
+
if expr == nil || expr.OperatorToken == nil {
|
|
15
|
+
return
|
|
16
|
+
}
|
|
17
|
+
if expr.OperatorToken.Kind != shimast.KindEqualsToken {
|
|
18
|
+
return
|
|
19
|
+
}
|
|
20
|
+
outer := stripParens(expr.Left)
|
|
21
|
+
if outer == nil || outer.Kind != shimast.KindPropertyAccessExpression {
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
receiver := stripParens(outer.AsPropertyAccessExpression().Expression)
|
|
25
|
+
if receiver == nil || receiver.Kind != shimast.KindPropertyAccessExpression {
|
|
26
|
+
return
|
|
27
|
+
}
|
|
28
|
+
inner := receiver.AsPropertyAccessExpression()
|
|
29
|
+
if identifierText(inner.Name()) != "prototype" {
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
builtin := identifierText(stripParens(inner.Expression))
|
|
33
|
+
if !isExtendNativeBuiltin(builtin) {
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
ctx.Report(node, builtin+" prototype is read only, properties should not be added.")
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
func isExtendNativeBuiltin(name string) bool {
|
|
40
|
+
switch name {
|
|
41
|
+
case "Object", "Array", "String", "Number", "Boolean", "Function",
|
|
42
|
+
"Date", "RegExp", "Error", "Map", "Set", "WeakMap", "WeakSet",
|
|
43
|
+
"Promise", "Symbol":
|
|
44
|
+
return true
|
|
45
|
+
}
|
|
46
|
+
return false
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
func init() {
|
|
50
|
+
Register(noExtendNative{})
|
|
51
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// noImportAssign: writes to a binding introduced by an `import`
|
|
2
|
+
// declaration. Imported bindings are read-only at runtime; mutating
|
|
3
|
+
// them either throws under strict mode or silently desynchronises the
|
|
4
|
+
// module's view of its own exports.
|
|
5
|
+
//
|
|
6
|
+
// Conservative scope tracking: collect the local names introduced by
|
|
7
|
+
// every `import` declaration in the file (default specifier, named
|
|
8
|
+
// specifier, namespace alias), then walk descendants once and flag
|
|
9
|
+
// `name = …` / `name op= …` / `++name` / `name--` assignments whose
|
|
10
|
+
// left-hand side is one of those names. Namespace imports are also
|
|
11
|
+
// flagged on `ns.foo = …` / `++ns.foo` because the namespace object
|
|
12
|
+
// is itself frozen — mutating any property throws in strict mode.
|
|
13
|
+
//
|
|
14
|
+
// Like `no-param-reassign`, this is an AST-only baseline: a later
|
|
15
|
+
// `const name = …` inside an inner scope that shadows an imported
|
|
16
|
+
// name will produce a false positive. Proper resolution needs the
|
|
17
|
+
// real binder, which the AST-only baseline avoids.
|
|
18
|
+
// https://eslint.org/docs/latest/rules/no-import-assign
|
|
19
|
+
package linthost
|
|
20
|
+
|
|
21
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
22
|
+
|
|
23
|
+
type noImportAssign struct{}
|
|
24
|
+
|
|
25
|
+
func (noImportAssign) Name() string { return "no-import-assign" }
|
|
26
|
+
func (noImportAssign) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindSourceFile} }
|
|
27
|
+
func (noImportAssign) Check(ctx *Context, node *shimast.Node) {
|
|
28
|
+
if node == nil {
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
imported := map[string]bool{}
|
|
32
|
+
namespaces := map[string]bool{}
|
|
33
|
+
collectImportedBindings(node, imported, namespaces)
|
|
34
|
+
if len(imported) == 0 {
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
walkDescendants(node, func(n *shimast.Node) {
|
|
38
|
+
switch n.Kind {
|
|
39
|
+
case shimast.KindBinaryExpression:
|
|
40
|
+
expr := n.AsBinaryExpression()
|
|
41
|
+
if expr == nil || expr.OperatorToken == nil || !isAssignmentOperator(expr.OperatorToken.Kind) {
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
reportImportTarget(ctx, expr.Left, imported, namespaces)
|
|
45
|
+
case shimast.KindPrefixUnaryExpression:
|
|
46
|
+
pre := n.AsPrefixUnaryExpression()
|
|
47
|
+
if pre == nil || (pre.Operator != shimast.KindPlusPlusToken && pre.Operator != shimast.KindMinusMinusToken) {
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
reportImportTarget(ctx, pre.Operand, imported, namespaces)
|
|
51
|
+
case shimast.KindPostfixUnaryExpression:
|
|
52
|
+
post := n.AsPostfixUnaryExpression()
|
|
53
|
+
if post == nil || (post.Operator != shimast.KindPlusPlusToken && post.Operator != shimast.KindMinusMinusToken) {
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
reportImportTarget(ctx, post.Operand, imported, namespaces)
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// collectImportedBindings walks every `import` declaration in `file` and
|
|
62
|
+
// records the local names introduced. Namespace bindings (`* as ns`) are
|
|
63
|
+
// additionally remembered so callers can flag property mutations like
|
|
64
|
+
// `ns.foo = …`.
|
|
65
|
+
func collectImportedBindings(file *shimast.Node, imported, namespaces map[string]bool) {
|
|
66
|
+
walkDescendants(file, func(n *shimast.Node) {
|
|
67
|
+
if n == nil || n.Kind != shimast.KindImportDeclaration {
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
decl := n.AsImportDeclaration()
|
|
71
|
+
if decl == nil || decl.ImportClause == nil {
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
clause := decl.ImportClause.AsImportClause()
|
|
75
|
+
if clause == nil {
|
|
76
|
+
return
|
|
77
|
+
}
|
|
78
|
+
// `import Default from "x"` — default specifier.
|
|
79
|
+
if name := identifierText(clause.Name()); name != "" {
|
|
80
|
+
imported[name] = true
|
|
81
|
+
}
|
|
82
|
+
if clause.NamedBindings == nil {
|
|
83
|
+
return
|
|
84
|
+
}
|
|
85
|
+
switch clause.NamedBindings.Kind {
|
|
86
|
+
case shimast.KindNamedImports:
|
|
87
|
+
named := clause.NamedBindings.AsNamedImports()
|
|
88
|
+
if named == nil || named.Elements == nil {
|
|
89
|
+
return
|
|
90
|
+
}
|
|
91
|
+
for _, specNode := range named.Elements.Nodes {
|
|
92
|
+
spec := specNode.AsImportSpecifier()
|
|
93
|
+
if spec == nil {
|
|
94
|
+
continue
|
|
95
|
+
}
|
|
96
|
+
if name := identifierText(spec.Name()); name != "" {
|
|
97
|
+
imported[name] = true
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
case shimast.KindNamespaceImport:
|
|
101
|
+
ns := clause.NamedBindings.AsNamespaceImport()
|
|
102
|
+
if ns == nil {
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
if name := identifierText(ns.Name()); name != "" {
|
|
106
|
+
imported[name] = true
|
|
107
|
+
namespaces[name] = true
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// reportImportTarget flags `target` when it writes to an imported name.
|
|
114
|
+
// A bare identifier matching an imported binding is always flagged; a
|
|
115
|
+
// `ns.<key>` property access is flagged when `ns` is a namespace import.
|
|
116
|
+
func reportImportTarget(ctx *Context, target *shimast.Node, imported, namespaces map[string]bool) {
|
|
117
|
+
stripped := stripParens(target)
|
|
118
|
+
if stripped == nil {
|
|
119
|
+
return
|
|
120
|
+
}
|
|
121
|
+
if name := identifierText(stripped); name != "" {
|
|
122
|
+
if imported[name] {
|
|
123
|
+
ctx.Report(target, "'"+name+"' is read-only.")
|
|
124
|
+
}
|
|
125
|
+
return
|
|
126
|
+
}
|
|
127
|
+
if stripped.Kind == shimast.KindPropertyAccessExpression {
|
|
128
|
+
access := stripped.AsPropertyAccessExpression()
|
|
129
|
+
if access == nil || access.Expression == nil {
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
if ns := identifierText(stripParens(access.Expression)); ns != "" && namespaces[ns] {
|
|
133
|
+
ctx.Report(target, "The members of '"+ns+"' are read-only.")
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
func init() {
|
|
139
|
+
Register(noImportAssign{})
|
|
140
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// noInvalidThis: reject `this` references that have no meaningful
|
|
2
|
+
// binding — that is, `this` used outside any function-like context or
|
|
3
|
+
// class static block. At the top level of a module (and in strict-mode
|
|
4
|
+
// scripts) `this` is `undefined`, so reading from it usually signals a
|
|
5
|
+
// copy-paste from a class method.
|
|
6
|
+
//
|
|
7
|
+
// Arrow functions inherit `this` from their enclosing lexical scope, so
|
|
8
|
+
// the rule walks past arrow boundaries when searching for a binding
|
|
9
|
+
// site. Plain function declarations, function expressions, methods,
|
|
10
|
+
// accessors, constructors, and class static blocks each create their
|
|
11
|
+
// own `this` and stop the walk.
|
|
12
|
+
// https://eslint.org/docs/latest/rules/no-invalid-this
|
|
13
|
+
package linthost
|
|
14
|
+
|
|
15
|
+
import (
|
|
16
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
type noInvalidThis struct{}
|
|
20
|
+
|
|
21
|
+
func (noInvalidThis) Name() string { return "no-invalid-this" }
|
|
22
|
+
func (noInvalidThis) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindThisKeyword} }
|
|
23
|
+
func (noInvalidThis) Check(ctx *Context, node *shimast.Node) {
|
|
24
|
+
if hasThisBindingAncestor(node) {
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
ctx.Report(node, "Unexpected 'this'.")
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// hasThisBindingAncestor reports whether `node` is lexically enclosed by
|
|
31
|
+
// a construct that defines its own `this`. Arrow functions are skipped
|
|
32
|
+
// because they capture `this` from the surrounding scope; the walk only
|
|
33
|
+
// stops on a real binding site or at the SourceFile root.
|
|
34
|
+
func hasThisBindingAncestor(node *shimast.Node) bool {
|
|
35
|
+
for cur := node.Parent; cur != nil; cur = cur.Parent {
|
|
36
|
+
switch cur.Kind {
|
|
37
|
+
case shimast.KindFunctionDeclaration,
|
|
38
|
+
shimast.KindFunctionExpression,
|
|
39
|
+
shimast.KindMethodDeclaration,
|
|
40
|
+
shimast.KindGetAccessor,
|
|
41
|
+
shimast.KindSetAccessor,
|
|
42
|
+
shimast.KindConstructor,
|
|
43
|
+
shimast.KindClassStaticBlockDeclaration:
|
|
44
|
+
return true
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return false
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
func init() {
|
|
51
|
+
Register(noInvalidThis{})
|
|
52
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// noLoopFunc reports a `function` declaration, function expression, or
|
|
2
|
+
// arrow function defined inside the body of a loop. The function value
|
|
3
|
+
// allocated each iteration almost always closes over the loop counter or
|
|
4
|
+
// some other binding that changes between iterations, so a deferred call
|
|
5
|
+
// (timer, microtask, event handler) observes whatever the binding holds
|
|
6
|
+
// at call time — usually the loop's terminal value, never the value the
|
|
7
|
+
// developer reasoned about at the textual position.
|
|
8
|
+
// https://eslint.org/docs/latest/rules/no-loop-func
|
|
9
|
+
//
|
|
10
|
+
// Conservative baseline: every function-like syntactically inside a loop
|
|
11
|
+
// body is flagged. Capture analysis (the rule's full upstream
|
|
12
|
+
// implementation only fires when the function actually closes over a
|
|
13
|
+
// `let` / `var` / `const` declared outside) is deferred; the false-
|
|
14
|
+
// positive rate is acceptable because the fix — hoist the function out
|
|
15
|
+
// of the loop — is almost always the cleaner code in either case.
|
|
16
|
+
//
|
|
17
|
+
// The walk stops at nested loop boundaries — each enclosing loop visits
|
|
18
|
+
// itself once, so an inner loop reports its own nested function-likes
|
|
19
|
+
// and the outer loop only owns the function-likes directly inside it.
|
|
20
|
+
// Inner function-likes are also boundaries: a closure inside an outer
|
|
21
|
+
// function-likes is that inner scope's problem.
|
|
22
|
+
package linthost
|
|
23
|
+
|
|
24
|
+
import (
|
|
25
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
type noLoopFunc struct{}
|
|
29
|
+
|
|
30
|
+
func (noLoopFunc) Name() string { return "no-loop-func" }
|
|
31
|
+
func (noLoopFunc) Visits() []shimast.Kind {
|
|
32
|
+
return []shimast.Kind{
|
|
33
|
+
shimast.KindForStatement,
|
|
34
|
+
shimast.KindForInStatement,
|
|
35
|
+
shimast.KindForOfStatement,
|
|
36
|
+
shimast.KindWhileStatement,
|
|
37
|
+
shimast.KindDoStatement,
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
func (noLoopFunc) Check(ctx *Context, node *shimast.Node) {
|
|
41
|
+
var walk func(n *shimast.Node)
|
|
42
|
+
walk = func(n *shimast.Node) {
|
|
43
|
+
if n == nil {
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
if isFunctionLikeKind(n) {
|
|
47
|
+
ctx.Report(n, "Function declared in a loop closes over the loop's bindings — hoist it out.")
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
if n != node && isLoopKind(n) {
|
|
51
|
+
// Nested loops report their own contents when visited.
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
n.ForEachChild(func(child *shimast.Node) bool {
|
|
55
|
+
walk(child)
|
|
56
|
+
return false
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
node.ForEachChild(func(child *shimast.Node) bool {
|
|
60
|
+
walk(child)
|
|
61
|
+
return false
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// isLoopKind reports whether n is one of the loop statement kinds this
|
|
66
|
+
// rule visits. Used to stop the walk at a nested loop boundary so each
|
|
67
|
+
// loop reports only the function-likes directly inside its own body.
|
|
68
|
+
func isLoopKind(n *shimast.Node) bool {
|
|
69
|
+
if n == nil {
|
|
70
|
+
return false
|
|
71
|
+
}
|
|
72
|
+
switch n.Kind {
|
|
73
|
+
case shimast.KindForStatement,
|
|
74
|
+
shimast.KindForInStatement,
|
|
75
|
+
shimast.KindForOfStatement,
|
|
76
|
+
shimast.KindWhileStatement,
|
|
77
|
+
shimast.KindDoStatement:
|
|
78
|
+
return true
|
|
79
|
+
}
|
|
80
|
+
return false
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
func init() {
|
|
84
|
+
Register(noLoopFunc{})
|
|
85
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// noMagicNumbers reports a numeric literal that appears in a position
|
|
2
|
+
// other than the initializer of a `const` declaration. Magic numbers
|
|
3
|
+
// scattered through expressions make a reader pause: a literal `60`
|
|
4
|
+
// inside a multiplication says nothing about whether it stands for
|
|
5
|
+
// seconds, frames, or items-per-page, while the same number bound to a
|
|
6
|
+
// `const SECONDS_PER_MINUTE = 60` carries its meaning along with it.
|
|
7
|
+
//
|
|
8
|
+
// Conservative baseline:
|
|
9
|
+
//
|
|
10
|
+
// - Three numbers are silently ignored — `0`, `1`, and `-1`. The
|
|
11
|
+
// first two are pervasive in counters and identity-style code; the
|
|
12
|
+
// third is the canonical "not-found" return from `indexOf` and
|
|
13
|
+
// similar APIs. Flagging them produces nothing but noise.
|
|
14
|
+
// - A numeric literal that is the initializer of a `const x = …`
|
|
15
|
+
// declaration is the named binding the rule is asking for, so it
|
|
16
|
+
// is not flagged.
|
|
17
|
+
// - A numeric literal that is the index of a `KindElementAccessExpression`
|
|
18
|
+
// (`arr[0]`, `tuple[3]`) is treated as an array index and ignored;
|
|
19
|
+
// ESLint's `ignoreArrayIndexes` option is on by default here.
|
|
20
|
+
// - A numeric literal that initializes an `enum` member is the
|
|
21
|
+
// binding's value, not a magic number — enums exist precisely to
|
|
22
|
+
// give numeric values names, so the value position is the point of
|
|
23
|
+
// the construct.
|
|
24
|
+
//
|
|
25
|
+
// https://eslint.org/docs/latest/rules/no-magic-numbers
|
|
26
|
+
package linthost
|
|
27
|
+
|
|
28
|
+
import (
|
|
29
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
type noMagicNumbers struct{}
|
|
33
|
+
|
|
34
|
+
func (noMagicNumbers) Name() string { return "no-magic-numbers" }
|
|
35
|
+
func (noMagicNumbers) Visits() []shimast.Kind {
|
|
36
|
+
return []shimast.Kind{shimast.KindNumericLiteral}
|
|
37
|
+
}
|
|
38
|
+
func (noMagicNumbers) Check(ctx *Context, node *shimast.Node) {
|
|
39
|
+
if node == nil {
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
text := numericLiteralText(node)
|
|
43
|
+
if isIgnoredMagicLiteralText(text) {
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
parent := node.Parent
|
|
47
|
+
if parent == nil {
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
// `-N` is a PrefixUnaryExpression whose Operand is the literal. The
|
|
51
|
+
// `-1` ignore list lives on the unary expression's combined text;
|
|
52
|
+
// recognize the negated form here so the rule does not flag the `1`
|
|
53
|
+
// inside `-1`.
|
|
54
|
+
if parent.Kind == shimast.KindPrefixUnaryExpression {
|
|
55
|
+
pre := parent.AsPrefixUnaryExpression()
|
|
56
|
+
if pre != nil && pre.Operator == shimast.KindMinusToken && text == "1" {
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Initializer of a `const x = N` declaration: the named binding the
|
|
61
|
+
// rule wants users to introduce.
|
|
62
|
+
if isConstVariableInitializer(parent, node) {
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
// Enum member value: `enum E { A = 0, B = 1 }` — the literal is
|
|
66
|
+
// the binding's value position, so leave it alone.
|
|
67
|
+
if parent.Kind == shimast.KindEnumMember {
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
// `arr[0]` / `tuple[3]`: numeric index position of an element access.
|
|
71
|
+
if isArrayIndexArgument(parent, node) {
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
ctx.Report(node, "No magic number: "+text+".")
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// isIgnoredMagicLiteralText reports whether the literal text falls into
|
|
78
|
+
// the always-ignored set. `-1` is handled by the caller (the leading
|
|
79
|
+
// minus lives on a PrefixUnaryExpression parent), so the table here only
|
|
80
|
+
// needs the two zero / one shapes.
|
|
81
|
+
func isIgnoredMagicLiteralText(text string) bool {
|
|
82
|
+
switch text {
|
|
83
|
+
case "0", "1":
|
|
84
|
+
return true
|
|
85
|
+
}
|
|
86
|
+
return false
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// isConstVariableInitializer reports whether `literal` sits in the
|
|
90
|
+
// Initializer slot of a `const x = literal` VariableDeclaration. `let`
|
|
91
|
+
// and `var` are deliberately excluded — a `let x = 60` binding can be
|
|
92
|
+
// reassigned, so the number is still magic in the position it was
|
|
93
|
+
// written.
|
|
94
|
+
func isConstVariableInitializer(parent, literal *shimast.Node) bool {
|
|
95
|
+
if parent == nil || parent.Kind != shimast.KindVariableDeclaration {
|
|
96
|
+
return false
|
|
97
|
+
}
|
|
98
|
+
decl := parent.AsVariableDeclaration()
|
|
99
|
+
if decl == nil || decl.Initializer != literal {
|
|
100
|
+
return false
|
|
101
|
+
}
|
|
102
|
+
return shimast.IsConst(parent)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// isArrayIndexArgument reports whether `literal` sits in the
|
|
106
|
+
// ArgumentExpression slot of a `target[literal]` ElementAccessExpression.
|
|
107
|
+
// ESLint calls this `ignoreArrayIndexes`; the rule's conservative
|
|
108
|
+
// baseline enables it because mixing numeric subscripts with renamed
|
|
109
|
+
// constants reads worse than the literal.
|
|
110
|
+
func isArrayIndexArgument(parent, literal *shimast.Node) bool {
|
|
111
|
+
if parent == nil || parent.Kind != shimast.KindElementAccessExpression {
|
|
112
|
+
return false
|
|
113
|
+
}
|
|
114
|
+
access := parent.AsElementAccessExpression()
|
|
115
|
+
if access == nil {
|
|
116
|
+
return false
|
|
117
|
+
}
|
|
118
|
+
return access.ArgumentExpression == literal
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
func init() {
|
|
122
|
+
Register(noMagicNumbers{})
|
|
123
|
+
}
|