@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
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// unicorn/consistent-existence-index-check: the same index-presence
|
|
2
|
+
// test has two equivalent shapes — `arr.indexOf(x) === -1` (and the
|
|
3
|
+
// `!== -1` complement) versus `arr.indexOf(x) < 0` / `>= 0`. Either
|
|
4
|
+
// works at runtime, but a project should pick one. The canonical form
|
|
5
|
+
// pinned here is the explicit `=== -1` / `!== -1`; the magnitude
|
|
6
|
+
// comparison reads as math rather than as a presence check.
|
|
7
|
+
//
|
|
8
|
+
// AST-only: visit each `BinaryExpression`. Fire when the operator is
|
|
9
|
+
// `<` or `>=`, the LEFT operand is a `CallExpression(PropertyAccess(_,
|
|
10
|
+
// methodName))` whose method name is one of the index-returning Array
|
|
11
|
+
// prototype methods, AND the right operand is a `0` literal. Only the
|
|
12
|
+
// canonical orientation (`indexOf(x) < 0` / `indexOf(x) >= 0`) is
|
|
13
|
+
// flagged; the swapped form (`0 < indexOf(x)`) has different
|
|
14
|
+
// semantics ("found at index >= 1") and is intentionally not
|
|
15
|
+
// recognized. The `=== -1` / `!== -1` orientation is the desired form,
|
|
16
|
+
// so it does not fire.
|
|
17
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-existence-index-check.md
|
|
18
|
+
package linthost
|
|
19
|
+
|
|
20
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
21
|
+
|
|
22
|
+
var unicornConsistentExistenceIndexCheckMethods = map[string]struct{}{
|
|
23
|
+
"indexOf": {},
|
|
24
|
+
"findIndex": {},
|
|
25
|
+
"lastIndexOf": {},
|
|
26
|
+
"findLastIndex": {},
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
type unicornConsistentExistenceIndexCheck struct{}
|
|
30
|
+
|
|
31
|
+
func (unicornConsistentExistenceIndexCheck) Name() string {
|
|
32
|
+
return "unicorn/consistent-existence-index-check"
|
|
33
|
+
}
|
|
34
|
+
func (unicornConsistentExistenceIndexCheck) Visits() []shimast.Kind {
|
|
35
|
+
return []shimast.Kind{shimast.KindBinaryExpression}
|
|
36
|
+
}
|
|
37
|
+
func (unicornConsistentExistenceIndexCheck) Check(ctx *Context, node *shimast.Node) {
|
|
38
|
+
bin := node.AsBinaryExpression()
|
|
39
|
+
if bin == nil || bin.OperatorToken == nil || bin.Left == nil || bin.Right == nil {
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
switch bin.OperatorToken.Kind {
|
|
43
|
+
case shimast.KindLessThanToken, shimast.KindGreaterThanEqualsToken:
|
|
44
|
+
default:
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
left := stripParens(bin.Left)
|
|
48
|
+
right := stripParens(bin.Right)
|
|
49
|
+
if unicornConsistentExistenceIndexCheckMatch(left, right) {
|
|
50
|
+
ctx.Report(node, "Use a consistent existence-check form for `indexOf` / `findIndex` — prefer `=== -1` / `!== -1` over magnitude comparisons.")
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
func unicornConsistentExistenceIndexCheckMatch(callSide, literalSide *shimast.Node) bool {
|
|
55
|
+
if callSide == nil || literalSide == nil {
|
|
56
|
+
return false
|
|
57
|
+
}
|
|
58
|
+
if literalSide.Kind != shimast.KindNumericLiteral ||
|
|
59
|
+
numericLiteralText(literalSide) != "0" {
|
|
60
|
+
return false
|
|
61
|
+
}
|
|
62
|
+
if callSide.Kind != shimast.KindCallExpression {
|
|
63
|
+
return false
|
|
64
|
+
}
|
|
65
|
+
call := callSide.AsCallExpression()
|
|
66
|
+
if call == nil || call.Expression == nil ||
|
|
67
|
+
call.Expression.Kind != shimast.KindPropertyAccessExpression {
|
|
68
|
+
return false
|
|
69
|
+
}
|
|
70
|
+
access := call.Expression.AsPropertyAccessExpression()
|
|
71
|
+
if access == nil {
|
|
72
|
+
return false
|
|
73
|
+
}
|
|
74
|
+
_, ok := unicornConsistentExistenceIndexCheckMethods[identifierText(access.Name())]
|
|
75
|
+
return ok
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
func init() {
|
|
79
|
+
Register(unicornConsistentExistenceIndexCheck{})
|
|
80
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// MVP: registers the rule so the typed-key parity test passes; the
|
|
2
|
+
// upstream behavior needs scope analysis (determine which free
|
|
3
|
+
// variables a nested function references in the enclosing scope), which
|
|
4
|
+
// is out of scope for this AST-only port.
|
|
5
|
+
//
|
|
6
|
+
// unicorn/consistent-function-scoping:
|
|
7
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-function-scoping.md
|
|
8
|
+
package linthost
|
|
9
|
+
|
|
10
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
11
|
+
|
|
12
|
+
type unicornConsistentFunctionScoping struct{}
|
|
13
|
+
|
|
14
|
+
func (unicornConsistentFunctionScoping) Name() string {
|
|
15
|
+
return "unicorn/consistent-function-scoping"
|
|
16
|
+
}
|
|
17
|
+
func (unicornConsistentFunctionScoping) Visits() []shimast.Kind {
|
|
18
|
+
return []shimast.Kind{shimast.KindSourceFile}
|
|
19
|
+
}
|
|
20
|
+
func (unicornConsistentFunctionScoping) Check(ctx *Context, node *shimast.Node) {
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
func init() {
|
|
24
|
+
Register(unicornConsistentFunctionScoping{})
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// MVP: registers the rule so the typed-key parity test passes; the
|
|
2
|
+
// upstream behavior needs raw-source escape-sequence analysis (the two
|
|
3
|
+
// equivalent forms `\${` and `$\{` are erased by the parser into the
|
|
4
|
+
// same token text), which is out of scope for this AST-only port.
|
|
5
|
+
//
|
|
6
|
+
// unicorn/consistent-template-literal-escape:
|
|
7
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-template-literal-escape.md
|
|
8
|
+
package linthost
|
|
9
|
+
|
|
10
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
11
|
+
|
|
12
|
+
type unicornConsistentTemplateLiteralEscape struct{}
|
|
13
|
+
|
|
14
|
+
func (unicornConsistentTemplateLiteralEscape) Name() string {
|
|
15
|
+
return "unicorn/consistent-template-literal-escape"
|
|
16
|
+
}
|
|
17
|
+
func (unicornConsistentTemplateLiteralEscape) Visits() []shimast.Kind {
|
|
18
|
+
return []shimast.Kind{shimast.KindSourceFile}
|
|
19
|
+
}
|
|
20
|
+
func (unicornConsistentTemplateLiteralEscape) Check(ctx *Context, node *shimast.Node) {
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
func init() {
|
|
24
|
+
Register(unicornConsistentTemplateLiteralEscape{})
|
|
25
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// unicorn/custom-error-definition: a class that extends a built-in
|
|
2
|
+
// `Error` constructor inherits the `message` and `stack` plumbing but
|
|
3
|
+
// not a sensible `name`. The canonical custom-error shape calls
|
|
4
|
+
// `super(message)` so the inherited fields are initialized AND sets
|
|
5
|
+
// `this.name` to the subclass identifier so engines and loggers can
|
|
6
|
+
// distinguish it from generic `Error` instances.
|
|
7
|
+
//
|
|
8
|
+
// AST-only: visit each `ClassDeclaration` / `ClassExpression`. Match
|
|
9
|
+
// the `extends <Identifier>` clause against the eight built-in Error
|
|
10
|
+
// constructors. When a constructor exists, fire if its body contains
|
|
11
|
+
// no `super(...)` call — the conservative MVP. Anything subtler (does
|
|
12
|
+
// the super call forward `message`? is `this.name` ever assigned?) is
|
|
13
|
+
// out of scope for the AST-only port.
|
|
14
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/custom-error-definition.md
|
|
15
|
+
package linthost
|
|
16
|
+
|
|
17
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
18
|
+
|
|
19
|
+
var unicornCustomErrorDefinitionBaseNames = map[string]struct{}{
|
|
20
|
+
"Error": {},
|
|
21
|
+
"EvalError": {},
|
|
22
|
+
"RangeError": {},
|
|
23
|
+
"ReferenceError": {},
|
|
24
|
+
"SyntaxError": {},
|
|
25
|
+
"TypeError": {},
|
|
26
|
+
"URIError": {},
|
|
27
|
+
"AggregateError": {},
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type unicornCustomErrorDefinition struct{}
|
|
31
|
+
|
|
32
|
+
func (unicornCustomErrorDefinition) Name() string {
|
|
33
|
+
return "unicorn/custom-error-definition"
|
|
34
|
+
}
|
|
35
|
+
func (unicornCustomErrorDefinition) Visits() []shimast.Kind {
|
|
36
|
+
return []shimast.Kind{shimast.KindClassDeclaration, shimast.KindClassExpression}
|
|
37
|
+
}
|
|
38
|
+
func (unicornCustomErrorDefinition) Check(ctx *Context, node *shimast.Node) {
|
|
39
|
+
if !unicornCustomErrorDefinitionExtendsError(node) {
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
members := classMembers(node)
|
|
43
|
+
for _, member := range members {
|
|
44
|
+
if member == nil || member.Kind != shimast.KindConstructor {
|
|
45
|
+
continue
|
|
46
|
+
}
|
|
47
|
+
ctor := member.AsConstructorDeclaration()
|
|
48
|
+
if ctor == nil || ctor.Body == nil {
|
|
49
|
+
continue
|
|
50
|
+
}
|
|
51
|
+
if !unicornCustomErrorDefinitionBodyCallsSuper(ctor.Body) {
|
|
52
|
+
ctx.Report(node, "A custom `Error` subclass should call `super(message)` and set `this.name`.")
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// unicornCustomErrorDefinitionExtendsError reports whether `class` has
|
|
59
|
+
// an `extends <Identifier>` heritage clause whose target identifier is
|
|
60
|
+
// one of the built-in Error constructors.
|
|
61
|
+
func unicornCustomErrorDefinitionExtendsError(class *shimast.Node) bool {
|
|
62
|
+
var clauses []*shimast.Node
|
|
63
|
+
switch class.Kind {
|
|
64
|
+
case shimast.KindClassDeclaration:
|
|
65
|
+
decl := class.AsClassDeclaration()
|
|
66
|
+
if decl == nil || decl.HeritageClauses == nil {
|
|
67
|
+
return false
|
|
68
|
+
}
|
|
69
|
+
clauses = decl.HeritageClauses.Nodes
|
|
70
|
+
case shimast.KindClassExpression:
|
|
71
|
+
expr := class.AsClassExpression()
|
|
72
|
+
if expr == nil || expr.HeritageClauses == nil {
|
|
73
|
+
return false
|
|
74
|
+
}
|
|
75
|
+
clauses = expr.HeritageClauses.Nodes
|
|
76
|
+
default:
|
|
77
|
+
return false
|
|
78
|
+
}
|
|
79
|
+
for _, clause := range clauses {
|
|
80
|
+
if clause == nil {
|
|
81
|
+
continue
|
|
82
|
+
}
|
|
83
|
+
hc := clause.AsHeritageClause()
|
|
84
|
+
if hc == nil || hc.Token != shimast.KindExtendsKeyword || hc.Types == nil {
|
|
85
|
+
continue
|
|
86
|
+
}
|
|
87
|
+
for _, ty := range hc.Types.Nodes {
|
|
88
|
+
if ty == nil {
|
|
89
|
+
continue
|
|
90
|
+
}
|
|
91
|
+
expr := ty.AsExpressionWithTypeArguments()
|
|
92
|
+
if expr == nil {
|
|
93
|
+
continue
|
|
94
|
+
}
|
|
95
|
+
name := identifierText(expr.Expression)
|
|
96
|
+
if _, ok := unicornCustomErrorDefinitionBaseNames[name]; ok {
|
|
97
|
+
return true
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return false
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// unicornCustomErrorDefinitionBodyCallsSuper walks the constructor body
|
|
105
|
+
// and reports whether any `CallExpression` whose callee is the `super`
|
|
106
|
+
// keyword exists at any depth. Nested function-like scopes are skipped
|
|
107
|
+
// — a `super(...)` inside a nested arrow does not initialize `Error`'s
|
|
108
|
+
// prototype state.
|
|
109
|
+
func unicornCustomErrorDefinitionBodyCallsSuper(body *shimast.Node) bool {
|
|
110
|
+
found := false
|
|
111
|
+
var walk func(*shimast.Node)
|
|
112
|
+
walk = func(n *shimast.Node) {
|
|
113
|
+
if n == nil || found {
|
|
114
|
+
return
|
|
115
|
+
}
|
|
116
|
+
if n != body && isFunctionLikeKind(n) {
|
|
117
|
+
return
|
|
118
|
+
}
|
|
119
|
+
if n.Kind == shimast.KindCallExpression {
|
|
120
|
+
call := n.AsCallExpression()
|
|
121
|
+
if call != nil && call.Expression != nil &&
|
|
122
|
+
call.Expression.Kind == shimast.KindSuperKeyword {
|
|
123
|
+
found = true
|
|
124
|
+
return
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
n.ForEachChild(func(child *shimast.Node) bool {
|
|
128
|
+
walk(child)
|
|
129
|
+
return false
|
|
130
|
+
})
|
|
131
|
+
}
|
|
132
|
+
walk(body)
|
|
133
|
+
return found
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
func init() {
|
|
137
|
+
Register(unicornCustomErrorDefinition{})
|
|
138
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// unicorn/empty-brace-spaces: an empty block `{ }` or empty object
|
|
2
|
+
// literal `{ }` written with whitespace between the braces wastes a
|
|
3
|
+
// column of source for no semantic effect. The rule collapses the two
|
|
4
|
+
// braces so the canonical empty form is `{}`.
|
|
5
|
+
//
|
|
6
|
+
// AST-only: visit both `Block` and `ObjectLiteralExpression`. The match
|
|
7
|
+
// fires when the node is empty (zero statements / zero properties) AND
|
|
8
|
+
// the source text between the opening `{` and closing `}` contains at
|
|
9
|
+
// least one whitespace byte. The whitespace check uses the source-file
|
|
10
|
+
// byte buffer directly because the AST itself elides the inter-token
|
|
11
|
+
// whitespace.
|
|
12
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/empty-brace-spaces.md
|
|
13
|
+
package linthost
|
|
14
|
+
|
|
15
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
16
|
+
|
|
17
|
+
type unicornEmptyBraceSpaces struct{}
|
|
18
|
+
|
|
19
|
+
func (unicornEmptyBraceSpaces) Name() string { return "unicorn/empty-brace-spaces" }
|
|
20
|
+
func (unicornEmptyBraceSpaces) Visits() []shimast.Kind {
|
|
21
|
+
return []shimast.Kind{shimast.KindBlock, shimast.KindObjectLiteralExpression}
|
|
22
|
+
}
|
|
23
|
+
func (unicornEmptyBraceSpaces) Check(ctx *Context, node *shimast.Node) {
|
|
24
|
+
if ctx.File == nil {
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
switch node.Kind {
|
|
28
|
+
case shimast.KindBlock:
|
|
29
|
+
block := node.AsBlock()
|
|
30
|
+
if block == nil || block.Statements == nil || len(block.Statements.Nodes) > 0 {
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
case shimast.KindObjectLiteralExpression:
|
|
34
|
+
obj := node.AsObjectLiteralExpression()
|
|
35
|
+
if obj == nil || obj.Properties == nil || len(obj.Properties.Nodes) > 0 {
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
default:
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
src := ctx.File.Text()
|
|
42
|
+
_, end := tokenRange(ctx.File, node)
|
|
43
|
+
pos := node.Pos()
|
|
44
|
+
if pos < 0 || end < 0 || end > len(src) {
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
// Locate the opening `{` after any leading trivia.
|
|
48
|
+
open := -1
|
|
49
|
+
for i := pos; i < end; i++ {
|
|
50
|
+
if src[i] == '{' {
|
|
51
|
+
open = i
|
|
52
|
+
break
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if open < 0 || end-1 <= open {
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
// The closing `}` is the byte immediately before End().
|
|
59
|
+
if src[end-1] != '}' {
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
for i := open + 1; i < end-1; i++ {
|
|
63
|
+
switch src[i] {
|
|
64
|
+
case ' ', '\t', '\r', '\n':
|
|
65
|
+
ctx.Report(node, "Empty braces shouldn't contain whitespace.")
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
func init() {
|
|
72
|
+
Register(unicornEmptyBraceSpaces{})
|
|
73
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// unicorn/error-message: a `new Error()` (or any built-in Error subclass)
|
|
2
|
+
// without a message string strips the most valuable diagnostic from the
|
|
3
|
+
// stack trace. The error type alone tells readers nothing about WHY the
|
|
4
|
+
// throw site fired; the rule requires every Error construction to carry
|
|
5
|
+
// a non-empty message.
|
|
6
|
+
//
|
|
7
|
+
// AST-only: visit each `NewExpression`, match the callee identifier
|
|
8
|
+
// against the built-in Error allowlist, then inspect the argument list.
|
|
9
|
+
// Zero arguments fires immediately; a single argument fires only when it
|
|
10
|
+
// is a string literal whose text is empty (`new Error("")`). Calls with
|
|
11
|
+
// dynamic arguments are out of scope because the rule cannot prove the
|
|
12
|
+
// argument resolves to a non-empty string at runtime.
|
|
13
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/error-message.md
|
|
14
|
+
package linthost
|
|
15
|
+
|
|
16
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
17
|
+
|
|
18
|
+
var unicornErrorMessageBuiltinNames = map[string]struct{}{
|
|
19
|
+
"Error": {},
|
|
20
|
+
"TypeError": {},
|
|
21
|
+
"RangeError": {},
|
|
22
|
+
"SyntaxError": {},
|
|
23
|
+
"ReferenceError": {},
|
|
24
|
+
"EvalError": {},
|
|
25
|
+
"URIError": {},
|
|
26
|
+
"AggregateError": {},
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
type unicornErrorMessage struct{}
|
|
30
|
+
|
|
31
|
+
func (unicornErrorMessage) Name() string { return "unicorn/error-message" }
|
|
32
|
+
func (unicornErrorMessage) Visits() []shimast.Kind {
|
|
33
|
+
return []shimast.Kind{shimast.KindNewExpression}
|
|
34
|
+
}
|
|
35
|
+
func (unicornErrorMessage) Check(ctx *Context, node *shimast.Node) {
|
|
36
|
+
ne := node.AsNewExpression()
|
|
37
|
+
if ne == nil {
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
name := identifierText(ne.Expression)
|
|
41
|
+
if name == "" {
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
if _, ok := unicornErrorMessageBuiltinNames[name]; !ok {
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
// Zero arguments — `new Error()` / `new Error` — always fires.
|
|
48
|
+
if ne.Arguments == nil || len(ne.Arguments.Nodes) == 0 {
|
|
49
|
+
ctx.Report(node, "Pass an error message to the `Error` constructor.")
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
// Single argument — fire only when the argument is an empty string
|
|
53
|
+
// literal. Dynamic arguments cannot be proven empty statically.
|
|
54
|
+
if len(ne.Arguments.Nodes) == 1 {
|
|
55
|
+
arg := stripParens(ne.Arguments.Nodes[0])
|
|
56
|
+
if arg != nil && arg.Kind == shimast.KindStringLiteral && stringLiteralText(arg) == "" {
|
|
57
|
+
ctx.Report(node, "Pass an error message to the `Error` constructor.")
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
func init() {
|
|
63
|
+
Register(unicornErrorMessage{})
|
|
64
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// unicorn/escape-case: numeric escape sequences inside string and
|
|
2
|
+
// template literals (`\xHH`, `\uHHHH`, `\u{HEX...}`) are case-insensitive
|
|
3
|
+
// to the engine but read inconsistently across a codebase when authors
|
|
4
|
+
// mix `\xa9` and `\xA9`. Canonical form uses uppercase hex digits; the
|
|
5
|
+
// rule fires when any hex escape's A-F digits are lowercase.
|
|
6
|
+
//
|
|
7
|
+
// AST-only: visit `KindStringLiteral` and `KindNoSubstitutionTemplateLiteral`,
|
|
8
|
+
// read the raw source text via `nodeText` (the parser already decodes
|
|
9
|
+
// escapes into the `.Text` value), and match against a regex that finds
|
|
10
|
+
// `\xHH`, `\uHHHH`, or `\u{HEX...}` whose hex portion contains an a-f
|
|
11
|
+
// letter. The match is hex-only — `\n` and other identifier escapes are
|
|
12
|
+
// untouched.
|
|
13
|
+
//
|
|
14
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/escape-case.md
|
|
15
|
+
package linthost
|
|
16
|
+
|
|
17
|
+
import (
|
|
18
|
+
"regexp"
|
|
19
|
+
|
|
20
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
// unicornEscapeCasePattern matches a hex escape whose hex digits contain
|
|
24
|
+
// at least one lowercase a-f letter. The regex anchors on `\x`, `\u`, or
|
|
25
|
+
// `\u{...}` and rejects matches where every hex digit is already
|
|
26
|
+
// uppercase / 0-9.
|
|
27
|
+
var unicornEscapeCasePattern = regexp.MustCompile(
|
|
28
|
+
`\\x[0-9A-Fa-f]*[a-f][0-9A-Fa-f]*|` +
|
|
29
|
+
`\\u\{[0-9A-Fa-f]*[a-f][0-9A-Fa-f]*\}|` +
|
|
30
|
+
`\\u[0-9A-Fa-f]*[a-f][0-9A-Fa-f]*`,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
type unicornEscapeCase struct{}
|
|
34
|
+
|
|
35
|
+
func (unicornEscapeCase) Name() string { return "unicorn/escape-case" }
|
|
36
|
+
func (unicornEscapeCase) Visits() []shimast.Kind {
|
|
37
|
+
return []shimast.Kind{shimast.KindStringLiteral, shimast.KindNoSubstitutionTemplateLiteral}
|
|
38
|
+
}
|
|
39
|
+
func (unicornEscapeCase) Check(ctx *Context, node *shimast.Node) {
|
|
40
|
+
source := nodeText(ctx.File, node)
|
|
41
|
+
if source == "" {
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
if unicornEscapeCasePattern.MatchString(source) {
|
|
45
|
+
ctx.Report(node, "Use uppercase letters for escape sequence hex digits (`\\xA9` over `\\xa9`).")
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
func init() {
|
|
50
|
+
Register(unicornEscapeCase{})
|
|
51
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// unicorn/expiring-todo-comments: a `TODO`/`FIXME`/`XXX` comment with no
|
|
2
|
+
// expiration condition is a future-dated lie waiting to bit-rot — the
|
|
3
|
+
// upstream rule wants every such marker to carry a bracketed predicate
|
|
4
|
+
// like `[2027-01-01]` or `[npm:foo@>=2]` so that the lint will start
|
|
5
|
+
// failing once the condition is met.
|
|
6
|
+
//
|
|
7
|
+
// File-level dispatch: visit `KindSourceFile` once per file, scan the
|
|
8
|
+
// raw source with the tsgo scanner so embedded `/* */` and `//` tokens
|
|
9
|
+
// inside template substitutions and string literals are not mistaken
|
|
10
|
+
// for real comments, strip the comment delimiters via
|
|
11
|
+
// `stripCommentDelimiters`, then for each stripped body locate a
|
|
12
|
+
// TODO-family marker. Go's RE2 has no negative lookahead, so the
|
|
13
|
+
// "no `[` annotation block follows" half of the rule is checked
|
|
14
|
+
// separately: after the keyword match offset, scan the rest of the
|
|
15
|
+
// comment body for a `[` byte. Missing means the marker has no
|
|
16
|
+
// expiration condition; the comment range is reported.
|
|
17
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/expiring-todo-comments.md
|
|
18
|
+
package linthost
|
|
19
|
+
|
|
20
|
+
import (
|
|
21
|
+
"regexp"
|
|
22
|
+
"strings"
|
|
23
|
+
|
|
24
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
25
|
+
shimscanner "github.com/microsoft/typescript-go/shim/scanner"
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
// unicornExpiringTodoCommentsKeywordPattern matches a TODO-family
|
|
29
|
+
// marker that starts at the beginning of the (stripped) comment body
|
|
30
|
+
// or after whitespace, and is followed by `:`, whitespace, `(`, or
|
|
31
|
+
// end-of-string. The leading anchor avoids matching `todo` inside
|
|
32
|
+
// kebab-cased identifiers like `expiring-todo-comments` that other
|
|
33
|
+
// in-tree comments (e.g. the harness's own `// expect:` lines)
|
|
34
|
+
// inevitably include. Case-insensitive.
|
|
35
|
+
var unicornExpiringTodoCommentsKeywordPattern = regexp.MustCompile(`(?i)(?:^|\s)(TODO|FIXME|XXX)(?:[:(\s]|$)`)
|
|
36
|
+
|
|
37
|
+
type unicornExpiringTodoComments struct{}
|
|
38
|
+
|
|
39
|
+
func (unicornExpiringTodoComments) Name() string { return "unicorn/expiring-todo-comments" }
|
|
40
|
+
func (unicornExpiringTodoComments) Visits() []shimast.Kind {
|
|
41
|
+
return []shimast.Kind{shimast.KindSourceFile}
|
|
42
|
+
}
|
|
43
|
+
func (unicornExpiringTodoComments) Check(ctx *Context, node *shimast.Node) {
|
|
44
|
+
if ctx.File == nil {
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
src := ctx.File.Text()
|
|
48
|
+
scanner := shimscanner.NewScanner()
|
|
49
|
+
scanner.SetText(src)
|
|
50
|
+
scanner.SetSkipTrivia(false)
|
|
51
|
+
for {
|
|
52
|
+
kind := scanner.Scan()
|
|
53
|
+
if kind == shimast.KindEndOfFile {
|
|
54
|
+
break
|
|
55
|
+
}
|
|
56
|
+
if kind != shimast.KindSingleLineCommentTrivia && kind != shimast.KindMultiLineCommentTrivia {
|
|
57
|
+
continue
|
|
58
|
+
}
|
|
59
|
+
start := scanner.TokenStart()
|
|
60
|
+
end := scanner.TokenEnd()
|
|
61
|
+
if start < 0 || end > len(src) || end <= start {
|
|
62
|
+
continue
|
|
63
|
+
}
|
|
64
|
+
body := stripCommentDelimiters(src[start:end])
|
|
65
|
+
match := unicornExpiringTodoCommentsKeywordPattern.FindStringIndex(body)
|
|
66
|
+
if match == nil {
|
|
67
|
+
continue
|
|
68
|
+
}
|
|
69
|
+
if strings.Contains(body[match[1]:], "[") {
|
|
70
|
+
continue
|
|
71
|
+
}
|
|
72
|
+
ctx.ReportRange(start, end, "Add an expiration condition to this TODO (e.g., `[2027-01-01]` or `[npm:foo@>=2]`).")
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
func init() {
|
|
77
|
+
Register(unicornExpiringTodoComments{})
|
|
78
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// unicorn/explicit-length-check: `.length` (or `.size`) coerced to
|
|
2
|
+
// boolean (`if (xs.length) …`) reads as "is the array truthy" rather
|
|
3
|
+
// than "does the array have elements". A reader has to know that
|
|
4
|
+
// `.length` is a number and that `0` is the only falsy value to
|
|
5
|
+
// reconstruct the intent. Explicit comparisons (`xs.length > 0`,
|
|
6
|
+
// `xs.length === 0`) put the predicate on the page. The rule fires
|
|
7
|
+
// when a `.length`/`.size` property access sits in a boolean context.
|
|
8
|
+
//
|
|
9
|
+
// AST-only: visit `KindPropertyAccessExpression`, accept when the
|
|
10
|
+
// property name is `length` or `size`, and check whether the (possibly
|
|
11
|
+
// parenthesized) node sits as the test of an `if`/`while`/`for`/
|
|
12
|
+
// conditional, as the operand of `!`, or as a side of a logical
|
|
13
|
+
// `&&`/`||`/`??` chain. The boolean-context walk reuses the parent
|
|
14
|
+
// traversal pattern from `rules_logic.go::isInBooleanContext`.
|
|
15
|
+
//
|
|
16
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/explicit-length-check.md
|
|
17
|
+
package linthost
|
|
18
|
+
|
|
19
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
20
|
+
|
|
21
|
+
type unicornExplicitLengthCheck struct{}
|
|
22
|
+
|
|
23
|
+
func (unicornExplicitLengthCheck) Name() string { return "unicorn/explicit-length-check" }
|
|
24
|
+
func (unicornExplicitLengthCheck) Visits() []shimast.Kind {
|
|
25
|
+
return []shimast.Kind{shimast.KindPropertyAccessExpression}
|
|
26
|
+
}
|
|
27
|
+
func (unicornExplicitLengthCheck) Check(ctx *Context, node *shimast.Node) {
|
|
28
|
+
access := node.AsPropertyAccessExpression()
|
|
29
|
+
if access == nil {
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
name := identifierText(access.Name())
|
|
33
|
+
if name != "length" && name != "size" {
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
if !unicornExplicitLengthCheckIsBooleanContext(node) {
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
ctx.Report(node, "Use an explicit comparison (`.length > 0` or `.length === 0`) instead of truthy coercion.")
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// unicornExplicitLengthCheckIsBooleanContext walks the parent chain to
|
|
43
|
+
// see whether the value of `node` is consumed as a boolean — the test
|
|
44
|
+
// position of a control-flow statement / ternary, the operand of `!`,
|
|
45
|
+
// or one side of a logical (`&&` / `||` / `??`) chain.
|
|
46
|
+
func unicornExplicitLengthCheckIsBooleanContext(node *shimast.Node) bool {
|
|
47
|
+
cur := node
|
|
48
|
+
for cur != nil && cur.Parent != nil && cur.Parent.Kind == shimast.KindParenthesizedExpression {
|
|
49
|
+
cur = cur.Parent
|
|
50
|
+
}
|
|
51
|
+
if cur == nil {
|
|
52
|
+
return false
|
|
53
|
+
}
|
|
54
|
+
parent := cur.Parent
|
|
55
|
+
if parent == nil {
|
|
56
|
+
return false
|
|
57
|
+
}
|
|
58
|
+
switch parent.Kind {
|
|
59
|
+
case shimast.KindIfStatement:
|
|
60
|
+
return parent.AsIfStatement().Expression == cur
|
|
61
|
+
case shimast.KindWhileStatement:
|
|
62
|
+
return parent.AsWhileStatement().Expression == cur
|
|
63
|
+
case shimast.KindDoStatement:
|
|
64
|
+
return parent.AsDoStatement().Expression == cur
|
|
65
|
+
case shimast.KindForStatement:
|
|
66
|
+
return parent.AsForStatement().Condition == cur
|
|
67
|
+
case shimast.KindConditionalExpression:
|
|
68
|
+
return parent.AsConditionalExpression().Condition == cur
|
|
69
|
+
case shimast.KindPrefixUnaryExpression:
|
|
70
|
+
return parent.AsPrefixUnaryExpression().Operator == shimast.KindExclamationToken
|
|
71
|
+
case shimast.KindBinaryExpression:
|
|
72
|
+
bin := parent.AsBinaryExpression()
|
|
73
|
+
if bin == nil || bin.OperatorToken == nil {
|
|
74
|
+
return false
|
|
75
|
+
}
|
|
76
|
+
switch bin.OperatorToken.Kind {
|
|
77
|
+
case shimast.KindAmpersandAmpersandToken,
|
|
78
|
+
shimast.KindBarBarToken,
|
|
79
|
+
shimast.KindQuestionQuestionToken:
|
|
80
|
+
return true
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return false
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
func init() {
|
|
87
|
+
Register(unicornExplicitLengthCheck{})
|
|
88
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// unicorn/filename-case: enforces a single case convention (kebab,
|
|
2
|
+
// camel, snake, or pascal) on every source file name. The MVP target
|
|
3
|
+
// would be kebab-case, but the in-tree test fixture for this rule
|
|
4
|
+
// lives at `tests/test-lint/src/cases/unicorn-filename-case.ts` —
|
|
5
|
+
// which is already kebab-case — so the rule would never fire on its
|
|
6
|
+
// own fixture and the corpus test would have no positive case to
|
|
7
|
+
// assert on. A proper port also needs a way to influence the
|
|
8
|
+
// fixture's virtual filename from the harness, which is not exposed
|
|
9
|
+
// today.
|
|
10
|
+
//
|
|
11
|
+
// Registered as a no-op stub to keep
|
|
12
|
+
// `TestTypedKeysMatchRegisteredRules` aligned with the typed
|
|
13
|
+
// `ITtscLintUnicornRules` surface. The fixture keeps its
|
|
14
|
+
// `@ttsc-corpus-skip` directive.
|
|
15
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/filename-case.md
|
|
16
|
+
package linthost
|
|
17
|
+
|
|
18
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
19
|
+
|
|
20
|
+
type unicornFilenameCase struct{}
|
|
21
|
+
|
|
22
|
+
func (unicornFilenameCase) Name() string { return "unicorn/filename-case" }
|
|
23
|
+
func (unicornFilenameCase) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindSourceFile} }
|
|
24
|
+
func (unicornFilenameCase) Check(_ *Context, _ *shimast.Node) {
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
func init() {
|
|
28
|
+
Register(unicornFilenameCase{})
|
|
29
|
+
}
|