@ttsc/lint 0.13.1 → 0.14.0-dev.20250530.1
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 +955 -85
- package/lib/defaultFormat.d.ts +15 -8
- package/lib/defaultFormat.js +15 -8
- 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/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/format/ITtscLintFormat.d.ts +128 -0
- package/lib/structures/{TtscLintRuleMap.js → format/ITtscLintFormat.js} +1 -1
- package/lib/structures/format/ITtscLintFormat.js.map +1 -0
- package/lib/structures/format/ITtscLintFormatJsDoc.d.ts +17 -0
- package/lib/structures/{ITtscLintFormatConfig.js → format/ITtscLintFormatJsDoc.js} +1 -1
- package/lib/structures/format/ITtscLintFormatJsDoc.js.map +1 -0
- package/lib/structures/format/ITtscLintFormatSortImports.d.ts +54 -0
- package/lib/structures/format/ITtscLintFormatSortImports.js +3 -0
- package/lib/structures/format/ITtscLintFormatSortImports.js.map +1 -0
- package/lib/structures/format/index.d.ts +3 -0
- package/lib/structures/format/index.js +20 -0
- package/lib/structures/format/index.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 +95 -0
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js +13 -0
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintBoundariesRules.d.ts +75 -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 +16 -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 +1229 -0
- package/lib/structures/rules/ITtscLintCoreRules.js +3 -0
- 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 +125 -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 +154 -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 +162 -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 +190 -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 +133 -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 +294 -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 +180 -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 +312 -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 +179 -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 +49 -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 +37 -0
- package/lib/structures/rules/ITtscLintReactRuleOptions.js +11 -0
- package/lib/structures/rules/ITtscLintReactRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintReactRules.d.ts +276 -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 +182 -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 +65 -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 +141 -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 +178 -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 +20 -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 +165 -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 +88 -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 +21 -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 +293 -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 +1074 -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 +133 -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 +118 -71
- package/linthost/config_format.go +270 -104
- package/linthost/directives.go +67 -25
- package/linthost/dispatch.go +14 -3
- package/linthost/engine.go +152 -31
- package/linthost/fix.go +10 -3
- package/linthost/format.go +222 -25
- package/linthost/format_editor_settings.go +262 -0
- package/linthost/lsp.go +898 -0
- package/linthost/print_dispatch.go +5 -2
- package/linthost/print_engine.go +5 -5
- package/linthost/print_nodes_call.go +149 -67
- package/linthost/print_nodes_function.go +27 -2
- package/linthost/print_nodes_list.go +40 -5
- package/linthost/print_nodes_object.go +1 -1
- package/linthost/print_nodes_ternary.go +86 -0
- 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 +95 -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_arrow_parens.go +167 -0
- package/linthost/rules_format_bracket_spacing.go +117 -0
- package/linthost/rules_format_clause_join.go +172 -0
- package/linthost/rules_format_declaration_header.go +595 -0
- package/linthost/rules_format_indent.go +372 -0
- package/linthost/rules_format_jsdoc.go +5 -5
- package/linthost/rules_format_orphan_semi.go +106 -0
- package/linthost/rules_format_parameter_properties.go +175 -0
- package/linthost/rules_format_print_width.go +66 -55
- package/linthost/rules_format_quote_props.go +169 -0
- package/linthost/rules_format_quotes.go +76 -30
- package/linthost/rules_format_semi.go +186 -11
- package/linthost/rules_format_sort_imports.go +437 -118
- package/linthost/rules_format_statement_split.go +343 -0
- package/linthost/rules_format_ternary_nullish_parens.go +77 -0
- package/linthost/rules_format_trailing_comma.go +22 -3
- package/linthost/rules_format_whitespace.go +336 -0
- 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 +1057 -2
- 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 +159 -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 +17 -10
- package/src/index.ts +40 -16
- package/src/structures/ITtscLintConfig.ts +14 -8
- package/src/structures/TtscLintRuleSetting.ts +55 -0
- package/src/structures/format/ITtscLintFormat.ts +141 -0
- package/src/structures/format/ITtscLintFormatJsDoc.ts +18 -0
- package/src/structures/format/ITtscLintFormatSortImports.ts +62 -0
- package/src/structures/format/index.ts +3 -0
- package/src/structures/index.ts +3 -4
- package/src/structures/rules/ITtscLintBoundariesRuleOptions.ts +117 -0
- package/src/structures/rules/ITtscLintBoundariesRules.ts +91 -0
- package/src/structures/rules/ITtscLintContributorRules.ts +20 -0
- package/src/structures/rules/ITtscLintCoreRules.ts +1378 -0
- package/src/structures/rules/ITtscLintCypressRuleOptions.ts +18 -0
- package/src/structures/rules/ITtscLintCypressRules.ts +141 -0
- package/src/structures/rules/ITtscLintFunctionalRuleOptions.ts +200 -0
- package/src/structures/rules/ITtscLintFunctionalRules.ts +197 -0
- package/src/structures/rules/ITtscLintJestRules.ts +209 -0
- package/src/structures/rules/ITtscLintJsdocRules.ts +146 -0
- package/src/structures/rules/ITtscLintJsxA11yRules.ts +331 -0
- package/src/structures/rules/ITtscLintNextjsRules.ts +201 -0
- package/src/structures/rules/ITtscLintPlaywrightRules.ts +343 -0
- package/src/structures/rules/ITtscLintPromiseRules.ts +196 -0
- package/src/structures/rules/ITtscLintReactPerfRuleOptions.ts +19 -0
- package/src/structures/rules/ITtscLintReactPerfRules.ts +53 -0
- package/src/structures/rules/ITtscLintReactRuleOptions.ts +41 -0
- package/src/structures/rules/ITtscLintReactRules.ts +308 -0
- package/src/structures/rules/ITtscLintRegexpRules.ts +204 -0
- package/src/structures/rules/ITtscLintRuleOptionsMap.ts +88 -0
- package/src/structures/rules/ITtscLintRules.ts +77 -0
- package/src/structures/rules/ITtscLintSecurityRules.ts +155 -0
- package/src/structures/rules/ITtscLintSolidRules.ts +199 -0
- package/src/structures/rules/ITtscLintStorybookRuleOptions.ts +22 -0
- package/src/structures/rules/ITtscLintStorybookRules.ts +184 -0
- package/src/structures/rules/ITtscLintTanstackQueryRules.ts +96 -0
- package/src/structures/rules/ITtscLintTestingLibraryRuleOptions.ts +23 -0
- package/src/structures/rules/ITtscLintTestingLibraryRules.ts +325 -0
- package/src/structures/rules/ITtscLintTypeScriptRules.ts +1172 -0
- package/src/structures/rules/ITtscLintUnicornRules.ts +1143 -0
- package/src/structures/rules/ITtscLintVitestRules.ts +146 -0
- package/src/structures/rules/index.ts +31 -0
- package/lib/structures/ITtscLintFormatConfig.d.ts +0 -153
- 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/ITtscLintFormatConfig.ts +0 -168
- package/src/structures/TtscLintRule.ts +0 -160
- package/src/structures/TtscLintRuleMap.ts +0 -55
- package/src/structures/TtscLintRuleOptions.ts +0 -151
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// unicorn/prefer-single-call: `xs.push(1); xs.push(2);` repeats the
|
|
2
|
+
// `xs.push` lookup and the call dispatch for what is conceptually one
|
|
3
|
+
// "append these values" operation. Variadic methods like `push`,
|
|
4
|
+
// `unshift`, `addEventListener`, and `removeEventListener` accept
|
|
5
|
+
// multiple arguments specifically so authors can collapse the back-to-
|
|
6
|
+
// back form into a single call.
|
|
7
|
+
//
|
|
8
|
+
// AST-only: visit each `Block` AND `SourceFile`, scan the statement
|
|
9
|
+
// list for any pair of consecutive `ExpressionStatement`s whose
|
|
10
|
+
// expressions are `CallExpression`s targeting
|
|
11
|
+
// `PropertyAccess(<sameReceiverText>, <sameMethod>)` where the method
|
|
12
|
+
// is one of the variadic appenders. Receiver equivalence is decided
|
|
13
|
+
// by source-text comparison so chained receivers (e.g. `obj.list.push`)
|
|
14
|
+
// line up exactly. Report on the second statement so the diagnostic
|
|
15
|
+
// anchors to the redundant call.
|
|
16
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-single-call.md
|
|
17
|
+
package linthost
|
|
18
|
+
|
|
19
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
20
|
+
|
|
21
|
+
type unicornPreferSingleCall struct{}
|
|
22
|
+
|
|
23
|
+
func (unicornPreferSingleCall) Name() string { return "unicorn/prefer-single-call" }
|
|
24
|
+
func (unicornPreferSingleCall) Visits() []shimast.Kind {
|
|
25
|
+
return []shimast.Kind{shimast.KindBlock, shimast.KindSourceFile}
|
|
26
|
+
}
|
|
27
|
+
func (unicornPreferSingleCall) Check(ctx *Context, node *shimast.Node) {
|
|
28
|
+
var stmts []*shimast.Node
|
|
29
|
+
switch node.Kind {
|
|
30
|
+
case shimast.KindBlock:
|
|
31
|
+
block := node.AsBlock()
|
|
32
|
+
if block == nil || block.Statements == nil {
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
stmts = block.Statements.Nodes
|
|
36
|
+
case shimast.KindSourceFile:
|
|
37
|
+
file := node.AsSourceFile()
|
|
38
|
+
if file == nil || file.Statements == nil {
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
stmts = file.Statements.Nodes
|
|
42
|
+
default:
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
for i := 1; i < len(stmts); i++ {
|
|
46
|
+
prevReceiver, prevMethod := unicornPreferSingleCallExtract(ctx, stmts[i-1])
|
|
47
|
+
if prevReceiver == "" {
|
|
48
|
+
continue
|
|
49
|
+
}
|
|
50
|
+
currReceiver, currMethod := unicornPreferSingleCallExtract(ctx, stmts[i])
|
|
51
|
+
if currReceiver == "" {
|
|
52
|
+
continue
|
|
53
|
+
}
|
|
54
|
+
if prevReceiver != currReceiver || prevMethod != currMethod {
|
|
55
|
+
continue
|
|
56
|
+
}
|
|
57
|
+
ctx.Report(stmts[i], "Combine consecutive `"+currMethod+"` calls with multiple arguments into a single call.")
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// unicornPreferSingleCallExtract returns (receiverText, methodName) for a
|
|
62
|
+
// statement of the shape `<receiver>.<method>(…);` where `method` is one
|
|
63
|
+
// of the variadic appenders the rule targets. Returns ("", "") for any
|
|
64
|
+
// other shape.
|
|
65
|
+
func unicornPreferSingleCallExtract(ctx *Context, stmt *shimast.Node) (string, string) {
|
|
66
|
+
if stmt == nil || stmt.Kind != shimast.KindExpressionStatement {
|
|
67
|
+
return "", ""
|
|
68
|
+
}
|
|
69
|
+
exprStmt := stmt.AsExpressionStatement()
|
|
70
|
+
if exprStmt == nil || exprStmt.Expression == nil {
|
|
71
|
+
return "", ""
|
|
72
|
+
}
|
|
73
|
+
call := stripParens(exprStmt.Expression)
|
|
74
|
+
if call == nil || call.Kind != shimast.KindCallExpression {
|
|
75
|
+
return "", ""
|
|
76
|
+
}
|
|
77
|
+
c := call.AsCallExpression()
|
|
78
|
+
if c == nil || c.Expression == nil || c.Expression.Kind != shimast.KindPropertyAccessExpression {
|
|
79
|
+
return "", ""
|
|
80
|
+
}
|
|
81
|
+
access := c.Expression.AsPropertyAccessExpression()
|
|
82
|
+
if access == nil || access.Expression == nil {
|
|
83
|
+
return "", ""
|
|
84
|
+
}
|
|
85
|
+
method := identifierText(access.Name())
|
|
86
|
+
switch method {
|
|
87
|
+
case "push", "unshift", "addEventListener", "removeEventListener":
|
|
88
|
+
default:
|
|
89
|
+
return "", ""
|
|
90
|
+
}
|
|
91
|
+
return nodeText(ctx.File, access.Expression), method
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
func init() {
|
|
95
|
+
Register(unicornPreferSingleCall{})
|
|
96
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// unicorn/prefer-spread: `Array.from(x)` with a single iterable argument
|
|
2
|
+
// is equivalent to a spread copy `[...x]`. The spread form is shorter,
|
|
3
|
+
// reads as a value-level operation rather than a constructor call, and
|
|
4
|
+
// removes the `Array` global from the read path entirely.
|
|
5
|
+
//
|
|
6
|
+
// AST-only: visit each `CallExpression`, match `Array.from(x)` — a
|
|
7
|
+
// callee that is a property access reading `from` on a bare identifier
|
|
8
|
+
// `Array`, with exactly one argument. The single-argument restriction
|
|
9
|
+
// is load-bearing: `Array.from(x, mapFn)` and `Array.from(x, mapFn,
|
|
10
|
+
// thisArg)` have observable behavior the spread does not (the mapper
|
|
11
|
+
// receives the index, and `thisArg` is bound on a non-arrow mapper), so
|
|
12
|
+
// the rule deliberately stays away from them.
|
|
13
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-spread.md
|
|
14
|
+
package linthost
|
|
15
|
+
|
|
16
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
17
|
+
|
|
18
|
+
type unicornPreferSpread struct{}
|
|
19
|
+
|
|
20
|
+
func (unicornPreferSpread) Name() string { return "unicorn/prefer-spread" }
|
|
21
|
+
func (unicornPreferSpread) Visits() []shimast.Kind {
|
|
22
|
+
return []shimast.Kind{shimast.KindCallExpression}
|
|
23
|
+
}
|
|
24
|
+
func (unicornPreferSpread) Check(ctx *Context, node *shimast.Node) {
|
|
25
|
+
call := node.AsCallExpression()
|
|
26
|
+
if call == nil || call.Expression == nil {
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
if call.Expression.Kind != shimast.KindPropertyAccessExpression {
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
access := call.Expression.AsPropertyAccessExpression()
|
|
33
|
+
if access == nil {
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
if identifierText(access.Name()) != "from" {
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
receiver := stripParens(access.Expression)
|
|
40
|
+
if identifierText(receiver) != "Array" {
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
if call.Arguments == nil || len(call.Arguments.Nodes) != 1 {
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
ctx.Report(node, "Prefer spread `[...x]` over `Array.from(x)` for single-arg shallow copies.")
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
func init() {
|
|
50
|
+
Register(unicornPreferSpread{})
|
|
51
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// unicorn/prefer-string-raw: a string literal whose source contains
|
|
2
|
+
// `\\` (an escaped backslash) is using the escape syntax to represent a
|
|
3
|
+
// literal backslash. The same value, written through `String.raw` as
|
|
4
|
+
// a template literal, drops every backslash escape and reads as the
|
|
5
|
+
// literal text the author meant — particularly noticeable for Windows
|
|
6
|
+
// paths, regex source strings, and TeX-shaped snippets.
|
|
7
|
+
//
|
|
8
|
+
// AST-only: visit `KindStringLiteral` and
|
|
9
|
+
// `KindNoSubstitutionTemplateLiteral`. The match keys on the raw source
|
|
10
|
+
// bytes of the literal node — `nodeText` returns the as-written source
|
|
11
|
+
// — and fires when those bytes contain the two-character sequence `\\`,
|
|
12
|
+
// i.e. an escaped backslash that `String.raw` would render literally.
|
|
13
|
+
// Untagged template literals with substitutions are out of scope; this
|
|
14
|
+
// rule only addresses the "single literal of fixed text" case.
|
|
15
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-string-raw.md
|
|
16
|
+
package linthost
|
|
17
|
+
|
|
18
|
+
import (
|
|
19
|
+
"strings"
|
|
20
|
+
|
|
21
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
type unicornPreferStringRaw struct{}
|
|
25
|
+
|
|
26
|
+
func (unicornPreferStringRaw) Name() string { return "unicorn/prefer-string-raw" }
|
|
27
|
+
func (unicornPreferStringRaw) Visits() []shimast.Kind {
|
|
28
|
+
return []shimast.Kind{shimast.KindStringLiteral, shimast.KindNoSubstitutionTemplateLiteral}
|
|
29
|
+
}
|
|
30
|
+
func (unicornPreferStringRaw) Check(ctx *Context, node *shimast.Node) {
|
|
31
|
+
raw := nodeText(ctx.File, node)
|
|
32
|
+
if raw == "" {
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
if !strings.Contains(raw, `\\`) {
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
ctx.Report(node, "Prefer `String.raw` for strings with backslash escapes.")
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
func init() {
|
|
42
|
+
Register(unicornPreferStringRaw{})
|
|
43
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// unicorn/prefer-string-replace-all: `"abc".replace(/a/g, "x")` is the
|
|
2
|
+
// pre-ES2021 idiom for "replace every occurrence". ES2021's
|
|
3
|
+
// `String#replaceAll` does the same thing without the regex flag
|
|
4
|
+
// detour. The rule fires on `.replace(/<pattern>/g, replacement)` so
|
|
5
|
+
// authors switch to the explicit method.
|
|
6
|
+
//
|
|
7
|
+
// AST-only: a `CallExpression` whose callee is `.replace` AND whose
|
|
8
|
+
// first argument is a `RegularExpressionLiteral` carrying the `g` flag
|
|
9
|
+
// in its trailing flag block matches. The flag is read from the raw
|
|
10
|
+
// source text — the AST does not split pattern from flags — using the
|
|
11
|
+
// shared `nodeText` accessor.
|
|
12
|
+
//
|
|
13
|
+
// To preserve semantics, the pattern body must also be literal — any
|
|
14
|
+
// regex metacharacter (`\`, `.`, `*`, `+`, `?`, `[`, `]`, `(`, `)`,
|
|
15
|
+
// `{`, `}`, `|`, `^`, `$`) disqualifies the rewrite, because
|
|
16
|
+
// `/<pat>/g` and `.replaceAll(<pat>, ...)` mean different things when
|
|
17
|
+
// the pattern is anything but a fixed string.
|
|
18
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-string-replace-all.md
|
|
19
|
+
package linthost
|
|
20
|
+
|
|
21
|
+
import (
|
|
22
|
+
"strings"
|
|
23
|
+
|
|
24
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
type unicornPreferStringReplaceAll struct{}
|
|
28
|
+
|
|
29
|
+
func (unicornPreferStringReplaceAll) Name() string { return "unicorn/prefer-string-replace-all" }
|
|
30
|
+
func (unicornPreferStringReplaceAll) Visits() []shimast.Kind {
|
|
31
|
+
return []shimast.Kind{shimast.KindCallExpression}
|
|
32
|
+
}
|
|
33
|
+
func (unicornPreferStringReplaceAll) Check(ctx *Context, node *shimast.Node) {
|
|
34
|
+
call := node.AsCallExpression()
|
|
35
|
+
if call == nil || call.Expression == nil ||
|
|
36
|
+
call.Expression.Kind != shimast.KindPropertyAccessExpression {
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
access := call.Expression.AsPropertyAccessExpression()
|
|
40
|
+
if access == nil || identifierText(access.Name()) != "replace" {
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
if call.Arguments == nil || len(call.Arguments.Nodes) < 1 {
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
first := stripParens(call.Arguments.Nodes[0])
|
|
47
|
+
if first == nil || first.Kind != shimast.KindRegularExpressionLiteral {
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
raw := nodeText(ctx.File, first)
|
|
51
|
+
if !unicornPreferStringReplaceAllHasGlobalFlag(raw) {
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
if !unicornPreferStringReplaceAllIsLiteralPattern(raw) {
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
ctx.Report(node, "Prefer `String#replaceAll(literal, replacement)` over `replace(/literal/g, replacement)`.")
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// unicornPreferStringReplaceAllHasGlobalFlag returns true when `raw` (the
|
|
61
|
+
// source text of a RegularExpressionLiteral, including the surrounding
|
|
62
|
+
// `/` delimiters and trailing flag block) carries the `g` flag.
|
|
63
|
+
func unicornPreferStringReplaceAllHasGlobalFlag(raw string) bool {
|
|
64
|
+
if len(raw) < 3 || raw[0] != '/' {
|
|
65
|
+
return false
|
|
66
|
+
}
|
|
67
|
+
closing := strings.LastIndexByte(raw, '/')
|
|
68
|
+
if closing <= 0 {
|
|
69
|
+
return false
|
|
70
|
+
}
|
|
71
|
+
flags := raw[closing+1:]
|
|
72
|
+
return strings.ContainsRune(flags, 'g')
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// unicornPreferStringReplaceAllIsLiteralPattern returns true when the
|
|
76
|
+
// pattern body of `raw` (the source text of a RegularExpressionLiteral)
|
|
77
|
+
// contains no regex metacharacters. Conservative: any metachar — even
|
|
78
|
+
// an escaped one like `\.` — disqualifies the rewrite, because
|
|
79
|
+
// recovering the original character cleanly from raw source requires
|
|
80
|
+
// regex-aware parsing we don't do here.
|
|
81
|
+
func unicornPreferStringReplaceAllIsLiteralPattern(raw string) bool {
|
|
82
|
+
if len(raw) < 3 || raw[0] != '/' {
|
|
83
|
+
return false
|
|
84
|
+
}
|
|
85
|
+
closing := strings.LastIndexByte(raw, '/')
|
|
86
|
+
if closing <= 0 {
|
|
87
|
+
return false
|
|
88
|
+
}
|
|
89
|
+
body := raw[1:closing]
|
|
90
|
+
return !strings.ContainsAny(body, `\.*+?[](){}|^$`)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
func init() {
|
|
94
|
+
Register(unicornPreferStringReplaceAll{})
|
|
95
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// unicorn/prefer-string-slice: `String#substr` is deprecated and
|
|
2
|
+
// `String#substring` has surprising "swap arguments when end < start"
|
|
3
|
+
// semantics. `String#slice` is the single modern alternative whose
|
|
4
|
+
// behavior matches author intent. The rule fires on any `.substr(…)`
|
|
5
|
+
// or `.substring(…)` callsite so the codebase converges on `.slice`.
|
|
6
|
+
//
|
|
7
|
+
// AST-only: a `CallExpression` whose callee is a
|
|
8
|
+
// `PropertyAccessExpression` ending in `substr` or `substring`
|
|
9
|
+
// matches. Receiver typing is intentionally not checked — both names
|
|
10
|
+
// exist almost exclusively on strings in real code, and the
|
|
11
|
+
// upstream rule treats them as banned regardless.
|
|
12
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-string-slice.md
|
|
13
|
+
package linthost
|
|
14
|
+
|
|
15
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
16
|
+
|
|
17
|
+
type unicornPreferStringSlice struct{}
|
|
18
|
+
|
|
19
|
+
func (unicornPreferStringSlice) Name() string { return "unicorn/prefer-string-slice" }
|
|
20
|
+
func (unicornPreferStringSlice) Visits() []shimast.Kind {
|
|
21
|
+
return []shimast.Kind{shimast.KindCallExpression}
|
|
22
|
+
}
|
|
23
|
+
func (unicornPreferStringSlice) Check(ctx *Context, node *shimast.Node) {
|
|
24
|
+
call := node.AsCallExpression()
|
|
25
|
+
if call == nil || call.Expression == nil ||
|
|
26
|
+
call.Expression.Kind != shimast.KindPropertyAccessExpression {
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
access := call.Expression.AsPropertyAccessExpression()
|
|
30
|
+
if access == nil {
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
switch identifierText(access.Name()) {
|
|
34
|
+
case "substr", "substring":
|
|
35
|
+
default:
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
ctx.Report(node, "Prefer `String#slice()` over `substr` / `substring`.")
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
func init() {
|
|
42
|
+
Register(unicornPreferStringSlice{})
|
|
43
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// unicorn/prefer-string-starts-ends-with: `s.slice(0, 4) === "http"` and
|
|
2
|
+
// `s.slice(-3) === "abc"` are the legacy spellings of `s.startsWith(...)`
|
|
3
|
+
// and `s.endsWith(...)`. The String methods are clearer about intent, do
|
|
4
|
+
// not allocate the intermediate substring, and have been available for
|
|
5
|
+
// over a decade.
|
|
6
|
+
//
|
|
7
|
+
// AST-only: visit each `BinaryExpression` whose operator is `===` or
|
|
8
|
+
// `!==`. One operand must be a `CallExpression` of the shape
|
|
9
|
+
// `_.slice(0, N)` or `_.slice(-N)` (the `-N` form being a unary minus
|
|
10
|
+
// over a numeric literal) and the other operand must be a string literal
|
|
11
|
+
// whose text length matches N. Reports on the binary expression.
|
|
12
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-string-starts-ends-with.md
|
|
13
|
+
package linthost
|
|
14
|
+
|
|
15
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
16
|
+
|
|
17
|
+
type unicornPreferStringStartsEndsWith struct{}
|
|
18
|
+
|
|
19
|
+
func (unicornPreferStringStartsEndsWith) Name() string {
|
|
20
|
+
return "unicorn/prefer-string-starts-ends-with"
|
|
21
|
+
}
|
|
22
|
+
func (unicornPreferStringStartsEndsWith) Visits() []shimast.Kind {
|
|
23
|
+
return []shimast.Kind{shimast.KindBinaryExpression}
|
|
24
|
+
}
|
|
25
|
+
func (unicornPreferStringStartsEndsWith) Check(ctx *Context, node *shimast.Node) {
|
|
26
|
+
bin := node.AsBinaryExpression()
|
|
27
|
+
if bin == nil || bin.OperatorToken == nil || bin.Left == nil || bin.Right == nil {
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
switch bin.OperatorToken.Kind {
|
|
31
|
+
case shimast.KindEqualsEqualsEqualsToken,
|
|
32
|
+
shimast.KindExclamationEqualsEqualsToken:
|
|
33
|
+
default:
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
left := stripParens(bin.Left)
|
|
37
|
+
right := stripParens(bin.Right)
|
|
38
|
+
if unicornPreferStringStartsEndsWithMatches(left, right) ||
|
|
39
|
+
unicornPreferStringStartsEndsWithMatches(right, left) {
|
|
40
|
+
ctx.Report(node, "Prefer `String#startsWith()` / `String#endsWith()` over slice-and-compare.")
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// unicornPreferStringStartsEndsWithMatches reports whether `callSide` is
|
|
45
|
+
// the slice call and `literalSide` is a matching string literal.
|
|
46
|
+
func unicornPreferStringStartsEndsWithMatches(callSide, literalSide *shimast.Node) bool {
|
|
47
|
+
if callSide == nil || literalSide == nil {
|
|
48
|
+
return false
|
|
49
|
+
}
|
|
50
|
+
if callSide.Kind != shimast.KindCallExpression {
|
|
51
|
+
return false
|
|
52
|
+
}
|
|
53
|
+
if literalSide.Kind != shimast.KindStringLiteral &&
|
|
54
|
+
literalSide.Kind != shimast.KindNoSubstitutionTemplateLiteral {
|
|
55
|
+
return false
|
|
56
|
+
}
|
|
57
|
+
call := callSide.AsCallExpression()
|
|
58
|
+
if call == nil || call.Expression == nil ||
|
|
59
|
+
call.Expression.Kind != shimast.KindPropertyAccessExpression {
|
|
60
|
+
return false
|
|
61
|
+
}
|
|
62
|
+
access := call.Expression.AsPropertyAccessExpression()
|
|
63
|
+
if access == nil || identifierText(access.Name()) != "slice" {
|
|
64
|
+
return false
|
|
65
|
+
}
|
|
66
|
+
if call.Arguments == nil {
|
|
67
|
+
return false
|
|
68
|
+
}
|
|
69
|
+
args := call.Arguments.Nodes
|
|
70
|
+
wantLen := -1
|
|
71
|
+
switch len(args) {
|
|
72
|
+
case 2:
|
|
73
|
+
first := stripParens(args[0])
|
|
74
|
+
second := stripParens(args[1])
|
|
75
|
+
if first == nil || first.Kind != shimast.KindNumericLiteral ||
|
|
76
|
+
numericLiteralText(first) != "0" {
|
|
77
|
+
return false
|
|
78
|
+
}
|
|
79
|
+
if second == nil || second.Kind != shimast.KindNumericLiteral {
|
|
80
|
+
return false
|
|
81
|
+
}
|
|
82
|
+
if !unicornPreferStringStartsEndsWithDigits(numericLiteralText(second)) {
|
|
83
|
+
return false
|
|
84
|
+
}
|
|
85
|
+
wantLen = unicornPreferStringStartsEndsWithToInt(numericLiteralText(second))
|
|
86
|
+
case 1:
|
|
87
|
+
// `.slice(-N)` — a unary minus over a positive numeric literal.
|
|
88
|
+
only := stripParens(args[0])
|
|
89
|
+
if only == nil || only.Kind != shimast.KindPrefixUnaryExpression {
|
|
90
|
+
return false
|
|
91
|
+
}
|
|
92
|
+
prefix := only.AsPrefixUnaryExpression()
|
|
93
|
+
if prefix == nil || prefix.Operator != shimast.KindMinusToken ||
|
|
94
|
+
prefix.Operand == nil ||
|
|
95
|
+
prefix.Operand.Kind != shimast.KindNumericLiteral {
|
|
96
|
+
return false
|
|
97
|
+
}
|
|
98
|
+
text := numericLiteralText(prefix.Operand)
|
|
99
|
+
if !unicornPreferStringStartsEndsWithDigits(text) {
|
|
100
|
+
return false
|
|
101
|
+
}
|
|
102
|
+
wantLen = unicornPreferStringStartsEndsWithToInt(text)
|
|
103
|
+
default:
|
|
104
|
+
return false
|
|
105
|
+
}
|
|
106
|
+
if wantLen <= 0 {
|
|
107
|
+
return false
|
|
108
|
+
}
|
|
109
|
+
return len(stringLiteralText(literalSide)) == wantLen
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// unicornPreferStringStartsEndsWithDigits reports whether `text` is a
|
|
113
|
+
// non-empty ASCII decimal-integer literal. Decimals, hex, and `e`-notation
|
|
114
|
+
// are rejected since the rule only handles fixed-length prefixes.
|
|
115
|
+
func unicornPreferStringStartsEndsWithDigits(text string) bool {
|
|
116
|
+
if text == "" {
|
|
117
|
+
return false
|
|
118
|
+
}
|
|
119
|
+
for i := 0; i < len(text); i++ {
|
|
120
|
+
c := text[i]
|
|
121
|
+
if c < '0' || c > '9' {
|
|
122
|
+
return false
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return true
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// unicornPreferStringStartsEndsWithToInt parses an ASCII decimal-integer
|
|
129
|
+
// literal into an int. Callers must have validated the input first; this
|
|
130
|
+
// helper returns -1 only as a defensive fallback for an overflow guard.
|
|
131
|
+
func unicornPreferStringStartsEndsWithToInt(text string) int {
|
|
132
|
+
n := 0
|
|
133
|
+
for i := 0; i < len(text); i++ {
|
|
134
|
+
c := text[i]
|
|
135
|
+
if c < '0' || c > '9' {
|
|
136
|
+
return -1
|
|
137
|
+
}
|
|
138
|
+
n = n*10 + int(c-'0')
|
|
139
|
+
if n > 1<<30 {
|
|
140
|
+
return -1
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return n
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
func init() {
|
|
147
|
+
Register(unicornPreferStringStartsEndsWith{})
|
|
148
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// unicorn/prefer-string-trim-start-end: `String#trimLeft` and
|
|
2
|
+
// `String#trimRight` are the deprecated names for what
|
|
3
|
+
// `String#trimStart` / `String#trimEnd` express directly. The deprecated
|
|
4
|
+
// names are still callable but should be replaced for consistency with
|
|
5
|
+
// the modern naming. The rule fires on zero-argument calls to either
|
|
6
|
+
// deprecated method.
|
|
7
|
+
//
|
|
8
|
+
// AST-only: a `CallExpression` whose callee is `.trimLeft` or
|
|
9
|
+
// `.trimRight` and whose argument list is empty matches. Arguments are
|
|
10
|
+
// theoretically not allowed on either method, but the AST does not
|
|
11
|
+
// know that — the rule defends against the syntactic shape only.
|
|
12
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-string-trim-start-end.md
|
|
13
|
+
package linthost
|
|
14
|
+
|
|
15
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
16
|
+
|
|
17
|
+
type unicornPreferStringTrimStartEnd struct{}
|
|
18
|
+
|
|
19
|
+
func (unicornPreferStringTrimStartEnd) Name() string {
|
|
20
|
+
return "unicorn/prefer-string-trim-start-end"
|
|
21
|
+
}
|
|
22
|
+
func (unicornPreferStringTrimStartEnd) Visits() []shimast.Kind {
|
|
23
|
+
return []shimast.Kind{shimast.KindCallExpression}
|
|
24
|
+
}
|
|
25
|
+
func (unicornPreferStringTrimStartEnd) Check(ctx *Context, node *shimast.Node) {
|
|
26
|
+
call := node.AsCallExpression()
|
|
27
|
+
if call == nil || call.Expression == nil ||
|
|
28
|
+
call.Expression.Kind != shimast.KindPropertyAccessExpression {
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
access := call.Expression.AsPropertyAccessExpression()
|
|
32
|
+
if access == nil {
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
switch identifierText(access.Name()) {
|
|
36
|
+
case "trimLeft", "trimRight":
|
|
37
|
+
default:
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
if call.Arguments != nil && len(call.Arguments.Nodes) > 0 {
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
ctx.Report(node, "Prefer `String#trimStart` / `String#trimEnd` over the deprecated `trimLeft` / `trimRight`.")
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
func init() {
|
|
47
|
+
Register(unicornPreferStringTrimStartEnd{})
|
|
48
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// unicorn/prefer-structured-clone: `JSON.parse(JSON.stringify(x))` is
|
|
2
|
+
// the historical deep-clone idiom. It silently drops everything JSON
|
|
3
|
+
// cannot round-trip — `Date`, `Map`, `Set`, typed arrays, cyclic
|
|
4
|
+
// references — and re-allocates a large intermediate string. The
|
|
5
|
+
// platform-native `structuredClone(x)` handles every transferable type,
|
|
6
|
+
// supports cycles, and avoids the string round-trip entirely.
|
|
7
|
+
//
|
|
8
|
+
// AST-only: visit each `CallExpression`, match `JSON.parse(arg)` whose
|
|
9
|
+
// single `arg` is itself a `JSON.stringify(...)` call. Both gates lock
|
|
10
|
+
// the receiver to the bare `JSON` identifier so member-access chains
|
|
11
|
+
// reading `parse`/`stringify` on a renamed alias do not trip the rule.
|
|
12
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-structured-clone.md
|
|
13
|
+
package linthost
|
|
14
|
+
|
|
15
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
16
|
+
|
|
17
|
+
type unicornPreferStructuredClone struct{}
|
|
18
|
+
|
|
19
|
+
func (unicornPreferStructuredClone) Name() string {
|
|
20
|
+
return "unicorn/prefer-structured-clone"
|
|
21
|
+
}
|
|
22
|
+
func (unicornPreferStructuredClone) Visits() []shimast.Kind {
|
|
23
|
+
return []shimast.Kind{shimast.KindCallExpression}
|
|
24
|
+
}
|
|
25
|
+
func (unicornPreferStructuredClone) Check(ctx *Context, node *shimast.Node) {
|
|
26
|
+
if !isJSONMethodCall(node, "parse") {
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
outer := node.AsCallExpression()
|
|
30
|
+
if outer == nil || outer.Arguments == nil || len(outer.Arguments.Nodes) != 1 {
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
arg := stripParens(outer.Arguments.Nodes[0])
|
|
34
|
+
if arg == nil || arg.Kind != shimast.KindCallExpression {
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
if !isJSONMethodCall(arg, "stringify") {
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
ctx.Report(node, "Prefer `structuredClone(x)` over `JSON.parse(JSON.stringify(x))`.")
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// isJSONMethodCall reports whether `node` is a CallExpression whose
|
|
44
|
+
// callee is `JSON.<method>` — a property access reading `method` on a
|
|
45
|
+
// bare `JSON` identifier. The bare-identifier gate keeps the rule from
|
|
46
|
+
// firing on `aliased.parse(...)` shapes that happen to share the
|
|
47
|
+
// method name.
|
|
48
|
+
func isJSONMethodCall(node *shimast.Node, method string) bool {
|
|
49
|
+
if node == nil || node.Kind != shimast.KindCallExpression {
|
|
50
|
+
return false
|
|
51
|
+
}
|
|
52
|
+
call := node.AsCallExpression()
|
|
53
|
+
if call == nil || call.Expression == nil {
|
|
54
|
+
return false
|
|
55
|
+
}
|
|
56
|
+
if call.Expression.Kind != shimast.KindPropertyAccessExpression {
|
|
57
|
+
return false
|
|
58
|
+
}
|
|
59
|
+
access := call.Expression.AsPropertyAccessExpression()
|
|
60
|
+
if access == nil {
|
|
61
|
+
return false
|
|
62
|
+
}
|
|
63
|
+
if identifierText(access.Name()) != method {
|
|
64
|
+
return false
|
|
65
|
+
}
|
|
66
|
+
return identifierText(stripParens(access.Expression)) == "JSON"
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
func init() {
|
|
70
|
+
Register(unicornPreferStructuredClone{})
|
|
71
|
+
}
|