@ttsc/lint 0.13.1 → 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 +35 -10
- package/lib/index.js.map +1 -1
- package/lib/structures/ITtscLintConfig.d.ts +12 -6
- package/lib/structures/{ITtscLintFormatConfig.d.ts → ITtscLintFormat.d.ts} +2 -2
- package/lib/structures/{TtscLintRuleMap.js → ITtscLintFormat.js} +1 -1
- package/lib/structures/ITtscLintFormat.js.map +1 -0
- package/lib/structures/TtscLintRuleSetting.d.ts +49 -0
- package/lib/structures/{TtscLintRuleOptions.js → TtscLintRuleSetting.js} +1 -1
- package/lib/structures/TtscLintRuleSetting.js.map +1 -0
- package/lib/structures/index.d.ts +3 -4
- package/lib/structures/index.js +3 -4
- package/lib/structures/index.js.map +1 -1
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.d.ts +104 -0
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js +14 -0
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintBoundariesRules.d.ts +79 -0
- package/lib/structures/rules/ITtscLintBoundariesRules.js +3 -0
- package/lib/structures/rules/ITtscLintBoundariesRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintContributorRules.d.ts +17 -0
- package/lib/structures/rules/ITtscLintContributorRules.js +3 -0
- package/lib/structures/rules/ITtscLintContributorRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintCoreRules.d.ts +1257 -0
- package/lib/structures/{ITtscLintFormatConfig.js → rules/ITtscLintCoreRules.js} +1 -1
- package/lib/structures/rules/ITtscLintCoreRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintCypressRuleOptions.d.ts +17 -0
- package/lib/structures/rules/ITtscLintCypressRuleOptions.js +10 -0
- package/lib/structures/rules/ITtscLintCypressRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintCypressRules.d.ts +129 -0
- package/lib/structures/rules/ITtscLintCypressRules.js +3 -0
- package/lib/structures/rules/ITtscLintCypressRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintFunctionalRuleOptions.d.ts +157 -0
- package/lib/structures/rules/ITtscLintFunctionalRuleOptions.js +13 -0
- package/lib/structures/rules/ITtscLintFunctionalRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintFunctionalRules.d.ts +167 -0
- package/lib/structures/rules/ITtscLintFunctionalRules.js +3 -0
- package/lib/structures/rules/ITtscLintFunctionalRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintJestRules.d.ts +201 -0
- package/lib/structures/rules/ITtscLintJestRules.js +3 -0
- package/lib/structures/rules/ITtscLintJestRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintJsdocRules.d.ts +140 -0
- package/lib/structures/rules/ITtscLintJsdocRules.js +3 -0
- package/lib/structures/rules/ITtscLintJsdocRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintJsxA11yRules.d.ts +302 -0
- package/lib/structures/rules/ITtscLintJsxA11yRules.js +3 -0
- package/lib/structures/rules/ITtscLintJsxA11yRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintNextjsRules.d.ts +185 -0
- package/lib/structures/rules/ITtscLintNextjsRules.js +3 -0
- package/lib/structures/rules/ITtscLintNextjsRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintPlaywrightRules.d.ts +330 -0
- package/lib/structures/rules/ITtscLintPlaywrightRules.js +3 -0
- package/lib/structures/rules/ITtscLintPlaywrightRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintPromiseRules.d.ts +188 -0
- package/lib/structures/rules/ITtscLintPromiseRules.js +3 -0
- package/lib/structures/rules/ITtscLintPromiseRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintReactPerfRuleOptions.d.ts +18 -0
- package/lib/structures/rules/ITtscLintReactPerfRuleOptions.js +8 -0
- package/lib/structures/rules/ITtscLintReactPerfRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintReactPerfRules.d.ts +51 -0
- package/lib/structures/rules/ITtscLintReactPerfRules.js +3 -0
- package/lib/structures/rules/ITtscLintReactPerfRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintReactRuleOptions.d.ts +39 -0
- package/lib/structures/rules/ITtscLintReactRuleOptions.js +12 -0
- package/lib/structures/rules/ITtscLintReactRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintReactRules.d.ts +289 -0
- package/lib/structures/rules/ITtscLintReactRules.js +3 -0
- package/lib/structures/rules/ITtscLintReactRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintRegexpRules.d.ts +190 -0
- package/lib/structures/rules/ITtscLintRegexpRules.js +3 -0
- package/lib/structures/rules/ITtscLintRegexpRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintRuleOptionsMap.d.ts +66 -0
- package/lib/structures/rules/ITtscLintRuleOptionsMap.js +3 -0
- package/lib/structures/rules/ITtscLintRuleOptionsMap.js.map +1 -0
- package/lib/structures/rules/ITtscLintRules.d.ts +55 -0
- package/lib/structures/{TtscLintRule.js → rules/ITtscLintRules.js} +1 -1
- package/lib/structures/rules/ITtscLintRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintSecurityRules.d.ts +148 -0
- package/lib/structures/rules/ITtscLintSecurityRules.js +3 -0
- package/lib/structures/rules/ITtscLintSecurityRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintSolidRules.d.ts +181 -0
- package/lib/structures/rules/ITtscLintSolidRules.js +3 -0
- package/lib/structures/rules/ITtscLintSolidRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintStorybookRuleOptions.d.ts +21 -0
- package/lib/structures/rules/ITtscLintStorybookRuleOptions.js +9 -0
- package/lib/structures/rules/ITtscLintStorybookRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintStorybookRules.d.ts +174 -0
- package/lib/structures/rules/ITtscLintStorybookRules.js +3 -0
- package/lib/structures/rules/ITtscLintStorybookRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintTanstackQueryRules.d.ts +94 -0
- package/lib/structures/rules/ITtscLintTanstackQueryRules.js +3 -0
- package/lib/structures/rules/ITtscLintTanstackQueryRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.d.ts +22 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.js +10 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRules.d.ts +310 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRules.js +3 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintTypeScriptRules.d.ts +1132 -0
- package/lib/structures/rules/ITtscLintTypeScriptRules.js +3 -0
- package/lib/structures/rules/ITtscLintTypeScriptRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintUnicornRules.d.ts +997 -0
- package/lib/structures/rules/ITtscLintUnicornRules.js +3 -0
- package/lib/structures/rules/ITtscLintUnicornRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintVitestRules.d.ts +141 -0
- package/lib/structures/rules/ITtscLintVitestRules.js +3 -0
- package/lib/structures/rules/ITtscLintVitestRules.js.map +1 -0
- package/lib/structures/rules/index.d.ts +31 -0
- package/lib/structures/rules/index.js +48 -0
- package/lib/structures/rules/index.js.map +1 -0
- package/linthost/ast_helpers.go +30 -5
- package/linthost/config.go +48 -17
- package/linthost/config_format.go +9 -9
- package/linthost/directives.go +67 -25
- package/linthost/dispatch.go +14 -3
- package/linthost/engine.go +152 -31
- package/linthost/fix.go +2 -2
- package/linthost/lsp.go +747 -0
- package/linthost/print_dispatch.go +2 -2
- package/linthost/print_nodes_function.go +2 -2
- package/linthost/print_nodes_object.go +1 -1
- package/linthost/rule_names.go +14 -0
- package/linthost/rules_arrays.go +2 -2
- package/linthost/rules_boundaries.go +532 -0
- package/linthost/rules_camelcase.go +133 -0
- package/linthost/rules_complexity.go +94 -0
- package/linthost/rules_consistent_return.go +130 -0
- package/linthost/rules_console.go +1 -1
- package/linthost/rules_core_extra.go +739 -0
- package/linthost/rules_curly.go +70 -0
- package/linthost/rules_cypress.go +608 -0
- package/linthost/rules_debugger.go +2 -2
- package/linthost/rules_default_case.go +39 -0
- package/linthost/rules_default_case_last.go +46 -0
- package/linthost/rules_dupes.go +3 -3
- package/linthost/rules_empty.go +3 -3
- package/linthost/rules_escape.go +44 -24
- package/linthost/rules_eval.go +2 -2
- package/linthost/rules_finally.go +2 -2
- package/linthost/rules_format_jsdoc.go +1 -1
- package/linthost/rules_format_print_width.go +9 -9
- package/linthost/rules_format_quotes.go +1 -1
- package/linthost/rules_format_semi.go +1 -1
- package/linthost/rules_format_sort_imports.go +1 -1
- package/linthost/rules_format_trailing_comma.go +1 -1
- package/linthost/rules_functional.go +967 -0
- package/linthost/rules_gap.go +24 -45
- package/linthost/rules_grouped_accessor_pairs.go +87 -0
- package/linthost/rules_guard_for_in.go +198 -0
- package/linthost/rules_id_length.go +77 -0
- package/linthost/rules_imports.go +70 -2
- package/linthost/rules_init_declarations.go +53 -0
- package/linthost/rules_jest.go +618 -0
- package/linthost/rules_jsdoc.go +502 -0
- package/linthost/rules_jsx_a11y.go +1264 -0
- package/linthost/rules_logic.go +12 -12
- package/linthost/rules_loops.go +1 -1
- package/linthost/rules_max_classes_per_file.go +58 -0
- package/linthost/rules_max_depth.go +83 -0
- package/linthost/rules_max_lines.go +101 -0
- package/linthost/rules_max_lines_per_function.go +57 -0
- package/linthost/rules_max_nested_callbacks.go +61 -0
- package/linthost/rules_max_params.go +49 -0
- package/linthost/rules_max_statements.go +59 -0
- package/linthost/rules_misc.go +1 -1
- package/linthost/rules_nextjs.go +697 -0
- package/linthost/rules_no_else_return.go +75 -0
- package/linthost/rules_no_empty_named_blocks.go +91 -0
- package/linthost/rules_no_extend_native.go +51 -0
- package/linthost/rules_no_import_assign.go +140 -0
- package/linthost/rules_no_invalid_this.go +52 -0
- package/linthost/rules_no_loop_func.go +85 -0
- package/linthost/rules_no_magic_numbers.go +123 -0
- package/linthost/rules_no_mixed_operators.go +80 -0
- package/linthost/rules_no_param_reassign.go +98 -0
- package/linthost/rules_no_redeclare.go +270 -0
- package/linthost/rules_no_restricted_imports.go +105 -0
- package/linthost/rules_no_restricted_syntax.go +49 -0
- package/linthost/rules_no_shadow.go +147 -0
- package/linthost/rules_no_unreachable.go +77 -0
- package/linthost/rules_no_useless_assignment.go +120 -0
- package/linthost/rules_no_useless_constructor.go +245 -0
- package/linthost/rules_no_useless_return.go +51 -0
- package/linthost/rules_params.go +1 -1
- package/linthost/rules_playwright.go +788 -0
- package/linthost/rules_prefer_arrow_callback.go +124 -0
- package/linthost/rules_prefer_destructuring.go +98 -0
- package/linthost/rules_prefer_named_capture_group.go +129 -0
- package/linthost/rules_prefer_rest_params.go +94 -0
- package/linthost/rules_problems.go +41 -30
- package/linthost/rules_promise.go +1128 -73
- package/linthost/rules_protos.go +2 -2
- package/linthost/rules_react.go +773 -0
- package/linthost/rules_react_extras.go +227 -0
- package/linthost/rules_react_hooks.go +848 -0
- package/linthost/rules_react_perf.go +293 -0
- package/linthost/rules_react_refresh.go +583 -0
- package/linthost/rules_regexp.go +410 -0
- package/linthost/rules_security.go +830 -0
- package/linthost/rules_self.go +2 -2
- package/linthost/rules_solid.go +1073 -0
- package/linthost/rules_sort_imports.go +69 -0
- package/linthost/rules_sort_keys.go +134 -0
- package/linthost/rules_storybook.go +1176 -0
- package/linthost/rules_strings.go +4 -4
- package/linthost/rules_suggestions.go +38 -38
- package/linthost/rules_tanstack_query.go +844 -0
- package/linthost/rules_testing_library.go +1204 -0
- package/linthost/rules_throw.go +1 -1
- package/linthost/rules_ts.go +19 -19
- package/linthost/rules_ts_async.go +399 -0
- package/linthost/rules_ts_class_literal_property_style.go +115 -0
- package/linthost/rules_ts_consistent_type_exports.go +256 -0
- package/linthost/rules_ts_explicit_function_return_type.go +67 -0
- package/linthost/rules_ts_extra.go +155 -36
- package/linthost/rules_ts_no_base_to_string.go +218 -0
- package/linthost/rules_ts_no_confusing_void.go +72 -0
- package/linthost/rules_ts_no_deprecated.go +195 -0
- package/linthost/rules_ts_no_for_in_array.go +84 -0
- package/linthost/rules_ts_no_magic_numbers.go +124 -0
- package/linthost/rules_ts_no_meaningless_void_operator.go +84 -0
- package/linthost/rules_ts_no_misused_spread.go +104 -0
- package/linthost/rules_ts_no_redundant_type_constituents.go +113 -0
- package/linthost/rules_ts_no_restricted_types.go +62 -0
- package/linthost/rules_ts_no_unnecessary_boolean_literal_compare.go +129 -0
- package/linthost/rules_ts_no_unnecessary_condition.go +250 -0
- package/linthost/rules_ts_no_unnecessary_qualifier.go +118 -0
- package/linthost/rules_ts_no_unnecessary_template_expression.go +178 -0
- package/linthost/rules_ts_no_unnecessary_type_arguments.go +234 -0
- package/linthost/rules_ts_no_unnecessary_type_assertion.go +157 -0
- package/linthost/rules_ts_no_unsafe_argument.go +82 -0
- package/linthost/rules_ts_no_unsafe_assignment.go +102 -0
- package/linthost/rules_ts_no_unsafe_call.go +82 -0
- package/linthost/rules_ts_no_unsafe_enum_comparison.go +235 -0
- package/linthost/rules_ts_no_unsafe_member_access.go +58 -0
- package/linthost/rules_ts_no_unsafe_return.go +126 -0
- package/linthost/rules_ts_no_unsafe_unary_minus.go +81 -0
- package/linthost/rules_ts_no_useless_constructor.go +52 -0
- package/linthost/rules_ts_non_nullable_type_assertion_style.go +108 -0
- package/linthost/rules_ts_parameter_properties.go +38 -0
- package/linthost/rules_ts_prefer_find.go +178 -0
- package/linthost/rules_ts_prefer_includes.go +255 -0
- package/linthost/rules_ts_prefer_nullish_coalescing.go +104 -0
- package/linthost/rules_ts_prefer_optional_chain.go +228 -0
- package/linthost/rules_ts_prefer_promise_reject_errors.go +176 -0
- package/linthost/rules_ts_prefer_readonly.go +73 -0
- package/linthost/rules_ts_prefer_reduce_type_parameter.go +116 -0
- package/linthost/rules_ts_prefer_regexp_exec.go +122 -0
- package/linthost/rules_ts_prefer_return_this_type.go +135 -0
- package/linthost/rules_ts_prefer_string_starts_ends_with.go +360 -0
- package/linthost/rules_ts_promise_function_async.go +77 -0
- package/linthost/rules_ts_related_getter_setter_pairs.go +113 -0
- package/linthost/rules_ts_require_array_sort_compare.go +96 -0
- package/linthost/rules_ts_restrict_plus_operands.go +127 -0
- package/linthost/rules_ts_restrict_template_expressions.go +95 -0
- package/linthost/rules_ts_simple.go +387 -0
- package/linthost/rules_ts_sort_type_constituents.go +144 -0
- package/linthost/rules_ts_strict_boolean_expressions.go +157 -0
- package/linthost/rules_ts_switch_exhaustiveness_check.go +147 -0
- package/linthost/rules_ts_unbound_method.go +126 -0
- package/linthost/rules_tsdoc.go +136 -0
- package/linthost/rules_unicorn_better_regex.go +27 -0
- package/linthost/rules_unicorn_catch_error_name.go +46 -0
- package/linthost/rules_unicorn_consistent_assert.go +47 -0
- package/linthost/rules_unicorn_consistent_date_clone.go +54 -0
- package/linthost/rules_unicorn_consistent_destructuring.go +25 -0
- package/linthost/rules_unicorn_consistent_empty_array_spread.go +62 -0
- package/linthost/rules_unicorn_consistent_existence_index_check.go +80 -0
- package/linthost/rules_unicorn_consistent_function_scoping.go +25 -0
- package/linthost/rules_unicorn_consistent_template_literal_escape.go +25 -0
- package/linthost/rules_unicorn_custom_error_definition.go +138 -0
- package/linthost/rules_unicorn_empty_brace_spaces.go +73 -0
- package/linthost/rules_unicorn_error_message.go +64 -0
- package/linthost/rules_unicorn_escape_case.go +51 -0
- package/linthost/rules_unicorn_expiring_todo_comments.go +78 -0
- package/linthost/rules_unicorn_explicit_length_check.go +88 -0
- package/linthost/rules_unicorn_filename_case.go +29 -0
- package/linthost/rules_unicorn_import_style.go +28 -0
- package/linthost/rules_unicorn_isolated_functions.go +29 -0
- package/linthost/rules_unicorn_new_for_builtins.go +87 -0
- package/linthost/rules_unicorn_no_abusive_eslint_disable.go +63 -0
- package/linthost/rules_unicorn_no_accessor_recursion.go +115 -0
- package/linthost/rules_unicorn_no_anonymous_default_export.go +74 -0
- package/linthost/rules_unicorn_no_array_callback_reference.go +65 -0
- package/linthost/rules_unicorn_no_array_for_each.go +40 -0
- package/linthost/rules_unicorn_no_array_method_this_argument.go +61 -0
- package/linthost/rules_unicorn_no_array_reduce.go +41 -0
- package/linthost/rules_unicorn_no_array_reverse.go +44 -0
- package/linthost/rules_unicorn_no_array_sort.go +43 -0
- package/linthost/rules_unicorn_no_await_expression_member.go +40 -0
- package/linthost/rules_unicorn_no_await_in_promise_methods.go +69 -0
- package/linthost/rules_unicorn_no_console_spaces.go +61 -0
- package/linthost/rules_unicorn_no_document_cookie.go +41 -0
- package/linthost/rules_unicorn_no_empty_file.go +44 -0
- package/linthost/rules_unicorn_no_for_loop.go +102 -0
- package/linthost/rules_unicorn_no_hex_escape.go +42 -0
- package/linthost/rules_unicorn_no_immediate_mutation.go +90 -0
- package/linthost/rules_unicorn_no_instanceof_builtins.go +66 -0
- package/linthost/rules_unicorn_no_invalid_fetch_options.go +79 -0
- package/linthost/rules_unicorn_no_invalid_remove_event_listener.go +51 -0
- package/linthost/rules_unicorn_no_keyword_prefix.go +101 -0
- package/linthost/rules_unicorn_no_lonely_if.go +44 -0
- package/linthost/rules_unicorn_no_magic_array_flat_depth.go +51 -0
- package/linthost/rules_unicorn_no_named_default.go +54 -0
- package/linthost/rules_unicorn_no_negated_condition.go +85 -0
- package/linthost/rules_unicorn_no_negation_in_equality_check.go +50 -0
- package/linthost/rules_unicorn_no_nested_ternary.go +43 -0
- package/linthost/rules_unicorn_no_new_array.go +30 -0
- package/linthost/rules_unicorn_no_new_buffer.go +31 -0
- package/linthost/rules_unicorn_no_null.go +24 -0
- package/linthost/rules_unicorn_no_object_as_default_parameter.go +48 -0
- package/linthost/rules_unicorn_no_process_exit.go +43 -0
- package/linthost/rules_unicorn_no_single_promise_in_promise_methods.go +59 -0
- package/linthost/rules_unicorn_no_static_only_class.go +56 -0
- package/linthost/rules_unicorn_no_thenable.go +74 -0
- package/linthost/rules_unicorn_no_this_assignment.go +35 -0
- package/linthost/rules_unicorn_no_typeof_undefined.go +58 -0
- package/linthost/rules_unicorn_no_unnecessary_array_flat_depth.go +49 -0
- package/linthost/rules_unicorn_no_unnecessary_array_splice_count.go +70 -0
- package/linthost/rules_unicorn_no_unnecessary_await.go +51 -0
- package/linthost/rules_unicorn_no_unnecessary_polyfills.go +32 -0
- package/linthost/rules_unicorn_no_unnecessary_slice_end.go +48 -0
- package/linthost/rules_unicorn_no_unreadable_array_destructuring.go +115 -0
- package/linthost/rules_unicorn_no_unreadable_iife.go +50 -0
- package/linthost/rules_unicorn_no_unused_properties.go +30 -0
- package/linthost/rules_unicorn_no_useless_collection_argument.go +63 -0
- package/linthost/rules_unicorn_no_useless_error_capture_stack_trace.go +46 -0
- package/linthost/rules_unicorn_no_useless_fallback_in_spread.go +81 -0
- package/linthost/rules_unicorn_no_useless_iterator_to_array.go +72 -0
- package/linthost/rules_unicorn_no_useless_length_check.go +144 -0
- package/linthost/rules_unicorn_no_useless_promise_resolve_reject.go +81 -0
- package/linthost/rules_unicorn_no_useless_spread.go +67 -0
- package/linthost/rules_unicorn_no_useless_switch_case.go +55 -0
- package/linthost/rules_unicorn_no_useless_undefined.go +55 -0
- package/linthost/rules_unicorn_no_zero_fractions.go +52 -0
- package/linthost/rules_unicorn_number_literal_case.go +69 -0
- package/linthost/rules_unicorn_numeric_separators_style.go +75 -0
- package/linthost/rules_unicorn_prefer_add_event_listener.go +66 -0
- package/linthost/rules_unicorn_prefer_array_find.go +51 -0
- package/linthost/rules_unicorn_prefer_array_flat.go +52 -0
- package/linthost/rules_unicorn_prefer_array_flat_map.go +63 -0
- package/linthost/rules_unicorn_prefer_array_index_of.go +147 -0
- package/linthost/rules_unicorn_prefer_array_some.go +67 -0
- package/linthost/rules_unicorn_prefer_at.go +77 -0
- package/linthost/rules_unicorn_prefer_bigint_literals.go +77 -0
- package/linthost/rules_unicorn_prefer_blob_reading_methods.go +44 -0
- package/linthost/rules_unicorn_prefer_class_fields.go +93 -0
- package/linthost/rules_unicorn_prefer_classlist_toggle.go +120 -0
- package/linthost/rules_unicorn_prefer_code_point.go +49 -0
- package/linthost/rules_unicorn_prefer_date_now.go +78 -0
- package/linthost/rules_unicorn_prefer_default_parameters.go +144 -0
- package/linthost/rules_unicorn_prefer_dom_node_append.go +40 -0
- package/linthost/rules_unicorn_prefer_dom_node_dataset.go +55 -0
- package/linthost/rules_unicorn_prefer_dom_node_remove.go +41 -0
- package/linthost/rules_unicorn_prefer_dom_node_text_content.go +37 -0
- package/linthost/rules_unicorn_prefer_event_target.go +36 -0
- package/linthost/rules_unicorn_prefer_export_from.go +129 -0
- package/linthost/rules_unicorn_prefer_global_this.go +127 -0
- package/linthost/rules_unicorn_prefer_import_meta_properties.go +66 -0
- package/linthost/rules_unicorn_prefer_includes.go +149 -0
- package/linthost/rules_unicorn_prefer_json_parse_buffer.go +65 -0
- package/linthost/rules_unicorn_prefer_keyboard_event_key.go +38 -0
- package/linthost/rules_unicorn_prefer_logical_operator_over_ternary.go +48 -0
- package/linthost/rules_unicorn_prefer_math_min_max.go +60 -0
- package/linthost/rules_unicorn_prefer_math_trunc.go +62 -0
- package/linthost/rules_unicorn_prefer_modern_dom_apis.go +47 -0
- package/linthost/rules_unicorn_prefer_modern_math_apis.go +70 -0
- package/linthost/rules_unicorn_prefer_module.go +50 -0
- package/linthost/rules_unicorn_prefer_native_coercion_functions.go +114 -0
- package/linthost/rules_unicorn_prefer_negative_index.go +74 -0
- package/linthost/rules_unicorn_prefer_node_protocol.go +122 -0
- package/linthost/rules_unicorn_prefer_number_properties.go +88 -0
- package/linthost/rules_unicorn_prefer_object_from_entries.go +55 -0
- package/linthost/rules_unicorn_prefer_optional_catch_binding.go +62 -0
- package/linthost/rules_unicorn_prefer_prototype_methods.go +54 -0
- package/linthost/rules_unicorn_prefer_query_selector.go +56 -0
- package/linthost/rules_unicorn_prefer_reflect_apply.go +36 -0
- package/linthost/rules_unicorn_prefer_regexp_test_rule.go +80 -0
- package/linthost/rules_unicorn_prefer_response_static_json.go +53 -0
- package/linthost/rules_unicorn_prefer_set_has.go +42 -0
- package/linthost/rules_unicorn_prefer_set_size.go +48 -0
- package/linthost/rules_unicorn_prefer_simple_condition_first.go +34 -0
- package/linthost/rules_unicorn_prefer_single_call.go +96 -0
- package/linthost/rules_unicorn_prefer_spread.go +51 -0
- package/linthost/rules_unicorn_prefer_string_raw.go +43 -0
- package/linthost/rules_unicorn_prefer_string_replace_all.go +95 -0
- package/linthost/rules_unicorn_prefer_string_slice.go +43 -0
- package/linthost/rules_unicorn_prefer_string_starts_ends_with.go +148 -0
- package/linthost/rules_unicorn_prefer_string_trim_start_end.go +48 -0
- package/linthost/rules_unicorn_prefer_structured_clone.go +71 -0
- package/linthost/rules_unicorn_prefer_switch.go +103 -0
- package/linthost/rules_unicorn_prefer_ternary.go +71 -0
- package/linthost/rules_unicorn_prefer_top_level_await.go +72 -0
- package/linthost/rules_unicorn_prefer_type_error.go +127 -0
- package/linthost/rules_unicorn_prevent_abbreviations.go +127 -0
- package/linthost/rules_unicorn_relative_url_style.go +49 -0
- package/linthost/rules_unicorn_require_array_join_separator.go +45 -0
- package/linthost/rules_unicorn_require_module_attributes.go +54 -0
- package/linthost/rules_unicorn_require_module_specifiers.go +55 -0
- package/linthost/rules_unicorn_require_number_to_fixed_digits_argument.go +43 -0
- package/linthost/rules_unicorn_require_post_message_target_origin.go +44 -0
- package/linthost/rules_unicorn_string_content.go +27 -0
- package/linthost/rules_unicorn_switch_case_braces.go +42 -0
- package/linthost/rules_unicorn_switch_case_break_position.go +31 -0
- package/linthost/rules_unicorn_template_indent.go +28 -0
- package/linthost/rules_unicorn_text_encoding_identifier_case.go +72 -0
- package/linthost/rules_unicorn_throw_new_error.go +61 -0
- package/linthost/rules_var.go +4 -4
- package/linthost/rules_vitest.go +568 -0
- package/package.json +3 -3
- package/plugin/main.go +49 -3
- package/rule/astutil/astutil.go +10 -3
- package/rule/rule.go +12 -10
- package/src/defaultFormat.ts +11 -8
- package/src/index.ts +40 -16
- package/src/structures/ITtscLintConfig.ts +12 -6
- package/src/structures/{ITtscLintFormatConfig.ts → ITtscLintFormat.ts} +2 -2
- package/src/structures/TtscLintRuleSetting.ts +55 -0
- package/src/structures/index.ts +3 -4
- package/src/structures/rules/ITtscLintBoundariesRuleOptions.ts +128 -0
- package/src/structures/rules/ITtscLintBoundariesRules.ts +95 -0
- package/src/structures/rules/ITtscLintContributorRules.ts +21 -0
- package/src/structures/rules/ITtscLintCoreRules.ts +1406 -0
- package/src/structures/rules/ITtscLintCypressRuleOptions.ts +18 -0
- package/src/structures/rules/ITtscLintCypressRules.ts +145 -0
- package/src/structures/rules/ITtscLintFunctionalRuleOptions.ts +213 -0
- package/src/structures/rules/ITtscLintFunctionalRules.ts +202 -0
- package/src/structures/rules/ITtscLintJestRules.ts +220 -0
- package/src/structures/rules/ITtscLintJsdocRules.ts +153 -0
- package/src/structures/rules/ITtscLintJsxA11yRules.ts +339 -0
- package/src/structures/rules/ITtscLintNextjsRules.ts +206 -0
- package/src/structures/rules/ITtscLintPlaywrightRules.ts +361 -0
- package/src/structures/rules/ITtscLintPromiseRules.ts +205 -0
- package/src/structures/rules/ITtscLintReactPerfRuleOptions.ts +19 -0
- package/src/structures/rules/ITtscLintReactPerfRules.ts +55 -0
- package/src/structures/rules/ITtscLintReactRuleOptions.ts +43 -0
- package/src/structures/rules/ITtscLintReactRules.ts +321 -0
- package/src/structures/rules/ITtscLintRegexpRules.ts +212 -0
- package/src/structures/rules/ITtscLintRuleOptionsMap.ts +89 -0
- package/src/structures/rules/ITtscLintRules.ts +77 -0
- package/src/structures/rules/ITtscLintSecurityRules.ts +162 -0
- package/src/structures/rules/ITtscLintSolidRules.ts +202 -0
- package/src/structures/rules/ITtscLintStorybookRuleOptions.ts +23 -0
- package/src/structures/rules/ITtscLintStorybookRules.ts +193 -0
- package/src/structures/rules/ITtscLintTanstackQueryRules.ts +102 -0
- package/src/structures/rules/ITtscLintTestingLibraryRuleOptions.ts +24 -0
- package/src/structures/rules/ITtscLintTestingLibraryRules.ts +342 -0
- package/src/structures/rules/ITtscLintTypeScriptRules.ts +1230 -0
- package/src/structures/rules/ITtscLintUnicornRules.ts +1143 -0
- package/src/structures/rules/ITtscLintVitestRules.ts +154 -0
- package/src/structures/rules/index.ts +31 -0
- package/lib/structures/ITtscLintFormatConfig.js.map +0 -1
- package/lib/structures/TtscLintRule.d.ts +0 -17
- package/lib/structures/TtscLintRule.js.map +0 -1
- package/lib/structures/TtscLintRuleMap.d.ts +0 -46
- package/lib/structures/TtscLintRuleMap.js.map +0 -1
- package/lib/structures/TtscLintRuleOptions.d.ts +0 -137
- package/lib/structures/TtscLintRuleOptions.js.map +0 -1
- package/src/structures/TtscLintRule.ts +0 -160
- package/src/structures/TtscLintRuleMap.ts +0 -55
- package/src/structures/TtscLintRuleOptions.ts +0 -151
package/linthost/directives.go
CHANGED
|
@@ -34,8 +34,9 @@ const (
|
|
|
34
34
|
|
|
35
35
|
// lintDirective is the parsed representation of one directive comment.
|
|
36
36
|
type lintDirective struct {
|
|
37
|
-
kind
|
|
38
|
-
rules
|
|
37
|
+
kind lintDirectiveKind
|
|
38
|
+
rules lintDirectiveRules
|
|
39
|
+
ruleList []string
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
// lintDirectiveRules holds the rule scope of a directive. When `all` is
|
|
@@ -55,13 +56,22 @@ type lintDirectiveEvent struct {
|
|
|
55
56
|
on bool
|
|
56
57
|
}
|
|
57
58
|
|
|
59
|
+
// lintDirectiveRecord preserves the per-directive rule list so the engine
|
|
60
|
+
// can surface unknown rule names referenced by `// eslint-disable*` comments
|
|
61
|
+
// (see `Engine.collectUnknownDirectiveRules`). The suppression path itself
|
|
62
|
+
// only needs `rules`; this record exists purely for that diagnostic pass.
|
|
63
|
+
type lintDirectiveRecord struct {
|
|
64
|
+
ruleList []string
|
|
65
|
+
}
|
|
66
|
+
|
|
58
67
|
// lintInlineDirectives accumulates the per-file directive information
|
|
59
68
|
// extracted by parseLintInlineDirectives. `lines` maps a zero-based line
|
|
60
69
|
// number to any disable-line / disable-next-line directives on that line.
|
|
61
70
|
// `events` is the ordered list of range-style disable/enable transitions.
|
|
62
71
|
type lintInlineDirectives struct {
|
|
63
|
-
lines
|
|
64
|
-
events
|
|
72
|
+
lines map[int][]lintDirectiveRules
|
|
73
|
+
events []lintDirectiveEvent
|
|
74
|
+
records []lintDirectiveRecord
|
|
65
75
|
}
|
|
66
76
|
|
|
67
77
|
// lintDisableState tracks the cumulative suppress/allow state as
|
|
@@ -75,11 +85,14 @@ type lintDisableState struct {
|
|
|
75
85
|
enabledInAll map[string]struct{}
|
|
76
86
|
}
|
|
77
87
|
|
|
78
|
-
|
|
88
|
+
// filterInlineDisabledFindingsWithDirectives drops findings suppressed by
|
|
89
|
+
// the directive set passed in. The caller is expected to have parsed
|
|
90
|
+
// directives once via parseLintInlineDirectives and reuse them for any
|
|
91
|
+
// other passes (e.g., Engine.collectUnknownDirectiveRules).
|
|
92
|
+
func filterInlineDisabledFindingsWithDirectives(file *shimast.SourceFile, findings []*Finding, directives *lintInlineDirectives) []*Finding {
|
|
79
93
|
if len(findings) == 0 || file == nil {
|
|
80
94
|
return findings
|
|
81
95
|
}
|
|
82
|
-
directives := parseLintInlineDirectives(file)
|
|
83
96
|
if directives.empty() {
|
|
84
97
|
return findings
|
|
85
98
|
}
|
|
@@ -111,8 +124,19 @@ func parseLintInlineDirectives(file *shimast.SourceFile) *lintInlineDirectives {
|
|
|
111
124
|
directives := &lintInlineDirectives{
|
|
112
125
|
lines: make(map[int][]lintDirectiveRules),
|
|
113
126
|
}
|
|
127
|
+
// Cheap byte-scan short-circuit: a file with no `-disable` or
|
|
128
|
+
// `-enable` substring cannot contain any recognized directive
|
|
129
|
+
// (`eslint-disable`, `lint-disable`, `eslint-enable`, `lint-enable`
|
|
130
|
+
// all match one of these). Running the full TypeScript scanner over
|
|
131
|
+
// every file just to find comments accounts for ~15 % of the lint
|
|
132
|
+
// engine's CPU on directive-free codebases; the substring check
|
|
133
|
+
// turns that into ~50 ns regardless of file size.
|
|
134
|
+
text := file.Text()
|
|
135
|
+
if !strings.Contains(text, "-disable") && !strings.Contains(text, "-enable") {
|
|
136
|
+
return directives
|
|
137
|
+
}
|
|
114
138
|
scanner := shimscanner.NewScanner()
|
|
115
|
-
scanner.SetText(
|
|
139
|
+
scanner.SetText(text)
|
|
116
140
|
scanner.SetSkipTrivia(false)
|
|
117
141
|
|
|
118
142
|
// templateBraceDepth tracks `{` nesting inside each open template
|
|
@@ -186,6 +210,9 @@ scan:
|
|
|
186
210
|
on: false,
|
|
187
211
|
})
|
|
188
212
|
}
|
|
213
|
+
directives.records = append(directives.records, lintDirectiveRecord{
|
|
214
|
+
ruleList: append([]string(nil), directive.ruleList...),
|
|
215
|
+
})
|
|
189
216
|
}
|
|
190
217
|
return directives
|
|
191
218
|
}
|
|
@@ -193,7 +220,7 @@ scan:
|
|
|
193
220
|
// empty reports whether no directives were found in the file, allowing the
|
|
194
221
|
// caller to skip the filtering step entirely.
|
|
195
222
|
func (d *lintInlineDirectives) empty() bool {
|
|
196
|
-
return d == nil || (len(d.lines) == 0 && len(d.events) == 0)
|
|
223
|
+
return d == nil || (len(d.lines) == 0 && len(d.events) == 0 && len(d.records) == 0)
|
|
197
224
|
}
|
|
198
225
|
|
|
199
226
|
// suppresses reports whether the directive set causes `finding` to be
|
|
@@ -259,8 +286,11 @@ func (s *lintDisableState) apply(event lintDirectiveEvent) {
|
|
|
259
286
|
}
|
|
260
287
|
|
|
261
288
|
// matches reports whether `rule` is currently suppressed given this state.
|
|
262
|
-
// The name is normalized before lookup so
|
|
263
|
-
//
|
|
289
|
+
// The name is normalized before lookup so an optional `eslint/` prefix in
|
|
290
|
+
// the directive does not prevent a match against the canonical rule id.
|
|
291
|
+
// Legacy `@typescript-eslint/` / `react-hooks/` / `tsdoc/syntax` prefixes
|
|
292
|
+
// are NOT normalized — they fall through to the unknown-rule path and
|
|
293
|
+
// surface as `Engine.UnknownRules()` so users see the migration loudly.
|
|
264
294
|
func (s lintDisableState) matches(rule string) bool {
|
|
265
295
|
normalized := normalizeDirectiveRuleName(rule)
|
|
266
296
|
if _, ok := s.rules[normalized]; ok {
|
|
@@ -336,9 +366,11 @@ func parseLintDirectiveLine(text string) (lintDirective, bool) {
|
|
|
336
366
|
if !ok {
|
|
337
367
|
continue
|
|
338
368
|
}
|
|
369
|
+
parsed := parseDirectivePayload(payload)
|
|
339
370
|
return lintDirective{
|
|
340
|
-
kind:
|
|
341
|
-
rules:
|
|
371
|
+
kind: form.kind,
|
|
372
|
+
rules: parsed.rules,
|
|
373
|
+
ruleList: parsed.ruleList,
|
|
342
374
|
}, true
|
|
343
375
|
}
|
|
344
376
|
}
|
|
@@ -363,10 +395,20 @@ func directivePayload(text, marker string) (string, bool) {
|
|
|
363
395
|
// marker) into a lintDirectiveRules value. The `--` separator strips an
|
|
364
396
|
// optional human-readable description. An empty rule list means "all rules".
|
|
365
397
|
func parseDirectiveRules(payload string) lintDirectiveRules {
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
398
|
+
return parseDirectivePayload(payload).rules
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
type parsedDirectivePayload struct {
|
|
402
|
+
rules lintDirectiveRules
|
|
403
|
+
ruleList []string
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
func parseDirectivePayload(payload string) parsedDirectivePayload {
|
|
407
|
+
ruleText := stripDirectiveDescription(payload)
|
|
408
|
+
ruleText = strings.ReplaceAll(ruleText, ",", " ")
|
|
409
|
+
fields := strings.Fields(ruleText)
|
|
369
410
|
rules := make(map[string]struct{}, len(fields))
|
|
411
|
+
ruleList := make([]string, 0, len(fields))
|
|
370
412
|
for _, field := range fields {
|
|
371
413
|
if strings.HasPrefix(field, "--") {
|
|
372
414
|
break
|
|
@@ -374,12 +416,16 @@ func parseDirectiveRules(payload string) lintDirectiveRules {
|
|
|
374
416
|
name := normalizeDirectiveRuleName(field)
|
|
375
417
|
if name != "" {
|
|
376
418
|
rules[name] = struct{}{}
|
|
419
|
+
ruleList = append(ruleList, name)
|
|
377
420
|
}
|
|
378
421
|
}
|
|
379
422
|
if len(rules) == 0 {
|
|
380
|
-
return lintDirectiveRules{all: true}
|
|
423
|
+
return parsedDirectivePayload{rules: lintDirectiveRules{all: true}}
|
|
424
|
+
}
|
|
425
|
+
return parsedDirectivePayload{
|
|
426
|
+
rules: lintDirectiveRules{rules: rules},
|
|
427
|
+
ruleList: ruleList,
|
|
381
428
|
}
|
|
382
|
-
return lintDirectiveRules{rules: rules}
|
|
383
429
|
}
|
|
384
430
|
|
|
385
431
|
// stripDirectiveDescription returns the portion of `payload` before the
|
|
@@ -398,15 +444,11 @@ func stripDirectiveDescription(payload string) string {
|
|
|
398
444
|
return strings.TrimSpace(payload[:i])
|
|
399
445
|
}
|
|
400
446
|
}
|
|
401
|
-
return payload
|
|
447
|
+
return strings.TrimSpace(payload)
|
|
402
448
|
}
|
|
403
449
|
|
|
404
|
-
// normalizeDirectiveRuleName strips
|
|
405
|
-
//
|
|
450
|
+
// normalizeDirectiveRuleName strips common ESLint namespace prefixes while
|
|
451
|
+
// preserving the kebab/slash rule IDs diagnostics use.
|
|
406
452
|
func normalizeDirectiveRuleName(name string) string {
|
|
407
|
-
|
|
408
|
-
name = strings.TrimPrefix(name, "@typescript-eslint/")
|
|
409
|
-
name = strings.TrimPrefix(name, "typescript-eslint/")
|
|
410
|
-
name = strings.TrimPrefix(name, "eslint/")
|
|
411
|
-
return name
|
|
453
|
+
return normalizeBuiltinRuleName(name)
|
|
412
454
|
}
|
package/linthost/dispatch.go
CHANGED
|
@@ -23,7 +23,8 @@ var Version = "dev"
|
|
|
23
23
|
// caller should propagate to the OS (`os.Exit`) or the host (`Plugin.Run`).
|
|
24
24
|
//
|
|
25
25
|
// Recognized verbs: `version` / `-v` / `--version`, `check`, `fix`, `format`,
|
|
26
|
-
// `build`, `transform
|
|
26
|
+
// `build`, `transform`, and the `lsp-*` protocol commands consumed by
|
|
27
|
+
// ttscserver. Anything else is a usage error (exit code 2).
|
|
27
28
|
func Main(args []string) int {
|
|
28
29
|
return run(args)
|
|
29
30
|
}
|
|
@@ -33,7 +34,7 @@ func Main(args []string) int {
|
|
|
33
34
|
// the same entry point the CLI uses.
|
|
34
35
|
func run(args []string) int {
|
|
35
36
|
if len(args) == 0 {
|
|
36
|
-
fmt.Fprintln(os.Stderr, "@ttsc/lint: command required (expected check|fix|format|build|transform|version)")
|
|
37
|
+
fmt.Fprintln(os.Stderr, "@ttsc/lint: command required (expected check|fix|format|build|transform|lsp-*|version)")
|
|
37
38
|
return 2
|
|
38
39
|
}
|
|
39
40
|
switch args[0] {
|
|
@@ -41,7 +42,7 @@ func run(args []string) int {
|
|
|
41
42
|
// Don't pay contributor-registration cost for the version banner.
|
|
42
43
|
fmt.Fprintf(os.Stdout, "@ttsc/lint %s\n", Version)
|
|
43
44
|
return 0
|
|
44
|
-
case "check", "fix", "format", "build", "transform":
|
|
45
|
+
case "check", "fix", "format", "build", "transform", "lsp-command-ids", "lsp-code-action-kinds", "lsp-diagnostics", "lsp-code-actions", "lsp-execute-command":
|
|
45
46
|
default:
|
|
46
47
|
fmt.Fprintf(os.Stderr, "@ttsc/lint: unknown command %q\n", args[0])
|
|
47
48
|
return 2
|
|
@@ -60,6 +61,16 @@ func run(args []string) int {
|
|
|
60
61
|
return RunBuild(args[1:])
|
|
61
62
|
case "transform":
|
|
62
63
|
return RunTransform(args[1:])
|
|
64
|
+
case "lsp-command-ids":
|
|
65
|
+
return RunLSPCommandIDs(args[1:])
|
|
66
|
+
case "lsp-code-action-kinds":
|
|
67
|
+
return RunLSPCodeActionKinds(args[1:])
|
|
68
|
+
case "lsp-diagnostics":
|
|
69
|
+
return RunLSPDiagnostics(args[1:])
|
|
70
|
+
case "lsp-code-actions":
|
|
71
|
+
return RunLSPCodeActions(args[1:])
|
|
72
|
+
case "lsp-execute-command":
|
|
73
|
+
return RunLSPExecuteCommand(args[1:])
|
|
63
74
|
}
|
|
64
75
|
return 2
|
|
65
76
|
}
|
package/linthost/engine.go
CHANGED
|
@@ -246,13 +246,22 @@ func AllRuleNames() []string {
|
|
|
246
246
|
|
|
247
247
|
// Engine binds a rule configuration to a Program and walks the AST once
|
|
248
248
|
// per source file, dispatching each visited node to its interested rules.
|
|
249
|
+
//
|
|
250
|
+
// `rules` is a fixed-size slice indexed by `shimast.Kind` value rather
|
|
251
|
+
// than a map. `KindCount` (~350) is small and bounded, and the slice
|
|
252
|
+
// removes a per-node map hash from the hot path — a `walk(node)` over a
|
|
253
|
+
// 50k-node file performs 50k dispatch lookups. The conversion is
|
|
254
|
+
// equivalent in semantics; entries for unused kinds are nil and the
|
|
255
|
+
// per-rule slice still grows by append.
|
|
249
256
|
type Engine struct {
|
|
250
|
-
config
|
|
251
|
-
rules
|
|
252
|
-
enabled
|
|
253
|
-
unknown
|
|
254
|
-
|
|
255
|
-
|
|
257
|
+
config RuleResolver
|
|
258
|
+
rules [][]Rule
|
|
259
|
+
enabled map[string]Severity
|
|
260
|
+
unknown []string
|
|
261
|
+
unknownDirectives map[string]struct{}
|
|
262
|
+
unknownDirectiveMu sync.Mutex
|
|
263
|
+
needsTypeChecker bool
|
|
264
|
+
serial bool
|
|
256
265
|
}
|
|
257
266
|
|
|
258
267
|
// SetSerial forces Engine.Run to walk files one at a time. The host calls
|
|
@@ -290,9 +299,10 @@ func NewEngineWithResolver(config RuleResolver) *Engine {
|
|
|
290
299
|
config = RuleConfig{}
|
|
291
300
|
}
|
|
292
301
|
eng := &Engine{
|
|
293
|
-
config:
|
|
294
|
-
rules:
|
|
295
|
-
enabled:
|
|
302
|
+
config: config,
|
|
303
|
+
rules: make([][]Rule, int(shimast.KindCount)),
|
|
304
|
+
enabled: make(map[string]Severity),
|
|
305
|
+
unknownDirectives: make(map[string]struct{}),
|
|
296
306
|
}
|
|
297
307
|
displaySeverities := config.EnabledRuleConfig()
|
|
298
308
|
for _, name := range config.ActiveRuleNames() {
|
|
@@ -313,16 +323,91 @@ func NewEngineWithResolver(config RuleResolver) *Engine {
|
|
|
313
323
|
continue
|
|
314
324
|
}
|
|
315
325
|
seen[kind] = struct{}{}
|
|
316
|
-
|
|
326
|
+
idx := int(kind)
|
|
327
|
+
if idx < 0 || idx >= len(eng.rules) {
|
|
328
|
+
// Defensive: a contributor returning a Kind beyond the
|
|
329
|
+
// shim's KindCount would otherwise panic on dispatch.
|
|
330
|
+
continue
|
|
331
|
+
}
|
|
332
|
+
eng.rules[idx] = append(eng.rules[idx], rule)
|
|
317
333
|
}
|
|
318
334
|
}
|
|
319
335
|
sort.Strings(eng.unknown)
|
|
320
336
|
return eng
|
|
321
337
|
}
|
|
322
338
|
|
|
323
|
-
// UnknownRules returns the names of rules that appeared in the
|
|
324
|
-
// have no
|
|
325
|
-
|
|
339
|
+
// UnknownRules returns the names of rules that appeared either in the
|
|
340
|
+
// config or in an inline `eslint-disable*` directive but have no
|
|
341
|
+
// registered implementation. Directive-side unknowns are deduped so the
|
|
342
|
+
// same misspelling on every page doesn't flood the warning channel.
|
|
343
|
+
func (e *Engine) UnknownRules() []string {
|
|
344
|
+
if e == nil {
|
|
345
|
+
return nil
|
|
346
|
+
}
|
|
347
|
+
e.unknownDirectiveMu.Lock()
|
|
348
|
+
extras := make([]string, 0, len(e.unknownDirectives))
|
|
349
|
+
for name := range e.unknownDirectives {
|
|
350
|
+
extras = append(extras, name)
|
|
351
|
+
}
|
|
352
|
+
e.unknownDirectiveMu.Unlock()
|
|
353
|
+
if len(extras) == 0 {
|
|
354
|
+
return e.unknown
|
|
355
|
+
}
|
|
356
|
+
seen := make(map[string]struct{}, len(e.unknown)+len(extras))
|
|
357
|
+
out := make([]string, 0, len(e.unknown)+len(extras))
|
|
358
|
+
for _, name := range e.unknown {
|
|
359
|
+
if _, dup := seen[name]; dup {
|
|
360
|
+
continue
|
|
361
|
+
}
|
|
362
|
+
seen[name] = struct{}{}
|
|
363
|
+
out = append(out, name)
|
|
364
|
+
}
|
|
365
|
+
for _, name := range extras {
|
|
366
|
+
if _, dup := seen[name]; dup {
|
|
367
|
+
continue
|
|
368
|
+
}
|
|
369
|
+
seen[name] = struct{}{}
|
|
370
|
+
out = append(out, name)
|
|
371
|
+
}
|
|
372
|
+
sort.Strings(out)
|
|
373
|
+
return out
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// collectUnknownDirectiveRules walks every directive's rule list and
|
|
377
|
+
// records names that don't resolve to a registered rule. Called once
|
|
378
|
+
// per file after `parseLintInlineDirectives`.
|
|
379
|
+
func (e *Engine) collectUnknownDirectiveRules(directives *lintInlineDirectives) {
|
|
380
|
+
if e == nil || directives == nil {
|
|
381
|
+
return
|
|
382
|
+
}
|
|
383
|
+
for _, rec := range directives.records {
|
|
384
|
+
for _, raw := range rec.ruleList {
|
|
385
|
+
name := normalizeDirectiveRuleName(raw)
|
|
386
|
+
if name == "" {
|
|
387
|
+
continue
|
|
388
|
+
}
|
|
389
|
+
if _, ok := registered.rules[name]; ok {
|
|
390
|
+
continue
|
|
391
|
+
}
|
|
392
|
+
e.recordUnknownDirectiveRule(name)
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// recordUnknownDirectiveRule remembers a rule name referenced by an
|
|
398
|
+
// `// eslint-disable*` directive that does not resolve to a registered
|
|
399
|
+
// rule. Each unique name is recorded once across the engine run.
|
|
400
|
+
func (e *Engine) recordUnknownDirectiveRule(name string) {
|
|
401
|
+
if e == nil || name == "" {
|
|
402
|
+
return
|
|
403
|
+
}
|
|
404
|
+
e.unknownDirectiveMu.Lock()
|
|
405
|
+
defer e.unknownDirectiveMu.Unlock()
|
|
406
|
+
if e.unknownDirectives == nil {
|
|
407
|
+
e.unknownDirectives = make(map[string]struct{})
|
|
408
|
+
}
|
|
409
|
+
e.unknownDirectives[name] = struct{}{}
|
|
410
|
+
}
|
|
326
411
|
|
|
327
412
|
// NeedsTypeChecker reports whether any active rule requires Context.Checker.
|
|
328
413
|
func (e *Engine) NeedsTypeChecker() bool {
|
|
@@ -393,6 +478,40 @@ type boundRule struct {
|
|
|
393
478
|
ctx *Context
|
|
394
479
|
}
|
|
395
480
|
|
|
481
|
+
// lintFileWalker drives the per-file AST traversal. The struct exists so
|
|
482
|
+
// the `ForEachChild` callback can be a method value cached in
|
|
483
|
+
// `childCB`. A naive nested-closure walker re-allocates one callback
|
|
484
|
+
// per recursive call (it captures the walking function variable),
|
|
485
|
+
// which on a 50 k-node file is 50 k throwaway closure allocations.
|
|
486
|
+
// Caching the method value reduces that to one allocation per file.
|
|
487
|
+
type lintFileWalker struct {
|
|
488
|
+
byKind [][]boundRule
|
|
489
|
+
collect func(*Finding)
|
|
490
|
+
childCB func(*shimast.Node) bool
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// walk dispatches a single node to every rule that registered for the
|
|
494
|
+
// node's Kind, then recurses into children via the cached childCB.
|
|
495
|
+
func (w *lintFileWalker) walk(node *shimast.Node) {
|
|
496
|
+
if node == nil {
|
|
497
|
+
return
|
|
498
|
+
}
|
|
499
|
+
if k := int(node.Kind); k >= 0 && k < len(w.byKind) {
|
|
500
|
+
for _, bound := range w.byKind[k] {
|
|
501
|
+
runRuleCheck(bound.rule, bound.ctx, node, w.collect)
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
node.ForEachChild(w.childCB)
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// visitChild is the cached ForEachChild callback. It is the method
|
|
508
|
+
// value stored in `childCB` so per-recursion closure allocation is
|
|
509
|
+
// avoided.
|
|
510
|
+
func (w *lintFileWalker) visitChild(child *shimast.Node) bool {
|
|
511
|
+
w.walk(child)
|
|
512
|
+
return false
|
|
513
|
+
}
|
|
514
|
+
|
|
396
515
|
// runFile is the per-file driver. The visitor is allocated once per file
|
|
397
516
|
// to keep the per-node hot path branch-free; it visits children
|
|
398
517
|
// post-order so parents see their already-checked subtrees.
|
|
@@ -415,9 +534,12 @@ func (e *Engine) runFile(file *shimast.SourceFile, checker *shimchecker.Checker)
|
|
|
415
534
|
// Context for every (node, rule) pair, which on a large program meant
|
|
416
535
|
// millions of short-lived heap allocations and the GC pressure they
|
|
417
536
|
// carry. Rules never mutate their Context, so reuse is safe.
|
|
418
|
-
byKind := make(
|
|
537
|
+
byKind := make([][]boundRule, len(e.rules))
|
|
419
538
|
ctxByRule := make(map[string]*Context, len(e.enabled))
|
|
420
539
|
for kind, rules := range e.rules {
|
|
540
|
+
if len(rules) == 0 {
|
|
541
|
+
continue
|
|
542
|
+
}
|
|
421
543
|
for _, rule := range rules {
|
|
422
544
|
name := rule.Name()
|
|
423
545
|
ctx, built := ctxByRule[name]
|
|
@@ -444,40 +566,39 @@ func (e *Engine) runFile(file *shimast.SourceFile, checker *shimchecker.Checker)
|
|
|
444
566
|
}
|
|
445
567
|
}
|
|
446
568
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
node.ForEachChild(func(child *shimast.Node) bool {
|
|
456
|
-
walk(child)
|
|
457
|
-
return false // visit every child
|
|
458
|
-
})
|
|
459
|
-
}
|
|
569
|
+
// Use a struct-based walker so the per-node ForEachChild callback is
|
|
570
|
+
// allocated once (stored as `w.childCB`) instead of once per Walk
|
|
571
|
+
// call. Closures that capture a recursive local function escape to
|
|
572
|
+
// the heap on every invocation; converting to a method value with a
|
|
573
|
+
// cached function field removes that allocation from the hot path —
|
|
574
|
+
// ~38 % of pre-Opt-4 CPU was in the inner ForEachChild closure.
|
|
575
|
+
w := &lintFileWalker{byKind: byKind, collect: collect}
|
|
576
|
+
w.childCB = w.visitChild
|
|
460
577
|
|
|
461
578
|
// SourceFile dispatches into its statement list directly; we walk
|
|
462
579
|
// statements explicitly so the file node itself can be inspected by
|
|
463
580
|
// rules (e.g., `ban-ts-comment` reads CommentDirectives off the
|
|
464
581
|
// SourceFile).
|
|
465
|
-
|
|
466
|
-
|
|
582
|
+
if k := int(shimast.KindSourceFile); k >= 0 && k < len(byKind) {
|
|
583
|
+
for _, bound := range byKind[k] {
|
|
584
|
+
runRuleCheck(bound.rule, bound.ctx, file.AsNode(), collect)
|
|
585
|
+
}
|
|
467
586
|
}
|
|
468
587
|
|
|
469
588
|
statements := file.Statements
|
|
470
589
|
if statements != nil {
|
|
471
590
|
for _, stmt := range statements.Nodes {
|
|
472
|
-
walk(stmt)
|
|
591
|
+
w.walk(stmt)
|
|
473
592
|
}
|
|
474
593
|
}
|
|
594
|
+
directives := parseLintInlineDirectives(file)
|
|
595
|
+
e.collectUnknownDirectiveRules(directives)
|
|
475
596
|
// Apply inline-disable filtering even for files with no statement
|
|
476
597
|
// list. A SourceFile-level rule that fires on a `// ttsc-lint-disable`
|
|
477
598
|
// comment must still honor the directive; early-returning before
|
|
478
599
|
// the filter would silently leak those findings into the diagnostic
|
|
479
600
|
// stream.
|
|
480
|
-
return
|
|
601
|
+
return filterInlineDisabledFindingsWithDirectives(file, collected, directives)
|
|
481
602
|
}
|
|
482
603
|
|
|
483
604
|
func hasEnabledFileRules(rules RuleConfig) bool {
|
package/linthost/fix.go
CHANGED
|
@@ -16,8 +16,8 @@ import (
|
|
|
16
16
|
shimdw "github.com/microsoft/typescript-go/shim/diagnosticwriter"
|
|
17
17
|
)
|
|
18
18
|
|
|
19
|
-
// maxFixPasses bounds the native fix cascade. Real-world cascades (
|
|
20
|
-
//
|
|
19
|
+
// maxFixPasses bounds the native fix cascade. Real-world cascades (noVar →
|
|
20
|
+
// preferConst → eqeqeq …) settle in a handful of passes; the cap exists so
|
|
21
21
|
// a buggy rule that re-reports its own edit cannot loop forever.
|
|
22
22
|
const maxFixPasses = 10
|
|
23
23
|
|