@ttsc/lint 0.13.0 → 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 +60 -37
- 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/compile.go +33 -2
- 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 +160 -40
- package/linthost/fix.go +10 -3
- package/linthost/flags_gen.go +17 -15
- package/linthost/format.go +222 -25
- package/linthost/format_editor_settings.go +262 -0
- package/linthost/host.go +40 -3
- 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 +10 -4
- package/linthost/rules_vitest.go +568 -0
- package/package.json +3 -3
- package/plugin/main.go +49 -3
- package/rule/astutil/astutil.go +10 -3
- package/rule/rule.go +12 -10
- package/src/defaultFormat.ts +17 -10
- package/src/index.ts +65 -43
- 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,41 @@
|
|
|
1
|
+
// unicorn/no-document-cookie: writing to (or reading) `document.cookie`
|
|
2
|
+
// directly mixes name/value parsing, serialization, attribute handling,
|
|
3
|
+
// and quoting concerns into one mutable string. The replacement is the
|
|
4
|
+
// async Cookie Store API (`cookieStore.set`/`cookieStore.get`) or a
|
|
5
|
+
// dedicated cookie wrapper — both surface attribute fields as data
|
|
6
|
+
// instead of string-encoded options.
|
|
7
|
+
//
|
|
8
|
+
// AST-only and identifier-text-driven: any `PropertyAccessExpression`
|
|
9
|
+
// whose receiver identifier is `document` and whose property name is
|
|
10
|
+
// `cookie` matches, so the same visit handles both the read
|
|
11
|
+
// (`document.cookie`) and the assignment LHS (`document.cookie = "..."`).
|
|
12
|
+
// Shadowed `document` bindings and computed/optional access are out of
|
|
13
|
+
// scope, mirroring `unicorn/no-process-exit`.
|
|
14
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-document-cookie.md
|
|
15
|
+
package linthost
|
|
16
|
+
|
|
17
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
18
|
+
|
|
19
|
+
type unicornNoDocumentCookie struct{}
|
|
20
|
+
|
|
21
|
+
func (unicornNoDocumentCookie) Name() string { return "unicorn/no-document-cookie" }
|
|
22
|
+
func (unicornNoDocumentCookie) Visits() []shimast.Kind {
|
|
23
|
+
return []shimast.Kind{shimast.KindPropertyAccessExpression}
|
|
24
|
+
}
|
|
25
|
+
func (unicornNoDocumentCookie) Check(ctx *Context, node *shimast.Node) {
|
|
26
|
+
access := node.AsPropertyAccessExpression()
|
|
27
|
+
if access == nil {
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
if identifierText(access.Expression) != "document" {
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
if identifierText(access.Name()) != "cookie" {
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
ctx.Report(node, "Don't use `document.cookie` directly; use the Cookie Store API or a wrapper.")
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
func init() {
|
|
40
|
+
Register(unicornNoDocumentCookie{})
|
|
41
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// unicorn/no-empty-file: a source file with no executable contribution
|
|
2
|
+
// — every statement is a bare `;` empty-statement (or there are no
|
|
3
|
+
// statements at all) — usually exists by accident: a placeholder kept
|
|
4
|
+
// around past its purpose, a generator output for a missing input, or
|
|
5
|
+
// a copy of a file whose body was deleted. The rule flags these so the
|
|
6
|
+
// file is either filled with content or removed.
|
|
7
|
+
//
|
|
8
|
+
// SourceFile dispatch: the engine fires `KindSourceFile` visits once
|
|
9
|
+
// per file at the file root (see engine.runFile). For visibility into
|
|
10
|
+
// where the diagnostic lands when reporters render `path:line:col`, the
|
|
11
|
+
// rule reports on the first statement node when one exists (so the
|
|
12
|
+
// pointer matches the file's source line); when the file truly has no
|
|
13
|
+
// statements at all it falls back to `ReportRange(0, 0, …)` so the
|
|
14
|
+
// diagnostic still surfaces.
|
|
15
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-empty-file.md
|
|
16
|
+
package linthost
|
|
17
|
+
|
|
18
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
19
|
+
|
|
20
|
+
type unicornNoEmptyFile struct{}
|
|
21
|
+
|
|
22
|
+
func (unicornNoEmptyFile) Name() string { return "unicorn/no-empty-file" }
|
|
23
|
+
func (unicornNoEmptyFile) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindSourceFile} }
|
|
24
|
+
func (unicornNoEmptyFile) Check(ctx *Context, node *shimast.Node) {
|
|
25
|
+
if ctx.File == nil {
|
|
26
|
+
return
|
|
27
|
+
}
|
|
28
|
+
statements := ctx.File.Statements
|
|
29
|
+
const message = "Empty files are not allowed."
|
|
30
|
+
if statements == nil || len(statements.Nodes) == 0 {
|
|
31
|
+
ctx.ReportRange(0, 0, message)
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
for _, stmt := range statements.Nodes {
|
|
35
|
+
if stmt == nil || stmt.Kind != shimast.KindEmptyStatement {
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
ctx.Report(statements.Nodes[0], message)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
func init() {
|
|
43
|
+
Register(unicornNoEmptyFile{})
|
|
44
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// unicorn/no-for-loop: the classic `for (let i = 0; i < arr.length; i++)`
|
|
2
|
+
// pattern is an index-based array walk that has a direct `for…of`
|
|
3
|
+
// translation. The index variable, the length re-read, and the manual
|
|
4
|
+
// increment are all incidental bookkeeping the language now expresses
|
|
5
|
+
// with one keyword.
|
|
6
|
+
//
|
|
7
|
+
// AST-only and syntactic: dispatch on `ForStatement` and match the
|
|
8
|
+
// three classic shapes — `let i = 0` initializer, `i < X.length`
|
|
9
|
+
// condition (the RHS must be a `.length` access; bare counters
|
|
10
|
+
// `i < n` are not flagged because the suggested `for…of` rewrite does
|
|
11
|
+
// not apply), and `i++` incrementor. The length operand is not
|
|
12
|
+
// required to resolve to an array at the type level; the syntactic
|
|
13
|
+
// shape is the signal the rule wants to discourage.
|
|
14
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-for-loop.md
|
|
15
|
+
package linthost
|
|
16
|
+
|
|
17
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
18
|
+
|
|
19
|
+
type unicornNoForLoop struct{}
|
|
20
|
+
|
|
21
|
+
func (unicornNoForLoop) Name() string { return "unicorn/no-for-loop" }
|
|
22
|
+
func (unicornNoForLoop) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindForStatement} }
|
|
23
|
+
func (unicornNoForLoop) Check(ctx *Context, node *shimast.Node) {
|
|
24
|
+
stmt := node.AsForStatement()
|
|
25
|
+
if stmt == nil || stmt.Initializer == nil || stmt.Condition == nil || stmt.Incrementor == nil {
|
|
26
|
+
return
|
|
27
|
+
}
|
|
28
|
+
indexName := indexInitializerName(stmt.Initializer)
|
|
29
|
+
if indexName == "" {
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
if !isLessThanCondition(stmt.Condition, indexName) {
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
if !isPostfixIncrementOf(stmt.Incrementor, indexName) {
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
ctx.Report(node, "Use `for…of` over an index-based `for` loop over an array.")
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// indexInitializerName returns the variable name of a `let i = 0`
|
|
42
|
+
// initializer, or "" when the initializer is anything else.
|
|
43
|
+
func indexInitializerName(init *shimast.Node) string {
|
|
44
|
+
if init == nil || init.Kind != shimast.KindVariableDeclarationList {
|
|
45
|
+
return ""
|
|
46
|
+
}
|
|
47
|
+
list := init.AsVariableDeclarationList()
|
|
48
|
+
if list == nil || list.Declarations == nil || len(list.Declarations.Nodes) != 1 {
|
|
49
|
+
return ""
|
|
50
|
+
}
|
|
51
|
+
decl := list.Declarations.Nodes[0].AsVariableDeclaration()
|
|
52
|
+
if decl == nil || decl.Initializer == nil {
|
|
53
|
+
return ""
|
|
54
|
+
}
|
|
55
|
+
if numericLiteralText(stripParens(decl.Initializer)) != "0" {
|
|
56
|
+
return ""
|
|
57
|
+
}
|
|
58
|
+
return identifierText(decl.Name())
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// isLessThanCondition reports whether `cond` has the shape
|
|
62
|
+
// `<name> < <something>.length`. The right-hand operand must be a
|
|
63
|
+
// property access ending in `length`; bare counter loops such as
|
|
64
|
+
// `for (let i = 0; i < n; i++)` are NOT flagged because the rule's
|
|
65
|
+
// suggested rewrite (`for…of`) only applies to array iteration.
|
|
66
|
+
func isLessThanCondition(cond *shimast.Node, name string) bool {
|
|
67
|
+
node := stripParens(cond)
|
|
68
|
+
if node == nil || node.Kind != shimast.KindBinaryExpression {
|
|
69
|
+
return false
|
|
70
|
+
}
|
|
71
|
+
bin := node.AsBinaryExpression()
|
|
72
|
+
if bin == nil || bin.OperatorToken == nil ||
|
|
73
|
+
bin.OperatorToken.Kind != shimast.KindLessThanToken {
|
|
74
|
+
return false
|
|
75
|
+
}
|
|
76
|
+
if identifierText(stripParens(bin.Left)) != name {
|
|
77
|
+
return false
|
|
78
|
+
}
|
|
79
|
+
right := stripParens(bin.Right)
|
|
80
|
+
if right == nil || right.Kind != shimast.KindPropertyAccessExpression {
|
|
81
|
+
return false
|
|
82
|
+
}
|
|
83
|
+
access := right.AsPropertyAccessExpression()
|
|
84
|
+
return access != nil && identifierText(access.Name()) == "length"
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// isPostfixIncrementOf reports whether `inc` has the shape `<name>++`.
|
|
88
|
+
func isPostfixIncrementOf(inc *shimast.Node, name string) bool {
|
|
89
|
+
node := stripParens(inc)
|
|
90
|
+
if node == nil || node.Kind != shimast.KindPostfixUnaryExpression {
|
|
91
|
+
return false
|
|
92
|
+
}
|
|
93
|
+
post := node.AsPostfixUnaryExpression()
|
|
94
|
+
if post == nil || post.Operator != shimast.KindPlusPlusToken {
|
|
95
|
+
return false
|
|
96
|
+
}
|
|
97
|
+
return identifierText(post.Operand) == name
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
func init() {
|
|
101
|
+
Register(unicornNoForLoop{})
|
|
102
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// unicorn/no-hex-escape: `\xHH` escapes inside string and template
|
|
2
|
+
// literals are legal but they read worse than the equivalent
|
|
3
|
+
// `\u00HH` Unicode escape — there's only one way to write a Unicode
|
|
4
|
+
// escape, while a hex escape silently widens to a Unicode escape at
|
|
5
|
+
// runtime anyway. The rule nudges authors toward the Unicode form.
|
|
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, so a normal accessor would see `©`
|
|
10
|
+
// instead of `\xA9`), and fire when the source contains a `\xHH`
|
|
11
|
+
// occurrence where HH is two hex digits.
|
|
12
|
+
//
|
|
13
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-hex-escape.md
|
|
14
|
+
package linthost
|
|
15
|
+
|
|
16
|
+
import (
|
|
17
|
+
"regexp"
|
|
18
|
+
|
|
19
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
var unicornNoHexEscapePattern = regexp.MustCompile(`\\x[0-9A-Fa-f]{2}`)
|
|
23
|
+
|
|
24
|
+
type unicornNoHexEscape struct{}
|
|
25
|
+
|
|
26
|
+
func (unicornNoHexEscape) Name() string { return "unicorn/no-hex-escape" }
|
|
27
|
+
func (unicornNoHexEscape) Visits() []shimast.Kind {
|
|
28
|
+
return []shimast.Kind{shimast.KindStringLiteral, shimast.KindNoSubstitutionTemplateLiteral}
|
|
29
|
+
}
|
|
30
|
+
func (unicornNoHexEscape) Check(ctx *Context, node *shimast.Node) {
|
|
31
|
+
source := nodeText(ctx.File, node)
|
|
32
|
+
if source == "" {
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
if unicornNoHexEscapePattern.MatchString(source) {
|
|
36
|
+
ctx.Report(node, "Prefer Unicode escapes (`\\uXXXX`) over hex escapes (`\\xHH`).")
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
func init() {
|
|
41
|
+
Register(unicornNoHexEscape{})
|
|
42
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// unicorn/no-immediate-mutation: mutating an expression on the same
|
|
2
|
+
// statement that produces it — e.g. `[1, 2, 3].push(4)` or
|
|
3
|
+
// `arr.map(...).sort()` — discards the mutator's return value (which is
|
|
4
|
+
// either the new length or `void`) and obscures whether the author
|
|
5
|
+
// wanted the array, the count, or the side effect. The rule splits the
|
|
6
|
+
// two operations: construct first, then mutate (or use the non-mutating
|
|
7
|
+
// counterpart).
|
|
8
|
+
//
|
|
9
|
+
// AST-only: visit each `CallExpression`. Match when the callee is a
|
|
10
|
+
// `PropertyAccessExpression(receiver, name)` where `name` is one of the
|
|
11
|
+
// mutating array methods AND the receiver (after `stripParens`) is
|
|
12
|
+
// either an `ArrayLiteralExpression` or another call expression whose
|
|
13
|
+
// callee is a non-mutating array method that produces a fresh array.
|
|
14
|
+
// Fire on the outer call.
|
|
15
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-immediate-mutation.md
|
|
16
|
+
package linthost
|
|
17
|
+
|
|
18
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
19
|
+
|
|
20
|
+
var unicornNoImmediateMutationMethods = map[string]struct{}{
|
|
21
|
+
"push": {},
|
|
22
|
+
"pop": {},
|
|
23
|
+
"shift": {},
|
|
24
|
+
"unshift": {},
|
|
25
|
+
"splice": {},
|
|
26
|
+
"sort": {},
|
|
27
|
+
"reverse": {},
|
|
28
|
+
"copyWithin": {},
|
|
29
|
+
"fill": {},
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
var unicornNoImmediateMutationFreshMethods = map[string]struct{}{
|
|
33
|
+
"map": {},
|
|
34
|
+
"filter": {},
|
|
35
|
+
"slice": {},
|
|
36
|
+
"concat": {},
|
|
37
|
+
"flat": {},
|
|
38
|
+
"flatMap": {},
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
type unicornNoImmediateMutation struct{}
|
|
42
|
+
|
|
43
|
+
func (unicornNoImmediateMutation) Name() string { return "unicorn/no-immediate-mutation" }
|
|
44
|
+
func (unicornNoImmediateMutation) Visits() []shimast.Kind {
|
|
45
|
+
return []shimast.Kind{shimast.KindCallExpression}
|
|
46
|
+
}
|
|
47
|
+
func (unicornNoImmediateMutation) Check(ctx *Context, node *shimast.Node) {
|
|
48
|
+
call := node.AsCallExpression()
|
|
49
|
+
if call == nil || call.Expression == nil {
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
if call.Expression.Kind != shimast.KindPropertyAccessExpression {
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
access := call.Expression.AsPropertyAccessExpression()
|
|
56
|
+
if access == nil {
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
method := identifierText(access.Name())
|
|
60
|
+
if _, ok := unicornNoImmediateMutationMethods[method]; !ok {
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
receiver := stripParens(access.Expression)
|
|
64
|
+
if receiver == nil {
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
if receiver.Kind == shimast.KindArrayLiteralExpression {
|
|
68
|
+
ctx.Report(node, "Don't mutate a freshly built array — separate the construction and the mutation, or use a non-mutating method.")
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
if receiver.Kind == shimast.KindCallExpression {
|
|
72
|
+
inner := receiver.AsCallExpression()
|
|
73
|
+
if inner == nil || inner.Expression == nil ||
|
|
74
|
+
inner.Expression.Kind != shimast.KindPropertyAccessExpression {
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
innerAccess := inner.Expression.AsPropertyAccessExpression()
|
|
78
|
+
if innerAccess == nil {
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
innerName := identifierText(innerAccess.Name())
|
|
82
|
+
if _, ok := unicornNoImmediateMutationFreshMethods[innerName]; ok {
|
|
83
|
+
ctx.Report(node, "Don't mutate a freshly built array — separate the construction and the mutation, or use a non-mutating method.")
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
func init() {
|
|
89
|
+
Register(unicornNoImmediateMutation{})
|
|
90
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// unicorn/no-instanceof-builtins: `x instanceof Array` (and the other
|
|
2
|
+
// built-in container constructors) is broken across realms and for
|
|
3
|
+
// user-defined subclasses. The cross-realm hazard is well known —
|
|
4
|
+
// `Array` in an iframe is a different constructor than the host
|
|
5
|
+
// `Array`, so a cross-realm value fails the check despite being an
|
|
6
|
+
// array; the subclass hazard is subtler — `instanceof` walks the
|
|
7
|
+
// prototype chain, so a `MyError extends Error` still passes
|
|
8
|
+
// `x instanceof Error` and obscures the actual type.
|
|
9
|
+
//
|
|
10
|
+
// AST-only: visit each `BinaryExpression` whose operator token is
|
|
11
|
+
// `instanceof`. The right-hand operand must be a bare identifier whose
|
|
12
|
+
// text appears in the built-in allowlist. Property-access or computed
|
|
13
|
+
// right-hand operands are out of scope because they cannot be matched
|
|
14
|
+
// syntactically against the global names.
|
|
15
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-instanceof-builtins.md
|
|
16
|
+
package linthost
|
|
17
|
+
|
|
18
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
19
|
+
|
|
20
|
+
var unicornNoInstanceofBuiltinsNames = map[string]struct{}{
|
|
21
|
+
"Array": {},
|
|
22
|
+
"Error": {},
|
|
23
|
+
"EvalError": {},
|
|
24
|
+
"RangeError": {},
|
|
25
|
+
"ReferenceError": {},
|
|
26
|
+
"SyntaxError": {},
|
|
27
|
+
"TypeError": {},
|
|
28
|
+
"URIError": {},
|
|
29
|
+
"AggregateError": {},
|
|
30
|
+
"Map": {},
|
|
31
|
+
"Set": {},
|
|
32
|
+
"WeakMap": {},
|
|
33
|
+
"WeakSet": {},
|
|
34
|
+
"Date": {},
|
|
35
|
+
"RegExp": {},
|
|
36
|
+
"Promise": {},
|
|
37
|
+
"Function": {},
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
type unicornNoInstanceofBuiltins struct{}
|
|
41
|
+
|
|
42
|
+
func (unicornNoInstanceofBuiltins) Name() string { return "unicorn/no-instanceof-builtins" }
|
|
43
|
+
func (unicornNoInstanceofBuiltins) Visits() []shimast.Kind {
|
|
44
|
+
return []shimast.Kind{shimast.KindBinaryExpression}
|
|
45
|
+
}
|
|
46
|
+
func (unicornNoInstanceofBuiltins) Check(ctx *Context, node *shimast.Node) {
|
|
47
|
+
bin := node.AsBinaryExpression()
|
|
48
|
+
if bin == nil || bin.OperatorToken == nil || bin.Right == nil {
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
if bin.OperatorToken.Kind != shimast.KindInstanceOfKeyword {
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
name := identifierText(bin.Right)
|
|
55
|
+
if name == "" {
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
if _, ok := unicornNoInstanceofBuiltinsNames[name]; !ok {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
ctx.Report(node, "Don't use `instanceof <Builtin>` — it breaks across realms and for subclasses. Use a type predicate or duck-typing instead.")
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
func init() {
|
|
65
|
+
Register(unicornNoInstanceofBuiltins{})
|
|
66
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// unicorn/no-invalid-fetch-options: passing a `body` together with a
|
|
2
|
+
// `GET` or `HEAD` `fetch()` call throws at runtime because the spec
|
|
3
|
+
// forbids a request body for those methods. The rule catches the
|
|
4
|
+
// mismatch at parse time so the throw never reaches production.
|
|
5
|
+
//
|
|
6
|
+
// AST-only: visit each `CallExpression`, match when the callee is a
|
|
7
|
+
// bare `fetch` identifier and the second argument is an object literal
|
|
8
|
+
// containing both a string-literal `method` of `GET` / `HEAD`
|
|
9
|
+
// (case-insensitive) AND a `body` property of any shape. Report on the
|
|
10
|
+
// call so the diagnostic lands at the offending site.
|
|
11
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-invalid-fetch-options.md
|
|
12
|
+
package linthost
|
|
13
|
+
|
|
14
|
+
import (
|
|
15
|
+
"strings"
|
|
16
|
+
|
|
17
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
type unicornNoInvalidFetchOptions struct{}
|
|
21
|
+
|
|
22
|
+
func (unicornNoInvalidFetchOptions) Name() string { return "unicorn/no-invalid-fetch-options" }
|
|
23
|
+
func (unicornNoInvalidFetchOptions) Visits() []shimast.Kind {
|
|
24
|
+
return []shimast.Kind{shimast.KindCallExpression}
|
|
25
|
+
}
|
|
26
|
+
func (unicornNoInvalidFetchOptions) Check(ctx *Context, node *shimast.Node) {
|
|
27
|
+
call := node.AsCallExpression()
|
|
28
|
+
if call == nil {
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
if identifierText(call.Expression) != "fetch" {
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
if call.Arguments == nil || len(call.Arguments.Nodes) < 2 {
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
init := stripParens(call.Arguments.Nodes[1])
|
|
38
|
+
if init == nil || init.Kind != shimast.KindObjectLiteralExpression {
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
obj := init.AsObjectLiteralExpression()
|
|
42
|
+
if obj == nil || obj.Properties == nil {
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
hasBody := false
|
|
46
|
+
methodIsBodyless := false
|
|
47
|
+
for _, prop := range obj.Properties.Nodes {
|
|
48
|
+
if prop == nil || prop.Kind != shimast.KindPropertyAssignment {
|
|
49
|
+
continue
|
|
50
|
+
}
|
|
51
|
+
assignment := prop.AsPropertyAssignment()
|
|
52
|
+
if assignment == nil || assignment.Name() == nil {
|
|
53
|
+
continue
|
|
54
|
+
}
|
|
55
|
+
key := identifierText(assignment.Name())
|
|
56
|
+
if key == "" && assignment.Name().Kind == shimast.KindStringLiteral {
|
|
57
|
+
key = stringLiteralText(assignment.Name())
|
|
58
|
+
}
|
|
59
|
+
switch key {
|
|
60
|
+
case "body":
|
|
61
|
+
hasBody = true
|
|
62
|
+
case "method":
|
|
63
|
+
value := stripParens(assignment.Initializer)
|
|
64
|
+
if value != nil && value.Kind == shimast.KindStringLiteral {
|
|
65
|
+
m := strings.ToLower(stringLiteralText(value))
|
|
66
|
+
if m == "get" || m == "head" {
|
|
67
|
+
methodIsBodyless = true
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if hasBody && methodIsBodyless {
|
|
73
|
+
ctx.Report(node, "Don't pass `body` with GET/HEAD `fetch` — it throws at runtime.")
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
func init() {
|
|
78
|
+
Register(unicornNoInvalidFetchOptions{})
|
|
79
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// unicorn/no-invalid-remove-event-listener: passing a fresh function
|
|
2
|
+
// literal to `removeEventListener` is a no-op because event-target
|
|
3
|
+
// internals match listeners by reference identity. The handler that was
|
|
4
|
+
// originally registered still fires; the call silently does nothing.
|
|
5
|
+
//
|
|
6
|
+
// AST-only: visit each `CallExpression`, match when the callee is a
|
|
7
|
+
// `PropertyAccessExpression(_, removeEventListener)` and the second
|
|
8
|
+
// argument (after stripping parens) is a fresh arrow function or
|
|
9
|
+
// function expression. Fire on the call so the diagnostic lands at the
|
|
10
|
+
// no-op site.
|
|
11
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-invalid-remove-event-listener.md
|
|
12
|
+
package linthost
|
|
13
|
+
|
|
14
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
15
|
+
|
|
16
|
+
type unicornNoInvalidRemoveEventListener struct{}
|
|
17
|
+
|
|
18
|
+
func (unicornNoInvalidRemoveEventListener) Name() string {
|
|
19
|
+
return "unicorn/no-invalid-remove-event-listener"
|
|
20
|
+
}
|
|
21
|
+
func (unicornNoInvalidRemoveEventListener) Visits() []shimast.Kind {
|
|
22
|
+
return []shimast.Kind{shimast.KindCallExpression}
|
|
23
|
+
}
|
|
24
|
+
func (unicornNoInvalidRemoveEventListener) 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 || identifierText(access.Name()) != "removeEventListener" {
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
if call.Arguments == nil || len(call.Arguments.Nodes) < 2 {
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
handler := stripParens(call.Arguments.Nodes[1])
|
|
40
|
+
if handler == nil {
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
switch handler.Kind {
|
|
44
|
+
case shimast.KindArrowFunction, shimast.KindFunctionExpression:
|
|
45
|
+
ctx.Report(node, "Calling `removeEventListener` with a fresh function reference removes nothing — store and reuse the handler.")
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
func init() {
|
|
50
|
+
Register(unicornNoInvalidRemoveEventListener{})
|
|
51
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// unicorn/no-keyword-prefix: identifiers like `newFoo` or `classBar`
|
|
2
|
+
// embed a reserved word at the prefix position so the reader has to
|
|
3
|
+
// re-parse the identifier each time. The rule discourages the prefix in
|
|
4
|
+
// declarations so the codebase converges on names whose first segment
|
|
5
|
+
// is not a JavaScript keyword.
|
|
6
|
+
//
|
|
7
|
+
// AST-only: visit every `Identifier` and fire only on declaration
|
|
8
|
+
// positions (parameter, variable, function, class, method, accessor,
|
|
9
|
+
// property, binding-element names). Reads of an already-named binding
|
|
10
|
+
// are NOT flagged — the diagnostic is anchored on the declaration so
|
|
11
|
+
// the rename happens once. Uses the same value-position-gate logic as
|
|
12
|
+
// `prefer-global-this`, inverted: this rule needs the identifier to be
|
|
13
|
+
// in a *name* slot, not a value-expression slot.
|
|
14
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-keyword-prefix.md
|
|
15
|
+
package linthost
|
|
16
|
+
|
|
17
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
18
|
+
|
|
19
|
+
type unicornNoKeywordPrefix struct{}
|
|
20
|
+
|
|
21
|
+
func (unicornNoKeywordPrefix) Name() string { return "unicorn/no-keyword-prefix" }
|
|
22
|
+
func (unicornNoKeywordPrefix) Visits() []shimast.Kind {
|
|
23
|
+
return []shimast.Kind{shimast.KindIdentifier}
|
|
24
|
+
}
|
|
25
|
+
func (unicornNoKeywordPrefix) Check(ctx *Context, node *shimast.Node) {
|
|
26
|
+
name := identifierText(node)
|
|
27
|
+
if !hasKeywordPrefix(name) {
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
if !isUnicornDeclarationPositionIdentifier(node) {
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
ctx.Report(node, "Don't prefix identifiers with a reserved word (`new` / `class`).")
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// hasKeywordPrefix reports whether `name` starts with `new` or `class`
|
|
37
|
+
// followed by an uppercase ASCII letter. The case-sensitive prefix +
|
|
38
|
+
// the uppercase next letter together pin the camelCase pattern the rule
|
|
39
|
+
// targets (`newFoo`, `classBar`); plain words like `news` or `classic`
|
|
40
|
+
// share the prefix bytes but not the camelCase break and are out of
|
|
41
|
+
// scope.
|
|
42
|
+
func hasKeywordPrefix(name string) bool {
|
|
43
|
+
for _, prefix := range []string{"new", "class"} {
|
|
44
|
+
if len(name) <= len(prefix) {
|
|
45
|
+
continue
|
|
46
|
+
}
|
|
47
|
+
if name[:len(prefix)] != prefix {
|
|
48
|
+
continue
|
|
49
|
+
}
|
|
50
|
+
next := name[len(prefix)]
|
|
51
|
+
if next >= 'A' && next <= 'Z' {
|
|
52
|
+
return true
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return false
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// isUnicornDeclarationPositionIdentifier reports whether `node` (a bare
|
|
59
|
+
// Identifier) appears as a *name* slot of a declaration, i.e. the slot
|
|
60
|
+
// reserved by the language for introducing a new binding. Reads,
|
|
61
|
+
// property keys on accesses, type references, and labels are filtered
|
|
62
|
+
// out so the rule only fires on declarations.
|
|
63
|
+
func isUnicornDeclarationPositionIdentifier(node *shimast.Node) bool {
|
|
64
|
+
if node == nil || node.Kind != shimast.KindIdentifier || node.Parent == nil {
|
|
65
|
+
return false
|
|
66
|
+
}
|
|
67
|
+
parent := node.Parent
|
|
68
|
+
switch parent.Kind {
|
|
69
|
+
case shimast.KindVariableDeclaration:
|
|
70
|
+
decl := parent.AsVariableDeclaration()
|
|
71
|
+
return decl != nil && decl.Name() == node
|
|
72
|
+
case shimast.KindBindingElement:
|
|
73
|
+
elem := parent.AsBindingElement()
|
|
74
|
+
return elem != nil && elem.Name() == node
|
|
75
|
+
case shimast.KindParameter:
|
|
76
|
+
param := parent.AsParameterDeclaration()
|
|
77
|
+
return param != nil && param.Name() == node
|
|
78
|
+
case shimast.KindFunctionDeclaration:
|
|
79
|
+
fn := parent.AsFunctionDeclaration()
|
|
80
|
+
return fn != nil && fn.Name() == node
|
|
81
|
+
case shimast.KindFunctionExpression:
|
|
82
|
+
fn := parent.AsFunctionExpression()
|
|
83
|
+
return fn != nil && fn.Name() == node
|
|
84
|
+
case shimast.KindClassDeclaration:
|
|
85
|
+
cls := parent.AsClassDeclaration()
|
|
86
|
+
return cls != nil && cls.Name() == node
|
|
87
|
+
case shimast.KindClassExpression:
|
|
88
|
+
cls := parent.AsClassExpression()
|
|
89
|
+
return cls != nil && cls.Name() == node
|
|
90
|
+
case shimast.KindMethodDeclaration,
|
|
91
|
+
shimast.KindGetAccessor,
|
|
92
|
+
shimast.KindSetAccessor,
|
|
93
|
+
shimast.KindPropertyDeclaration:
|
|
94
|
+
return true
|
|
95
|
+
}
|
|
96
|
+
return false
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
func init() {
|
|
100
|
+
Register(unicornNoKeywordPrefix{})
|
|
101
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// unicorn/no-lonely-if: `else { if (cond) { … } }` collapses to
|
|
2
|
+
// `else if (cond) { … }`. Wrapping a single `if` in an `else` block
|
|
3
|
+
// adds an extra brace pair and an extra indentation level without
|
|
4
|
+
// changing semantics, so the rule flags it as redundant punctuation.
|
|
5
|
+
//
|
|
6
|
+
// AST-only and parent-walking: visit every `IfStatement`, then check
|
|
7
|
+
// whether its parent is a `Block` containing exactly this one
|
|
8
|
+
// statement AND that block is the `ElseStatement` of an outer
|
|
9
|
+
// `IfStatement`. Mirrors the core `no-lonely-if` rule shape.
|
|
10
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-lonely-if.md
|
|
11
|
+
package linthost
|
|
12
|
+
|
|
13
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
14
|
+
|
|
15
|
+
type unicornNoLonelyIf struct{}
|
|
16
|
+
|
|
17
|
+
func (unicornNoLonelyIf) Name() string { return "unicorn/no-lonely-if" }
|
|
18
|
+
func (unicornNoLonelyIf) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindIfStatement} }
|
|
19
|
+
func (unicornNoLonelyIf) Check(ctx *Context, node *shimast.Node) {
|
|
20
|
+
parent := node.Parent
|
|
21
|
+
if parent == nil || parent.Kind != shimast.KindBlock {
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
block := parent.AsBlock()
|
|
25
|
+
if block == nil || block.Statements == nil {
|
|
26
|
+
return
|
|
27
|
+
}
|
|
28
|
+
if len(block.Statements.Nodes) != 1 {
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
grand := parent.Parent
|
|
32
|
+
if grand == nil || grand.Kind != shimast.KindIfStatement {
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
gif := grand.AsIfStatement()
|
|
36
|
+
if gif == nil || gif.ElseStatement != parent {
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
ctx.Report(node, "Use `else if` instead of an `if` as the only statement inside an `else` block.")
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
func init() {
|
|
43
|
+
Register(unicornNoLonelyIf{})
|
|
44
|
+
}
|