@ttsc/lint 0.14.0-dev.20260529.2 → 0.14.0
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 +21 -23
- package/lib/defaultFormat.d.ts +10 -6
- package/lib/defaultFormat.js +10 -6
- package/lib/defaultFormat.js.map +1 -1
- package/lib/structures/ITtscLintConfig.d.ts +5 -5
- package/lib/structures/TtscLintRuleSetting.d.ts +19 -19
- package/lib/structures/{ITtscLintFormat.d.ts → format/ITtscLintFormat.d.ts} +45 -70
- package/lib/structures/format/ITtscLintFormat.js.map +1 -0
- package/lib/structures/format/ITtscLintFormatJsDoc.d.ts +15 -0
- package/lib/structures/format/ITtscLintFormatJsDoc.js +3 -0
- 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 +1 -1
- package/lib/structures/index.js +1 -1
- package/lib/structures/index.js.map +1 -1
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.d.ts +18 -27
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js +4 -5
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js.map +1 -1
- package/lib/structures/rules/ITtscLintBoundariesRules.d.ts +29 -33
- package/lib/structures/rules/ITtscLintContributorRules.d.ts +6 -7
- package/lib/structures/rules/ITtscLintCoreRules.d.ts +380 -408
- package/lib/structures/rules/ITtscLintCypressRuleOptions.d.ts +5 -5
- package/lib/structures/rules/ITtscLintCypressRuleOptions.js +2 -2
- package/lib/structures/rules/ITtscLintCypressRules.d.ts +34 -38
- package/lib/structures/rules/ITtscLintFunctionalRuleOptions.d.ts +21 -24
- package/lib/structures/rules/ITtscLintFunctionalRuleOptions.js +2 -2
- package/lib/structures/rules/ITtscLintFunctionalRules.d.ts +51 -56
- package/lib/structures/rules/ITtscLintJestRules.d.ts +63 -74
- package/lib/structures/rules/ITtscLintJsdocRules.d.ts +47 -54
- package/lib/structures/rules/ITtscLintJsxA11yRules.d.ts +94 -102
- package/lib/structures/rules/ITtscLintNextjsRules.d.ts +50 -55
- package/lib/structures/rules/ITtscLintPlaywrightRules.d.ts +104 -122
- package/lib/structures/rules/ITtscLintPromiseRules.d.ts +62 -71
- package/lib/structures/rules/ITtscLintReactPerfRuleOptions.d.ts +4 -4
- package/lib/structures/rules/ITtscLintReactPerfRules.d.ts +17 -19
- package/lib/structures/rules/ITtscLintReactRuleOptions.d.ts +8 -10
- package/lib/structures/rules/ITtscLintReactRuleOptions.js +1 -2
- package/lib/structures/rules/ITtscLintReactRuleOptions.js.map +1 -1
- package/lib/structures/rules/ITtscLintReactRules.d.ts +91 -104
- package/lib/structures/rules/ITtscLintRegexpRules.d.ts +46 -54
- package/lib/structures/rules/ITtscLintRuleOptionsMap.d.ts +7 -8
- package/lib/structures/rules/ITtscLintSecurityRules.d.ts +45 -52
- package/lib/structures/rules/ITtscLintSolidRules.d.ts +53 -56
- package/lib/structures/rules/ITtscLintStorybookRuleOptions.d.ts +3 -4
- package/lib/structures/rules/ITtscLintStorybookRules.d.ts +60 -69
- package/lib/structures/rules/ITtscLintTanstackQueryRules.d.ts +31 -37
- package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.d.ts +2 -3
- package/lib/structures/rules/ITtscLintTestingLibraryRules.d.ts +102 -119
- package/lib/structures/rules/ITtscLintTypeScriptRules.d.ts +460 -518
- package/lib/structures/rules/ITtscLintVitestRules.d.ts +43 -51
- package/linthost/config.go +89 -72
- package/linthost/config_format.go +265 -99
- package/linthost/directives.go +5 -1
- package/linthost/display_width.go +72 -0
- package/linthost/fix.go +26 -1
- package/linthost/format.go +222 -25
- package/linthost/format_editor_settings.go +262 -0
- package/linthost/lsp.go +8 -4
- package/linthost/print_dispatch.go +3 -0
- package/linthost/print_doc.go +13 -0
- package/linthost/print_engine.go +68 -11
- package/linthost/print_nodes_array.go +108 -5
- package/linthost/print_nodes_call.go +515 -74
- package/linthost/print_nodes_function.go +25 -0
- package/linthost/print_nodes_imports.go +47 -14
- package/linthost/print_nodes_list.go +191 -8
- package/linthost/print_nodes_object.go +12 -6
- package/linthost/print_nodes_ternary.go +106 -0
- package/linthost/rules_boundaries.go +400 -400
- package/linthost/rules_camelcase.go +81 -81
- package/linthost/rules_complexity.go +52 -51
- package/linthost/rules_consistent_return.go +81 -81
- package/linthost/rules_core_extra.go +472 -472
- package/linthost/rules_curly.go +43 -43
- package/linthost/rules_default_case.go +15 -15
- package/linthost/rules_default_case_last.go +22 -22
- 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 +664 -0
- package/linthost/rules_format_indent.go +616 -0
- package/linthost/rules_format_jsdoc.go +4 -4
- 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 +185 -69
- package/linthost/rules_format_quote_props.go +169 -0
- package/linthost/rules_format_quotes.go +75 -29
- package/linthost/rules_format_semi.go +185 -10
- package/linthost/rules_format_sort_imports.go +456 -121
- package/linthost/rules_format_statement_split.go +368 -0
- package/linthost/rules_format_ternary_nullish_parens.go +77 -0
- package/linthost/rules_format_trailing_comma.go +21 -2
- package/linthost/rules_format_whitespace.go +336 -0
- package/linthost/rules_functional.go +688 -688
- package/linthost/rules_gap.go +146 -11
- package/linthost/rules_grouped_accessor_pairs.go +60 -60
- package/linthost/rules_guard_for_in.go +122 -122
- package/linthost/rules_id_length.go +44 -44
- package/linthost/rules_imports.go +11 -3
- package/linthost/rules_init_declarations.go +25 -25
- package/linthost/rules_jsx_a11y.go +844 -844
- package/linthost/rules_max_classes_per_file.go +24 -24
- package/linthost/rules_max_depth.go +43 -43
- package/linthost/rules_max_lines.go +53 -53
- package/linthost/rules_max_lines_per_function.go +28 -28
- package/linthost/rules_max_nested_callbacks.go +26 -26
- package/linthost/rules_max_params.go +20 -20
- package/linthost/rules_max_statements.go +29 -29
- package/linthost/rules_nextjs.go +5 -5
- package/linthost/rules_no_else_return.go +38 -38
- package/linthost/rules_no_empty_named_blocks.go +45 -45
- package/linthost/rules_no_import_assign.go +96 -96
- package/linthost/rules_no_invalid_this.go +19 -19
- package/linthost/rules_no_loop_func.go +43 -43
- package/linthost/rules_no_magic_numbers.go +60 -60
- package/linthost/rules_no_mixed_operators.go +44 -44
- package/linthost/rules_no_param_reassign.go +64 -64
- package/linthost/rules_no_restricted_imports.go +45 -45
- package/linthost/rules_no_restricted_syntax.go +17 -17
- package/linthost/rules_no_shadow.go +112 -112
- package/linthost/rules_no_unreachable.go +36 -36
- package/linthost/rules_no_useless_assignment.go +79 -79
- package/linthost/rules_no_useless_constructor.go +167 -167
- package/linthost/rules_no_useless_return.go +28 -28
- package/linthost/rules_prefer_arrow_callback.go +74 -74
- package/linthost/rules_prefer_destructuring.go +61 -61
- package/linthost/rules_prefer_named_capture_group.go +87 -87
- package/linthost/rules_prefer_rest_params.go +61 -61
- package/linthost/rules_promise.go +800 -800
- package/linthost/rules_react.go +600 -600
- package/linthost/rules_react_extras.go +162 -162
- package/linthost/rules_react_hooks.go +2 -2
- package/linthost/rules_react_perf.go +231 -231
- package/linthost/rules_regexp.go +293 -293
- package/linthost/rules_security.go +613 -613
- package/linthost/rules_sort_imports.go +37 -37
- package/linthost/rules_sort_keys.go +88 -88
- package/linthost/rules_suggestions.go +13 -0
- package/linthost/rules_ts.go +2 -2
- package/linthost/rules_ts_async.go +247 -247
- package/linthost/rules_ts_class_literal_property_style.go +64 -64
- package/linthost/rules_ts_consistent_type_exports.go +209 -209
- package/linthost/rules_ts_explicit_function_return_type.go +35 -35
- package/linthost/rules_ts_extra.go +6 -2
- package/linthost/rules_ts_no_base_to_string.go +140 -140
- package/linthost/rules_ts_no_confusing_void.go +28 -28
- package/linthost/rules_ts_no_deprecated.go +110 -110
- package/linthost/rules_ts_no_for_in_array.go +45 -45
- package/linthost/rules_ts_no_magic_numbers.go +67 -67
- package/linthost/rules_ts_no_meaningless_void_operator.go +44 -44
- package/linthost/rules_ts_no_misused_spread.go +64 -64
- package/linthost/rules_ts_no_redundant_type_constituents.go +72 -72
- package/linthost/rules_ts_no_restricted_types.go +28 -28
- package/linthost/rules_ts_no_unnecessary_boolean_literal_compare.go +87 -87
- package/linthost/rules_ts_no_unnecessary_condition.go +184 -184
- package/linthost/rules_ts_no_unnecessary_qualifier.go +72 -72
- package/linthost/rules_ts_no_unnecessary_template_expression.go +120 -120
- package/linthost/rules_ts_no_unnecessary_type_arguments.go +171 -171
- package/linthost/rules_ts_no_unnecessary_type_assertion.go +90 -90
- package/linthost/rules_ts_no_unsafe_argument.go +50 -50
- package/linthost/rules_ts_no_unsafe_assignment.go +60 -60
- package/linthost/rules_ts_no_unsafe_call.go +40 -40
- package/linthost/rules_ts_no_unsafe_enum_comparison.go +147 -147
- package/linthost/rules_ts_no_unsafe_member_access.go +29 -29
- package/linthost/rules_ts_no_unsafe_return.go +64 -64
- package/linthost/rules_ts_no_unsafe_unary_minus.go +42 -42
- package/linthost/rules_ts_no_useless_constructor.go +20 -20
- package/linthost/rules_ts_non_nullable_type_assertion_style.go +60 -60
- package/linthost/rules_ts_parameter_properties.go +10 -10
- package/linthost/rules_ts_prefer_find.go +116 -116
- package/linthost/rules_ts_prefer_includes.go +173 -173
- package/linthost/rules_ts_prefer_nullish_coalescing.go +54 -54
- package/linthost/rules_ts_prefer_optional_chain.go +156 -156
- package/linthost/rules_ts_prefer_promise_reject_errors.go +104 -104
- package/linthost/rules_ts_prefer_readonly.go +31 -31
- package/linthost/rules_ts_prefer_reduce_type_parameter.go +74 -74
- package/linthost/rules_ts_prefer_regexp_exec.go +69 -69
- package/linthost/rules_ts_prefer_return_this_type.go +79 -79
- package/linthost/rules_ts_prefer_string_starts_ends_with.go +237 -237
- package/linthost/rules_ts_promise_function_async.go +41 -41
- package/linthost/rules_ts_related_getter_setter_pairs.go +61 -61
- package/linthost/rules_ts_require_array_sort_compare.go +58 -58
- package/linthost/rules_ts_restrict_plus_operands.go +82 -82
- package/linthost/rules_ts_restrict_template_expressions.go +50 -50
- package/linthost/rules_ts_simple.go +249 -249
- package/linthost/rules_ts_sort_type_constituents.go +88 -88
- package/linthost/rules_ts_strict_boolean_expressions.go +103 -103
- package/linthost/rules_ts_switch_exhaustiveness_check.go +90 -90
- package/linthost/rules_ts_unbound_method.go +65 -65
- package/linthost/rules_tsdoc.go +88 -88
- package/linthost/rules_unicorn_better_regex.go +1 -1
- package/linthost/rules_unicorn_catch_error_name.go +19 -19
- package/linthost/rules_unicorn_consistent_assert.go +20 -20
- package/linthost/rules_unicorn_consistent_date_clone.go +27 -27
- package/linthost/rules_unicorn_consistent_destructuring.go +3 -3
- package/linthost/rules_unicorn_consistent_empty_array_spread.go +34 -34
- package/linthost/rules_unicorn_consistent_existence_index_check.go +42 -42
- package/linthost/rules_unicorn_consistent_function_scoping.go +3 -3
- package/linthost/rules_unicorn_consistent_template_literal_escape.go +3 -3
- package/linthost/rules_unicorn_custom_error_definition.go +92 -92
- package/linthost/rules_unicorn_empty_brace_spaces.go +47 -47
- package/linthost/rules_unicorn_error_message.go +34 -34
- package/linthost/rules_unicorn_escape_case.go +14 -14
- package/linthost/rules_unicorn_expiring_todo_comments.go +36 -36
- package/linthost/rules_unicorn_explicit_length_check.go +51 -51
- package/linthost/rules_unicorn_filename_case.go +1 -1
- package/linthost/rules_unicorn_import_style.go +1 -1
- package/linthost/rules_unicorn_isolated_functions.go +2 -2
- package/linthost/rules_unicorn_new_for_builtins.go +49 -49
- package/linthost/rules_unicorn_no_abusive_eslint_disable.go +31 -31
- package/linthost/rules_unicorn_no_accessor_recursion.go +69 -69
- package/linthost/rules_unicorn_no_anonymous_default_export.go +40 -40
- package/linthost/rules_unicorn_no_array_callback_reference.go +33 -33
- package/linthost/rules_unicorn_no_array_for_each.go +14 -14
- package/linthost/rules_unicorn_no_array_method_this_argument.go +29 -29
- package/linthost/rules_unicorn_no_array_reduce.go +15 -15
- package/linthost/rules_unicorn_no_array_reverse.go +17 -17
- package/linthost/rules_unicorn_no_array_sort.go +17 -17
- package/linthost/rules_unicorn_no_await_expression_member.go +12 -12
- package/linthost/rules_unicorn_no_await_in_promise_methods.go +38 -38
- package/linthost/rules_unicorn_no_console_spaces.go +30 -30
- package/linthost/rules_unicorn_no_document_cookie.go +13 -13
- package/linthost/rules_unicorn_no_empty_file.go +16 -16
- package/linthost/rules_unicorn_no_for_loop.go +58 -58
- package/linthost/rules_unicorn_no_hex_escape.go +11 -11
- package/linthost/rules_unicorn_no_immediate_mutation.go +55 -55
- package/linthost/rules_unicorn_no_instanceof_builtins.go +34 -34
- package/linthost/rules_unicorn_no_invalid_fetch_options.go +52 -52
- package/linthost/rules_unicorn_no_invalid_remove_event_listener.go +25 -25
- package/linthost/rules_unicorn_no_keyword_prefix.go +56 -56
- package/linthost/rules_unicorn_no_lonely_if.go +21 -21
- package/linthost/rules_unicorn_no_magic_array_flat_depth.go +22 -22
- package/linthost/rules_unicorn_no_named_default.go +25 -25
- package/linthost/rules_unicorn_no_negated_condition.go +54 -54
- package/linthost/rules_unicorn_no_negation_in_equality_check.go +23 -23
- package/linthost/rules_unicorn_no_nested_ternary.go +15 -15
- package/linthost/rules_unicorn_no_new_array.go +5 -5
- package/linthost/rules_unicorn_no_new_buffer.go +5 -5
- package/linthost/rules_unicorn_no_null.go +2 -2
- package/linthost/rules_unicorn_no_object_as_default_parameter.go +19 -19
- package/linthost/rules_unicorn_no_process_exit.go +17 -17
- package/linthost/rules_unicorn_no_single_promise_in_promise_methods.go +29 -29
- package/linthost/rules_unicorn_no_static_only_class.go +27 -27
- package/linthost/rules_unicorn_no_thenable.go +47 -47
- package/linthost/rules_unicorn_no_this_assignment.go +10 -10
- package/linthost/rules_unicorn_no_typeof_undefined.go +31 -31
- package/linthost/rules_unicorn_no_unnecessary_array_flat_depth.go +23 -23
- package/linthost/rules_unicorn_no_unnecessary_array_splice_count.go +37 -37
- package/linthost/rules_unicorn_no_unnecessary_await.go +24 -24
- package/linthost/rules_unicorn_no_unnecessary_slice_end.go +22 -22
- package/linthost/rules_unicorn_no_unreadable_array_destructuring.go +67 -67
- package/linthost/rules_unicorn_no_unreadable_iife.go +22 -22
- package/linthost/rules_unicorn_no_useless_collection_argument.go +34 -34
- package/linthost/rules_unicorn_no_useless_error_capture_stack_trace.go +18 -18
- package/linthost/rules_unicorn_no_useless_fallback_in_spread.go +49 -49
- package/linthost/rules_unicorn_no_useless_iterator_to_array.go +41 -41
- package/linthost/rules_unicorn_no_useless_length_check.go +82 -82
- package/linthost/rules_unicorn_no_useless_promise_resolve_reject.go +42 -42
- package/linthost/rules_unicorn_no_useless_spread.go +38 -38
- package/linthost/rules_unicorn_no_useless_switch_case.go +29 -29
- package/linthost/rules_unicorn_no_useless_undefined.go +25 -25
- package/linthost/rules_unicorn_no_zero_fractions.go +17 -17
- package/linthost/rules_unicorn_number_literal_case.go +33 -33
- package/linthost/rules_unicorn_numeric_separators_style.go +36 -36
- package/linthost/rules_unicorn_prefer_add_event_listener.go +30 -30
- package/linthost/rules_unicorn_prefer_array_find.go +27 -27
- package/linthost/rules_unicorn_prefer_array_flat.go +25 -25
- package/linthost/rules_unicorn_prefer_array_flat_map.go +37 -37
- package/linthost/rules_unicorn_prefer_array_index_of.go +108 -108
- package/linthost/rules_unicorn_prefer_array_some.go +43 -43
- package/linthost/rules_unicorn_prefer_at.go +42 -42
- package/linthost/rules_unicorn_prefer_bigint_literals.go +42 -42
- package/linthost/rules_unicorn_prefer_blob_reading_methods.go +15 -15
- package/linthost/rules_unicorn_prefer_class_fields.go +57 -57
- package/linthost/rules_unicorn_prefer_classlist_toggle.go +76 -76
- package/linthost/rules_unicorn_prefer_code_point.go +21 -21
- package/linthost/rules_unicorn_prefer_date_now.go +47 -47
- package/linthost/rules_unicorn_prefer_default_parameters.go +96 -96
- package/linthost/rules_unicorn_prefer_dom_node_append.go +14 -14
- package/linthost/rules_unicorn_prefer_dom_node_dataset.go +27 -27
- package/linthost/rules_unicorn_prefer_dom_node_remove.go +17 -17
- package/linthost/rules_unicorn_prefer_dom_node_text_content.go +11 -11
- package/linthost/rules_unicorn_prefer_event_target.go +10 -10
- package/linthost/rules_unicorn_prefer_export_from.go +99 -99
- package/linthost/rules_unicorn_prefer_global_this.go +91 -91
- package/linthost/rules_unicorn_prefer_import_meta_properties.go +38 -38
- package/linthost/rules_unicorn_prefer_includes.go +108 -108
- package/linthost/rules_unicorn_prefer_json_parse_buffer.go +37 -37
- package/linthost/rules_unicorn_prefer_keyboard_event_key.go +10 -10
- package/linthost/rules_unicorn_prefer_logical_operator_over_ternary.go +20 -20
- package/linthost/rules_unicorn_prefer_math_min_max.go +33 -33
- package/linthost/rules_unicorn_prefer_math_trunc.go +32 -32
- package/linthost/rules_unicorn_prefer_modern_dom_apis.go +18 -18
- package/linthost/rules_unicorn_prefer_modern_math_apis.go +38 -38
- package/linthost/rules_unicorn_prefer_module.go +22 -22
- package/linthost/rules_unicorn_prefer_native_coercion_functions.go +73 -73
- package/linthost/rules_unicorn_prefer_negative_index.go +46 -46
- package/linthost/rules_unicorn_prefer_node_protocol.go +90 -90
- package/linthost/rules_unicorn_prefer_number_properties.go +57 -57
- package/linthost/rules_unicorn_prefer_object_from_entries.go +26 -26
- package/linthost/rules_unicorn_prefer_optional_catch_binding.go +24 -24
- package/linthost/rules_unicorn_prefer_prototype_methods.go +25 -25
- package/linthost/rules_unicorn_prefer_query_selector.go +25 -25
- package/linthost/rules_unicorn_prefer_reflect_apply.go +10 -10
- package/linthost/rules_unicorn_prefer_regexp_test_rule.go +47 -47
- package/linthost/rules_unicorn_prefer_response_static_json.go +26 -26
- package/linthost/rules_unicorn_prefer_set_has.go +16 -16
- package/linthost/rules_unicorn_prefer_set_size.go +22 -22
- package/linthost/rules_unicorn_prefer_simple_condition_first.go +3 -3
- package/linthost/rules_unicorn_prefer_single_call.go +59 -59
- package/linthost/rules_unicorn_prefer_spread.go +24 -24
- package/linthost/rules_unicorn_prefer_string_raw.go +12 -12
- package/linthost/rules_unicorn_prefer_string_replace_all.go +46 -46
- package/linthost/rules_unicorn_prefer_string_slice.go +17 -17
- package/linthost/rules_unicorn_prefer_string_starts_ends_with.go +104 -104
- package/linthost/rules_unicorn_prefer_string_trim_start_end.go +21 -21
- package/linthost/rules_unicorn_prefer_structured_clone.go +36 -36
- package/linthost/rules_unicorn_prefer_switch.go +65 -65
- package/linthost/rules_unicorn_prefer_ternary.go +35 -35
- package/linthost/rules_unicorn_prefer_top_level_await.go +34 -34
- package/linthost/rules_unicorn_prefer_type_error.go +84 -84
- package/linthost/rules_unicorn_prevent_abbreviations.go +68 -68
- package/linthost/rules_unicorn_relative_url_style.go +19 -19
- package/linthost/rules_unicorn_require_array_join_separator.go +18 -18
- package/linthost/rules_unicorn_require_module_attributes.go +25 -25
- package/linthost/rules_unicorn_require_module_specifiers.go +28 -28
- package/linthost/rules_unicorn_require_number_to_fixed_digits_argument.go +18 -18
- package/linthost/rules_unicorn_require_post_message_target_origin.go +18 -18
- package/linthost/rules_unicorn_string_content.go +1 -1
- package/linthost/rules_unicorn_switch_case_braces.go +16 -16
- package/linthost/rules_unicorn_switch_case_break_position.go +3 -3
- package/linthost/rules_unicorn_template_indent.go +1 -1
- package/linthost/rules_unicorn_text_encoding_identifier_case.go +36 -36
- package/linthost/rules_unicorn_throw_new_error.go +30 -30
- package/linthost/rules_var.go +273 -3
- package/package.json +3 -3
- package/src/defaultFormat.ts +11 -7
- package/src/structures/ITtscLintConfig.ts +5 -5
- package/src/structures/TtscLintRuleSetting.ts +19 -19
- package/src/structures/{ITtscLintFormat.ts → format/ITtscLintFormat.ts} +48 -75
- package/src/structures/format/ITtscLintFormatJsDoc.ts +16 -0
- package/src/structures/format/ITtscLintFormatSortImports.ts +62 -0
- package/src/structures/format/index.ts +3 -0
- package/src/structures/index.ts +1 -1
- package/src/structures/rules/ITtscLintBoundariesRuleOptions.ts +20 -31
- package/src/structures/rules/ITtscLintBoundariesRules.ts +32 -36
- package/src/structures/rules/ITtscLintContributorRules.ts +6 -7
- package/src/structures/rules/ITtscLintCoreRules.ts +380 -408
- package/src/structures/rules/ITtscLintCypressRuleOptions.ts +5 -5
- package/src/structures/rules/ITtscLintCypressRules.ts +34 -38
- package/src/structures/rules/ITtscLintFunctionalRuleOptions.ts +28 -41
- package/src/structures/rules/ITtscLintFunctionalRules.ts +51 -56
- package/src/structures/rules/ITtscLintJestRules.ts +63 -74
- package/src/structures/rules/ITtscLintJsdocRules.ts +47 -54
- package/src/structures/rules/ITtscLintJsxA11yRules.ts +94 -102
- package/src/structures/rules/ITtscLintNextjsRules.ts +50 -55
- package/src/structures/rules/ITtscLintPlaywrightRules.ts +104 -122
- package/src/structures/rules/ITtscLintPromiseRules.ts +62 -71
- package/src/structures/rules/ITtscLintReactPerfRuleOptions.ts +4 -4
- package/src/structures/rules/ITtscLintReactPerfRules.ts +17 -19
- package/src/structures/rules/ITtscLintReactRuleOptions.ts +8 -10
- package/src/structures/rules/ITtscLintReactRules.ts +91 -104
- package/src/structures/rules/ITtscLintRegexpRules.ts +46 -54
- package/src/structures/rules/ITtscLintRuleOptionsMap.ts +7 -8
- package/src/structures/rules/ITtscLintSecurityRules.ts +45 -52
- package/src/structures/rules/ITtscLintSolidRules.ts +53 -56
- package/src/structures/rules/ITtscLintStorybookRuleOptions.ts +3 -4
- package/src/structures/rules/ITtscLintStorybookRules.ts +60 -69
- package/src/structures/rules/ITtscLintTanstackQueryRules.ts +31 -37
- package/src/structures/rules/ITtscLintTestingLibraryRuleOptions.ts +2 -3
- package/src/structures/rules/ITtscLintTestingLibraryRules.ts +102 -119
- package/src/structures/rules/ITtscLintTypeScriptRules.ts +460 -518
- package/src/structures/rules/ITtscLintVitestRules.ts +43 -51
- package/lib/structures/ITtscLintFormat.js.map +0 -1
- /package/lib/structures/{ITtscLintFormat.js → format/ITtscLintFormat.js} +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
package linthost
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
"regexp"
|
|
5
|
+
"strings"
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
8
8
|
)
|
|
9
9
|
|
|
10
10
|
type functionalParameters struct{}
|
|
@@ -44,778 +44,778 @@ func (functionalNoThrowStatements) Name() string { return "functional/no-t
|
|
|
44
44
|
func (functionalNoTryStatements) Name() string { return "functional/no-try-statements" }
|
|
45
45
|
func (functionalPreferImmutableTypes) Name() string { return "functional/prefer-immutable-types" }
|
|
46
46
|
func (functionalPreferPropertySignatures) Name() string {
|
|
47
|
-
|
|
47
|
+
return "functional/prefer-property-signatures"
|
|
48
48
|
}
|
|
49
49
|
func (functionalPreferReadonlyType) Name() string { return "functional/prefer-readonly-type" }
|
|
50
50
|
func (functionalPreferTacit) Name() string { return "functional/prefer-tacit" }
|
|
51
51
|
func (functionalReadonlyType) Name() string { return "functional/readonly-type" }
|
|
52
52
|
func (functionalTypeDeclarationImmutability) Name() string {
|
|
53
|
-
|
|
53
|
+
return "functional/type-declaration-immutability"
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
func (functionalParameters) Visits() []shimast.Kind {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
57
|
+
return []shimast.Kind{
|
|
58
|
+
shimast.KindParameter,
|
|
59
|
+
shimast.KindIdentifier,
|
|
60
|
+
shimast.KindFunctionDeclaration,
|
|
61
|
+
shimast.KindFunctionExpression,
|
|
62
|
+
shimast.KindArrowFunction,
|
|
63
|
+
shimast.KindMethodDeclaration,
|
|
64
|
+
}
|
|
65
65
|
}
|
|
66
66
|
func (functionalImmutableData) Visits() []shimast.Kind {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
67
|
+
return []shimast.Kind{
|
|
68
|
+
shimast.KindBinaryExpression,
|
|
69
|
+
shimast.KindPrefixUnaryExpression,
|
|
70
|
+
shimast.KindPostfixUnaryExpression,
|
|
71
|
+
shimast.KindDeleteExpression,
|
|
72
|
+
shimast.KindCallExpression,
|
|
73
|
+
}
|
|
74
74
|
}
|
|
75
75
|
func (functionalNoClassInheritance) Visits() []shimast.Kind {
|
|
76
|
-
|
|
76
|
+
return []shimast.Kind{shimast.KindClassDeclaration, shimast.KindClassExpression}
|
|
77
77
|
}
|
|
78
78
|
func (functionalNoClasses) Visits() []shimast.Kind {
|
|
79
|
-
|
|
79
|
+
return []shimast.Kind{shimast.KindClassDeclaration, shimast.KindClassExpression}
|
|
80
80
|
}
|
|
81
81
|
func (functionalNoConditionalStatements) Visits() []shimast.Kind {
|
|
82
|
-
|
|
82
|
+
return []shimast.Kind{shimast.KindIfStatement, shimast.KindSwitchStatement}
|
|
83
83
|
}
|
|
84
84
|
func (functionalNoExpressionStatements) Visits() []shimast.Kind {
|
|
85
|
-
|
|
85
|
+
return []shimast.Kind{shimast.KindExpressionStatement}
|
|
86
86
|
}
|
|
87
87
|
func (functionalNoLet) Visits() []shimast.Kind {
|
|
88
|
-
|
|
88
|
+
return []shimast.Kind{shimast.KindVariableDeclarationList}
|
|
89
89
|
}
|
|
90
90
|
func (functionalNoLoopStatements) Visits() []shimast.Kind {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
91
|
+
return []shimast.Kind{
|
|
92
|
+
shimast.KindForStatement,
|
|
93
|
+
shimast.KindForInStatement,
|
|
94
|
+
shimast.KindForOfStatement,
|
|
95
|
+
shimast.KindWhileStatement,
|
|
96
|
+
shimast.KindDoStatement,
|
|
97
|
+
}
|
|
98
98
|
}
|
|
99
99
|
func (functionalNoMixedTypes) Visits() []shimast.Kind {
|
|
100
|
-
|
|
100
|
+
return []shimast.Kind{shimast.KindInterfaceDeclaration, shimast.KindTypeLiteral}
|
|
101
101
|
}
|
|
102
102
|
func (functionalNoPromiseReject) Visits() []shimast.Kind {
|
|
103
|
-
|
|
103
|
+
return []shimast.Kind{shimast.KindCallExpression}
|
|
104
104
|
}
|
|
105
105
|
func (functionalNoReturnVoid) Visits() []shimast.Kind {
|
|
106
|
-
|
|
106
|
+
return []shimast.Kind{shimast.KindReturnStatement, shimast.KindFunctionDeclaration, shimast.KindFunctionExpression, shimast.KindArrowFunction, shimast.KindMethodDeclaration}
|
|
107
107
|
}
|
|
108
108
|
func (functionalNoThisExpressions) Visits() []shimast.Kind {
|
|
109
|
-
|
|
109
|
+
return []shimast.Kind{shimast.KindThisKeyword}
|
|
110
110
|
}
|
|
111
111
|
func (functionalNoThrowStatements) Visits() []shimast.Kind {
|
|
112
|
-
|
|
112
|
+
return []shimast.Kind{shimast.KindThrowStatement}
|
|
113
113
|
}
|
|
114
114
|
func (functionalNoTryStatements) Visits() []shimast.Kind {
|
|
115
|
-
|
|
115
|
+
return []shimast.Kind{shimast.KindTryStatement}
|
|
116
116
|
}
|
|
117
117
|
func (functionalPreferImmutableTypes) Visits() []shimast.Kind {
|
|
118
|
-
|
|
118
|
+
return []shimast.Kind{shimast.KindVariableDeclaration, shimast.KindParameter, shimast.KindPropertyDeclaration, shimast.KindPropertySignature}
|
|
119
119
|
}
|
|
120
120
|
func (functionalPreferPropertySignatures) Visits() []shimast.Kind {
|
|
121
|
-
|
|
121
|
+
return []shimast.Kind{shimast.KindMethodSignature}
|
|
122
122
|
}
|
|
123
123
|
func (functionalPreferReadonlyType) Visits() []shimast.Kind {
|
|
124
|
-
|
|
124
|
+
return []shimast.Kind{shimast.KindArrayType, shimast.KindTupleType, shimast.KindTypeReference, shimast.KindPropertySignature}
|
|
125
125
|
}
|
|
126
126
|
func (functionalPreferTacit) Visits() []shimast.Kind {
|
|
127
|
-
|
|
127
|
+
return []shimast.Kind{shimast.KindArrowFunction}
|
|
128
128
|
}
|
|
129
129
|
func (functionalReadonlyType) Visits() []shimast.Kind {
|
|
130
|
-
|
|
130
|
+
return []shimast.Kind{shimast.KindTypeReference, shimast.KindTypeOperator}
|
|
131
131
|
}
|
|
132
132
|
func (functionalTypeDeclarationImmutability) Visits() []shimast.Kind {
|
|
133
|
-
|
|
133
|
+
return []shimast.Kind{shimast.KindInterfaceDeclaration, shimast.KindTypeAliasDeclaration}
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
type functionalNoLetOptions struct {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
137
|
+
functionalPatternOptions
|
|
138
|
+
AllowInForLoopInit bool `json:"allowInForLoopInit"`
|
|
139
|
+
AllowInFunctions bool `json:"allowInFunctions"`
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
type functionalNoTryOptions struct {
|
|
143
|
-
|
|
144
|
-
|
|
143
|
+
AllowCatch bool `json:"allowCatch"`
|
|
144
|
+
AllowFinally bool `json:"allowFinally"`
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
type functionalImmutableDataOptions struct {
|
|
148
|
-
|
|
149
|
-
|
|
148
|
+
functionalPatternOptions
|
|
149
|
+
IgnoreMapsAndSets bool `json:"ignoreMapsAndSets"`
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
type functionalParametersOptions struct {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
153
|
+
functionalPatternOptions
|
|
154
|
+
AllowRestParameter bool `json:"allowRestParameter"`
|
|
155
|
+
AllowArgumentsKeyword bool `json:"allowArgumentsKeyword"`
|
|
156
|
+
EnforceParameterCount interface{} `json:"enforceParameterCount"`
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
type functionalPreferImmutableTypesOptions struct {
|
|
160
|
-
|
|
160
|
+
functionalPatternOptions
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
type functionalPreferReadonlyTypeOptions struct {
|
|
164
|
-
|
|
164
|
+
functionalPatternOptions
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
type functionalReadonlyTypeOptions struct {
|
|
168
|
-
|
|
168
|
+
Prefer string `json:"prefer"`
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
type functionalPatternOptions struct {
|
|
172
|
-
|
|
173
|
-
|
|
172
|
+
IgnoreIdentifierPattern interface{} `json:"ignoreIdentifierPattern"`
|
|
173
|
+
IgnoreCodePattern interface{} `json:"ignoreCodePattern"`
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
type functionalImmutabilityDeclarationOptions struct {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
177
|
+
functionalPatternOptions
|
|
178
|
+
Rules []functionalImmutabilityRule `json:"rules"`
|
|
179
|
+
IgnoreInterfaces bool `json:"ignoreInterfaces"`
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
type functionalImmutabilityRule struct {
|
|
183
|
-
|
|
183
|
+
Identifiers interface{} `json:"identifiers"`
|
|
184
184
|
}
|
|
185
185
|
|
|
186
186
|
func (functionalParameters) Check(ctx *Context, node *shimast.Node) {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
187
|
+
var opts functionalParametersOptions
|
|
188
|
+
_ = ctx.DecodeOptions(&opts)
|
|
189
|
+
switch node.Kind {
|
|
190
|
+
case shimast.KindParameter:
|
|
191
|
+
param := node.AsParameterDeclaration()
|
|
192
|
+
if param != nil && param.DotDotDotToken != nil && !opts.AllowRestParameter {
|
|
193
|
+
if functionalShouldIgnore(ctx, opts.functionalPatternOptions, node, identifierText(param.Name())) {
|
|
194
|
+
return
|
|
195
|
+
}
|
|
196
|
+
ctx.Report(node, "Unexpected rest parameter. Use a regular parameter of array type instead.")
|
|
197
|
+
}
|
|
198
|
+
case shimast.KindIdentifier:
|
|
199
|
+
if opts.AllowArgumentsKeyword || identifierText(node) != "arguments" || isDeclarationName(node) {
|
|
200
|
+
return
|
|
201
|
+
}
|
|
202
|
+
if functionalShouldIgnore(ctx, opts.functionalPatternOptions, node, "arguments") {
|
|
203
|
+
return
|
|
204
|
+
}
|
|
205
|
+
ctx.Report(node, "Unexpected use of `arguments`. Use regular function arguments instead.")
|
|
206
|
+
default:
|
|
207
|
+
if opts.EnforceParameterCount == nil || opts.EnforceParameterCount == false {
|
|
208
|
+
return
|
|
209
|
+
}
|
|
210
|
+
if len(node.Parameters()) == 0 {
|
|
211
|
+
if functionalShouldIgnore(ctx, opts.functionalPatternOptions, node, functionalFunctionLikeName(node)) {
|
|
212
|
+
return
|
|
213
|
+
}
|
|
214
|
+
ctx.Report(node, "Functions must have at least one parameter.")
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
217
|
}
|
|
218
218
|
|
|
219
219
|
func (functionalImmutableData) Check(ctx *Context, node *shimast.Node) {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
220
|
+
var opts functionalImmutableDataOptions
|
|
221
|
+
_ = ctx.DecodeOptions(&opts)
|
|
222
|
+
switch node.Kind {
|
|
223
|
+
case shimast.KindBinaryExpression:
|
|
224
|
+
expr := node.AsBinaryExpression()
|
|
225
|
+
if expr == nil || expr.OperatorToken == nil || !isAssignmentOperator(expr.OperatorToken.Kind) {
|
|
226
|
+
return
|
|
227
|
+
}
|
|
228
|
+
if isMemberMutationTarget(expr.Left) {
|
|
229
|
+
if functionalShouldIgnore(ctx, opts.functionalPatternOptions, expr.Left, functionalIdentifierTexts(expr.Left)...) {
|
|
230
|
+
return
|
|
231
|
+
}
|
|
232
|
+
ctx.Report(expr.Left, "Modifying an existing object/array is not allowed.")
|
|
233
|
+
}
|
|
234
|
+
case shimast.KindPrefixUnaryExpression:
|
|
235
|
+
expr := node.AsPrefixUnaryExpression()
|
|
236
|
+
if expr != nil && isUpdateOperator(expr.Operator) && isMemberMutationTarget(expr.Operand) {
|
|
237
|
+
if functionalShouldIgnore(ctx, opts.functionalPatternOptions, expr.Operand, functionalIdentifierTexts(expr.Operand)...) {
|
|
238
|
+
return
|
|
239
|
+
}
|
|
240
|
+
ctx.Report(expr.Operand, "Modifying an existing object/array is not allowed.")
|
|
241
|
+
}
|
|
242
|
+
case shimast.KindPostfixUnaryExpression:
|
|
243
|
+
expr := node.AsPostfixUnaryExpression()
|
|
244
|
+
if expr != nil && isUpdateOperator(expr.Operator) && isMemberMutationTarget(expr.Operand) {
|
|
245
|
+
if functionalShouldIgnore(ctx, opts.functionalPatternOptions, expr.Operand, functionalIdentifierTexts(expr.Operand)...) {
|
|
246
|
+
return
|
|
247
|
+
}
|
|
248
|
+
ctx.Report(expr.Operand, "Modifying an existing object/array is not allowed.")
|
|
249
|
+
}
|
|
250
|
+
case shimast.KindDeleteExpression:
|
|
251
|
+
expr := node.AsDeleteExpression()
|
|
252
|
+
if expr != nil && isMemberMutationTarget(expr.Expression) {
|
|
253
|
+
if functionalShouldIgnore(ctx, opts.functionalPatternOptions, expr.Expression, functionalIdentifierTexts(expr.Expression)...) {
|
|
254
|
+
return
|
|
255
|
+
}
|
|
256
|
+
ctx.Report(expr.Expression, "Modifying an existing object/array is not allowed.")
|
|
257
|
+
}
|
|
258
|
+
case shimast.KindCallExpression:
|
|
259
|
+
call := node.AsCallExpression()
|
|
260
|
+
if call == nil || call.Expression == nil || call.Expression.Kind != shimast.KindPropertyAccessExpression {
|
|
261
|
+
return
|
|
262
|
+
}
|
|
263
|
+
access := call.Expression.AsPropertyAccessExpression()
|
|
264
|
+
if access == nil {
|
|
265
|
+
return
|
|
266
|
+
}
|
|
267
|
+
method := identifierText(access.Name())
|
|
268
|
+
if isMutableArrayMethod(method) || (!opts.IgnoreMapsAndSets && isMutableCollectionMethod(method)) {
|
|
269
|
+
if functionalShouldIgnore(ctx, opts.functionalPatternOptions, call.Expression, functionalIdentifierTexts(call.Expression)...) {
|
|
270
|
+
return
|
|
271
|
+
}
|
|
272
|
+
ctx.Report(call.Expression, "Modifying an existing object/array is not allowed.")
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
275
|
}
|
|
276
276
|
|
|
277
277
|
func (functionalNoClassInheritance) Check(ctx *Context, node *shimast.Node) {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
278
|
+
if hasModifier(node, shimast.KindAbstractKeyword) {
|
|
279
|
+
ctx.Report(node, "Unexpected abstract class.")
|
|
280
|
+
return
|
|
281
|
+
}
|
|
282
|
+
if classHasHeritage(node) {
|
|
283
|
+
ctx.Report(node, "Unexpected inheritance, use composition instead.")
|
|
284
|
+
}
|
|
285
285
|
}
|
|
286
286
|
|
|
287
287
|
func (functionalNoClasses) Check(ctx *Context, node *shimast.Node) {
|
|
288
|
-
|
|
288
|
+
ctx.Report(node, "Unexpected class, use functions not classes.")
|
|
289
289
|
}
|
|
290
290
|
|
|
291
291
|
func (functionalNoConditionalStatements) Check(ctx *Context, node *shimast.Node) {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
292
|
+
switch node.Kind {
|
|
293
|
+
case shimast.KindIfStatement:
|
|
294
|
+
ctx.Report(node, "Unexpected if, use a conditional expression instead.")
|
|
295
|
+
case shimast.KindSwitchStatement:
|
|
296
|
+
ctx.Report(node, "Unexpected switch, use a conditional expression instead.")
|
|
297
|
+
}
|
|
298
298
|
}
|
|
299
299
|
|
|
300
300
|
func (functionalNoExpressionStatements) Check(ctx *Context, node *shimast.Node) {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
301
|
+
text := strings.TrimSpace(nodeText(ctx.File, node))
|
|
302
|
+
if strings.HasPrefix(text, `"use `) || strings.HasPrefix(text, `'use `) {
|
|
303
|
+
return
|
|
304
|
+
}
|
|
305
|
+
ctx.Report(node, "Using expressions to cause side effects is not allowed.")
|
|
306
306
|
}
|
|
307
307
|
|
|
308
308
|
func (functionalNoLet) Check(ctx *Context, node *shimast.Node) {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
309
|
+
if !shimast.IsLet(node) {
|
|
310
|
+
return
|
|
311
|
+
}
|
|
312
|
+
var opts functionalNoLetOptions
|
|
313
|
+
_ = ctx.DecodeOptions(&opts)
|
|
314
|
+
if opts.AllowInForLoopInit && node.Parent != nil && node.Parent.Kind == shimast.KindForStatement {
|
|
315
|
+
return
|
|
316
|
+
}
|
|
317
|
+
if opts.AllowInFunctions && hasAncestor(node, isFunctionLikeKind) {
|
|
318
|
+
return
|
|
319
|
+
}
|
|
320
|
+
if functionalShouldIgnore(ctx, opts.functionalPatternOptions, node, functionalVariableDeclarationListNames(node)...) {
|
|
321
|
+
return
|
|
322
|
+
}
|
|
323
|
+
start := keywordStart(ctx.File, node, "let")
|
|
324
|
+
if start >= 0 {
|
|
325
|
+
ctx.ReportRange(start, start+len("let"), "Unexpected let, use const instead.")
|
|
326
|
+
return
|
|
327
|
+
}
|
|
328
|
+
ctx.Report(node, "Unexpected let, use const instead.")
|
|
329
329
|
}
|
|
330
330
|
|
|
331
331
|
func (functionalNoLoopStatements) Check(ctx *Context, node *shimast.Node) {
|
|
332
|
-
|
|
332
|
+
ctx.Report(node, "Unexpected loop, use map or reduce instead.")
|
|
333
333
|
}
|
|
334
334
|
|
|
335
335
|
func (functionalNoMixedTypes) Check(ctx *Context, node *shimast.Node) {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
336
|
+
members := containerMembers(node)
|
|
337
|
+
if len(members) < 2 {
|
|
338
|
+
return
|
|
339
|
+
}
|
|
340
|
+
first := ""
|
|
341
|
+
for _, member := range members {
|
|
342
|
+
kind := functionalMemberKind(member)
|
|
343
|
+
if kind == "" {
|
|
344
|
+
continue
|
|
345
|
+
}
|
|
346
|
+
if first == "" {
|
|
347
|
+
first = kind
|
|
348
|
+
continue
|
|
349
|
+
}
|
|
350
|
+
if first != kind {
|
|
351
|
+
ctx.Report(member, "Only the same kind of members are allowed in types.")
|
|
352
|
+
return
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
355
|
}
|
|
356
356
|
|
|
357
357
|
func (functionalNoPromiseReject) Check(ctx *Context, node *shimast.Node) {
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
358
|
+
call := node.AsCallExpression()
|
|
359
|
+
if call != nil && isMatchingPropertyAccess(call.Expression, "Promise", "reject") {
|
|
360
|
+
ctx.Report(node, "Unexpected rejection, resolve an error instead.")
|
|
361
|
+
}
|
|
362
362
|
}
|
|
363
363
|
|
|
364
364
|
func (functionalNoReturnVoid) Check(ctx *Context, node *shimast.Node) {
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
365
|
+
if node.Kind == shimast.KindReturnStatement {
|
|
366
|
+
ret := node.AsReturnStatement()
|
|
367
|
+
if ret != nil && ret.Expression == nil {
|
|
368
|
+
ctx.Report(node, "Function must return a value.")
|
|
369
|
+
}
|
|
370
|
+
return
|
|
371
|
+
}
|
|
372
|
+
if functionalReturnTypeText(ctx, node) == "void" {
|
|
373
|
+
ctx.Report(node, "Function must return a value.")
|
|
374
|
+
}
|
|
375
375
|
}
|
|
376
376
|
|
|
377
377
|
func (functionalNoThisExpressions) Check(ctx *Context, node *shimast.Node) {
|
|
378
|
-
|
|
378
|
+
ctx.Report(node, "Unexpected this, use functions not classes.")
|
|
379
379
|
}
|
|
380
380
|
|
|
381
381
|
func (functionalNoThrowStatements) Check(ctx *Context, node *shimast.Node) {
|
|
382
|
-
|
|
382
|
+
ctx.Report(node, "Unexpected throw, throwing exceptions is not functional.")
|
|
383
383
|
}
|
|
384
384
|
|
|
385
385
|
func (functionalNoTryStatements) Check(ctx *Context, node *shimast.Node) {
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
386
|
+
var opts functionalNoTryOptions
|
|
387
|
+
_ = ctx.DecodeOptions(&opts)
|
|
388
|
+
try := node.AsTryStatement()
|
|
389
|
+
if try == nil {
|
|
390
|
+
return
|
|
391
|
+
}
|
|
392
|
+
if try.CatchClause != nil && !opts.AllowCatch {
|
|
393
|
+
ctx.Report(node, "Unexpected try-catch, this pattern is not functional.")
|
|
394
|
+
return
|
|
395
|
+
}
|
|
396
|
+
if try.FinallyBlock != nil && !opts.AllowFinally {
|
|
397
|
+
ctx.Report(node, "Unexpected try-finally, this pattern is not functional.")
|
|
398
|
+
}
|
|
399
399
|
}
|
|
400
400
|
|
|
401
401
|
func (functionalPreferImmutableTypes) Check(ctx *Context, node *shimast.Node) {
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
402
|
+
var opts functionalPreferImmutableTypesOptions
|
|
403
|
+
_ = ctx.DecodeOptions(&opts)
|
|
404
|
+
typeNode := declarationTypeNode(node)
|
|
405
|
+
if typeNode == nil || !functionalMutableType(typeNode) {
|
|
406
|
+
return
|
|
407
|
+
}
|
|
408
|
+
if functionalShouldIgnore(ctx, opts.functionalPatternOptions, node, functionalDeclarationName(node)) ||
|
|
409
|
+
functionalShouldIgnore(ctx, opts.functionalPatternOptions, typeNode) {
|
|
410
|
+
return
|
|
411
|
+
}
|
|
412
|
+
ctx.Report(typeNode, "Type should be readonly or immutable.")
|
|
413
413
|
}
|
|
414
414
|
|
|
415
415
|
func (functionalPreferPropertySignatures) Check(ctx *Context, node *shimast.Node) {
|
|
416
|
-
|
|
416
|
+
ctx.Report(node, "Use a property signature instead of a method signature.")
|
|
417
417
|
}
|
|
418
418
|
|
|
419
419
|
func (functionalPreferReadonlyType) Check(ctx *Context, node *shimast.Node) {
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
420
|
+
var opts functionalPreferReadonlyTypeOptions
|
|
421
|
+
_ = ctx.DecodeOptions(&opts)
|
|
422
|
+
switch node.Kind {
|
|
423
|
+
case shimast.KindArrayType:
|
|
424
|
+
if !isReadonlyTypeNode(node) {
|
|
425
|
+
if functionalShouldIgnore(ctx, opts.functionalPatternOptions, node) {
|
|
426
|
+
return
|
|
427
|
+
}
|
|
428
|
+
ctx.Report(node, "Only readonly arrays allowed.")
|
|
429
|
+
}
|
|
430
|
+
case shimast.KindTupleType:
|
|
431
|
+
if !isReadonlyTypeNode(node) {
|
|
432
|
+
if functionalShouldIgnore(ctx, opts.functionalPatternOptions, node) {
|
|
433
|
+
return
|
|
434
|
+
}
|
|
435
|
+
ctx.Report(node, "Only readonly tuples allowed.")
|
|
436
|
+
}
|
|
437
|
+
case shimast.KindTypeReference:
|
|
438
|
+
if isMutableTypeReference(node) {
|
|
439
|
+
if functionalShouldIgnore(ctx, opts.functionalPatternOptions, node, functionalIdentifierTexts(node)...) {
|
|
440
|
+
return
|
|
441
|
+
}
|
|
442
|
+
ctx.Report(node, "Only readonly types allowed.")
|
|
443
|
+
}
|
|
444
|
+
case shimast.KindPropertySignature:
|
|
445
|
+
if !hasModifier(node, shimast.KindReadonlyKeyword) {
|
|
446
|
+
if functionalShouldIgnore(ctx, opts.functionalPatternOptions, node, functionalDeclarationName(node)) {
|
|
447
|
+
return
|
|
448
|
+
}
|
|
449
|
+
ctx.Report(node, "A readonly modifier is required.")
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
452
|
}
|
|
453
453
|
|
|
454
454
|
func (functionalPreferTacit) Check(ctx *Context, node *shimast.Node) {
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
455
|
+
text := compactFunctionalWhitespace(nodeText(ctx.File, node))
|
|
456
|
+
if isTacitWrapperText(text) {
|
|
457
|
+
ctx.Report(node, "Potentially unnecessary function wrapper.")
|
|
458
|
+
}
|
|
459
459
|
}
|
|
460
460
|
|
|
461
461
|
func (functionalReadonlyType) Check(ctx *Context, node *shimast.Node) {
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
462
|
+
var opts functionalReadonlyTypeOptions
|
|
463
|
+
_ = ctx.DecodeOptions(&opts)
|
|
464
|
+
prefer := opts.Prefer
|
|
465
|
+
if prefer == "" {
|
|
466
|
+
prefer = "keyword"
|
|
467
|
+
}
|
|
468
|
+
switch node.Kind {
|
|
469
|
+
case shimast.KindTypeReference:
|
|
470
|
+
if prefer == "keyword" && identifierText(node.AsTypeReferenceNode().TypeName) == "ReadonlyArray" {
|
|
471
|
+
ctx.Report(node, "Use the readonly keyword instead of ReadonlyArray<T>.")
|
|
472
|
+
}
|
|
473
|
+
case shimast.KindTypeOperator:
|
|
474
|
+
if prefer == "generic" && strings.HasPrefix(strings.TrimSpace(nodeText(ctx.File, node)), "readonly ") {
|
|
475
|
+
ctx.Report(node, "Use Readonly<T> instead of the readonly keyword.")
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
478
|
}
|
|
479
479
|
|
|
480
480
|
func (functionalTypeDeclarationImmutability) Check(ctx *Context, node *shimast.Node) {
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
481
|
+
var opts functionalImmutabilityDeclarationOptions
|
|
482
|
+
_ = ctx.DecodeOptions(&opts)
|
|
483
|
+
if opts.IgnoreInterfaces && node.Kind == shimast.KindInterfaceDeclaration {
|
|
484
|
+
return
|
|
485
|
+
}
|
|
486
|
+
name := functionalTypeDeclarationName(node)
|
|
487
|
+
if functionalShouldIgnore(ctx, opts.functionalPatternOptions, node, name) {
|
|
488
|
+
return
|
|
489
|
+
}
|
|
490
|
+
if !functionalDeclarationRuleApplies(opts, name) {
|
|
491
|
+
return
|
|
492
|
+
}
|
|
493
|
+
if functionalDeclarationIsMutable(node) {
|
|
494
|
+
ctx.Report(node, "Type declaration should only expose readonly members and immutable property types.")
|
|
495
|
+
}
|
|
496
496
|
}
|
|
497
497
|
|
|
498
498
|
func isMemberMutationTarget(node *shimast.Node) bool {
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
499
|
+
if node == nil {
|
|
500
|
+
return false
|
|
501
|
+
}
|
|
502
|
+
node = stripParens(node)
|
|
503
|
+
return node != nil && (node.Kind == shimast.KindPropertyAccessExpression || node.Kind == shimast.KindElementAccessExpression)
|
|
504
504
|
}
|
|
505
505
|
|
|
506
506
|
func functionalShouldIgnore(ctx *Context, opts functionalPatternOptions, node *shimast.Node, identifiers ...string) bool {
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
507
|
+
if functionalPatternOptionMatches(opts.IgnoreCodePattern, strings.TrimSpace(nodeText(ctx.File, node))) {
|
|
508
|
+
return true
|
|
509
|
+
}
|
|
510
|
+
for _, name := range identifiers {
|
|
511
|
+
if functionalPatternOptionMatches(opts.IgnoreIdentifierPattern, name) {
|
|
512
|
+
return true
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
return false
|
|
516
516
|
}
|
|
517
517
|
|
|
518
518
|
func isUpdateOperator(kind shimast.Kind) bool {
|
|
519
|
-
|
|
519
|
+
return kind == shimast.KindPlusPlusToken || kind == shimast.KindMinusMinusToken
|
|
520
520
|
}
|
|
521
521
|
|
|
522
522
|
func isMutableArrayMethod(name string) bool {
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
523
|
+
switch name {
|
|
524
|
+
case "copyWithin", "fill", "pop", "push", "reverse", "shift", "sort", "splice", "unshift":
|
|
525
|
+
return true
|
|
526
|
+
default:
|
|
527
|
+
return false
|
|
528
|
+
}
|
|
529
529
|
}
|
|
530
530
|
|
|
531
531
|
func isMutableCollectionMethod(name string) bool {
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
532
|
+
switch name {
|
|
533
|
+
case "add", "clear", "delete", "set":
|
|
534
|
+
return true
|
|
535
|
+
default:
|
|
536
|
+
return false
|
|
537
|
+
}
|
|
538
538
|
}
|
|
539
539
|
|
|
540
540
|
func classHasHeritage(node *shimast.Node) bool {
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
541
|
+
switch node.Kind {
|
|
542
|
+
case shimast.KindClassDeclaration:
|
|
543
|
+
decl := node.AsClassDeclaration()
|
|
544
|
+
return decl != nil && decl.HeritageClauses != nil && len(decl.HeritageClauses.Nodes) > 0
|
|
545
|
+
case shimast.KindClassExpression:
|
|
546
|
+
decl := node.AsClassExpression()
|
|
547
|
+
return decl != nil && decl.HeritageClauses != nil && len(decl.HeritageClauses.Nodes) > 0
|
|
548
|
+
default:
|
|
549
|
+
return false
|
|
550
|
+
}
|
|
551
551
|
}
|
|
552
552
|
|
|
553
553
|
func hasAncestor(node *shimast.Node, pred func(*shimast.Node) bool) bool {
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
554
|
+
for cur := node.Parent; cur != nil; cur = cur.Parent {
|
|
555
|
+
if pred(cur) {
|
|
556
|
+
return true
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
return false
|
|
560
560
|
}
|
|
561
561
|
|
|
562
562
|
func functionalMemberKind(node *shimast.Node) string {
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
563
|
+
if node == nil {
|
|
564
|
+
return ""
|
|
565
|
+
}
|
|
566
|
+
switch node.Kind {
|
|
567
|
+
case shimast.KindPropertySignature, shimast.KindPropertyDeclaration:
|
|
568
|
+
return "property"
|
|
569
|
+
case shimast.KindMethodSignature, shimast.KindMethodDeclaration:
|
|
570
|
+
return "method"
|
|
571
|
+
case shimast.KindCallSignature:
|
|
572
|
+
return "call"
|
|
573
|
+
case shimast.KindIndexSignature:
|
|
574
|
+
return "index"
|
|
575
|
+
default:
|
|
576
|
+
return ""
|
|
577
|
+
}
|
|
578
578
|
}
|
|
579
579
|
|
|
580
580
|
func isDeclarationName(node *shimast.Node) bool {
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
581
|
+
if node == nil || node.Parent == nil {
|
|
582
|
+
return false
|
|
583
|
+
}
|
|
584
|
+
parent := node.Parent
|
|
585
|
+
switch parent.Kind {
|
|
586
|
+
case shimast.KindVariableDeclaration:
|
|
587
|
+
decl := parent.AsVariableDeclaration()
|
|
588
|
+
return decl != nil && decl.Name() == node
|
|
589
|
+
case shimast.KindParameter:
|
|
590
|
+
decl := parent.AsParameterDeclaration()
|
|
591
|
+
return decl != nil && decl.Name() == node
|
|
592
|
+
case shimast.KindFunctionDeclaration, shimast.KindClassDeclaration, shimast.KindInterfaceDeclaration, shimast.KindTypeAliasDeclaration:
|
|
593
|
+
return true
|
|
594
|
+
default:
|
|
595
|
+
return false
|
|
596
|
+
}
|
|
597
597
|
}
|
|
598
598
|
|
|
599
599
|
func functionalReturnTypeText(ctx *Context, node *shimast.Node) string {
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
600
|
+
var typeNode *shimast.Node
|
|
601
|
+
switch node.Kind {
|
|
602
|
+
case shimast.KindFunctionDeclaration:
|
|
603
|
+
if decl := node.AsFunctionDeclaration(); decl != nil {
|
|
604
|
+
typeNode = decl.Type
|
|
605
|
+
}
|
|
606
|
+
case shimast.KindFunctionExpression:
|
|
607
|
+
if decl := node.AsFunctionExpression(); decl != nil {
|
|
608
|
+
typeNode = decl.Type
|
|
609
|
+
}
|
|
610
|
+
case shimast.KindArrowFunction:
|
|
611
|
+
if decl := node.AsArrowFunction(); decl != nil {
|
|
612
|
+
typeNode = decl.Type
|
|
613
|
+
}
|
|
614
|
+
case shimast.KindMethodDeclaration:
|
|
615
|
+
if decl := node.AsMethodDeclaration(); decl != nil {
|
|
616
|
+
typeNode = decl.Type
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
return strings.TrimSpace(nodeText(ctx.File, typeNode))
|
|
620
620
|
}
|
|
621
621
|
|
|
622
622
|
func functionalFunctionLikeName(node *shimast.Node) string {
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
623
|
+
if node == nil {
|
|
624
|
+
return ""
|
|
625
|
+
}
|
|
626
|
+
switch node.Kind {
|
|
627
|
+
case shimast.KindFunctionDeclaration:
|
|
628
|
+
if decl := node.AsFunctionDeclaration(); decl != nil {
|
|
629
|
+
return identifierText(decl.Name())
|
|
630
|
+
}
|
|
631
|
+
case shimast.KindMethodDeclaration:
|
|
632
|
+
if decl := node.AsMethodDeclaration(); decl != nil {
|
|
633
|
+
return identifierText(decl.Name())
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
return ""
|
|
637
637
|
}
|
|
638
638
|
|
|
639
639
|
func declarationTypeNode(node *shimast.Node) *shimast.Node {
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
640
|
+
if node == nil {
|
|
641
|
+
return nil
|
|
642
|
+
}
|
|
643
|
+
switch node.Kind {
|
|
644
|
+
case shimast.KindVariableDeclaration:
|
|
645
|
+
if decl := node.AsVariableDeclaration(); decl != nil {
|
|
646
|
+
return decl.Type
|
|
647
|
+
}
|
|
648
|
+
case shimast.KindParameter:
|
|
649
|
+
if decl := node.AsParameterDeclaration(); decl != nil {
|
|
650
|
+
return decl.Type
|
|
651
|
+
}
|
|
652
|
+
case shimast.KindPropertyDeclaration:
|
|
653
|
+
if decl := node.AsPropertyDeclaration(); decl != nil {
|
|
654
|
+
return decl.Type
|
|
655
|
+
}
|
|
656
|
+
case shimast.KindPropertySignature:
|
|
657
|
+
if decl := node.AsPropertySignatureDeclaration(); decl != nil {
|
|
658
|
+
return decl.Type
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
return nil
|
|
662
662
|
}
|
|
663
663
|
|
|
664
664
|
func functionalDeclarationName(node *shimast.Node) string {
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
665
|
+
if node == nil {
|
|
666
|
+
return ""
|
|
667
|
+
}
|
|
668
|
+
switch node.Kind {
|
|
669
|
+
case shimast.KindVariableDeclaration:
|
|
670
|
+
if decl := node.AsVariableDeclaration(); decl != nil {
|
|
671
|
+
return identifierText(decl.Name())
|
|
672
|
+
}
|
|
673
|
+
case shimast.KindParameter:
|
|
674
|
+
if decl := node.AsParameterDeclaration(); decl != nil {
|
|
675
|
+
return identifierText(decl.Name())
|
|
676
|
+
}
|
|
677
|
+
case shimast.KindPropertyDeclaration:
|
|
678
|
+
if decl := node.AsPropertyDeclaration(); decl != nil {
|
|
679
|
+
return identifierText(decl.Name())
|
|
680
|
+
}
|
|
681
|
+
case shimast.KindPropertySignature:
|
|
682
|
+
if decl := node.AsPropertySignatureDeclaration(); decl != nil {
|
|
683
|
+
return identifierText(decl.Name())
|
|
684
|
+
}
|
|
685
|
+
case shimast.KindFunctionDeclaration:
|
|
686
|
+
if decl := node.AsFunctionDeclaration(); decl != nil {
|
|
687
|
+
return identifierText(decl.Name())
|
|
688
|
+
}
|
|
689
|
+
case shimast.KindMethodDeclaration:
|
|
690
|
+
if decl := node.AsMethodDeclaration(); decl != nil {
|
|
691
|
+
return identifierText(decl.Name())
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
return ""
|
|
695
695
|
}
|
|
696
696
|
|
|
697
697
|
func functionalVariableDeclarationListNames(node *shimast.Node) []string {
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
698
|
+
list := node.AsVariableDeclarationList()
|
|
699
|
+
if list == nil || list.Declarations == nil {
|
|
700
|
+
return nil
|
|
701
|
+
}
|
|
702
|
+
names := make([]string, 0, len(list.Declarations.Nodes))
|
|
703
|
+
for _, child := range list.Declarations.Nodes {
|
|
704
|
+
if name := functionalDeclarationName(child); name != "" {
|
|
705
|
+
names = append(names, name)
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
return names
|
|
709
709
|
}
|
|
710
710
|
|
|
711
711
|
func functionalIdentifierTexts(node *shimast.Node) []string {
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
712
|
+
var names []string
|
|
713
|
+
walkDescendants(node, func(child *shimast.Node) {
|
|
714
|
+
if name := identifierText(child); name != "" {
|
|
715
|
+
names = append(names, name)
|
|
716
|
+
}
|
|
717
|
+
})
|
|
718
|
+
return names
|
|
719
719
|
}
|
|
720
720
|
|
|
721
721
|
func functionalMutableType(node *shimast.Node) bool {
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
722
|
+
if node == nil || isReadonlyTypeNode(node) {
|
|
723
|
+
return false
|
|
724
|
+
}
|
|
725
|
+
switch node.Kind {
|
|
726
|
+
case shimast.KindArrayType, shimast.KindTupleType:
|
|
727
|
+
return true
|
|
728
|
+
case shimast.KindTypeReference:
|
|
729
|
+
return isMutableTypeReference(node)
|
|
730
|
+
case shimast.KindTypeLiteral:
|
|
731
|
+
return functionalTypeLiteralIsMutable(node)
|
|
732
|
+
default:
|
|
733
|
+
found := false
|
|
734
|
+
walkDescendants(node, func(child *shimast.Node) {
|
|
735
|
+
if child != node && functionalMutableType(child) {
|
|
736
|
+
found = true
|
|
737
|
+
}
|
|
738
|
+
})
|
|
739
|
+
return found
|
|
740
|
+
}
|
|
741
741
|
}
|
|
742
742
|
|
|
743
743
|
func isReadonlyTypeNode(node *shimast.Node) bool {
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
744
|
+
if node == nil {
|
|
745
|
+
return false
|
|
746
|
+
}
|
|
747
|
+
return node.Kind == shimast.KindTypeOperator ||
|
|
748
|
+
(node.Parent != nil && node.Parent.Kind == shimast.KindTypeOperator &&
|
|
749
|
+
strings.HasPrefix(strings.TrimSpace(nodeText(nilSafeFile(node), node.Parent)), "readonly "))
|
|
750
750
|
}
|
|
751
751
|
|
|
752
752
|
func nilSafeFile(node *shimast.Node) *shimast.SourceFile {
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
753
|
+
for cur := node; cur != nil; cur = cur.Parent {
|
|
754
|
+
if cur.Kind == shimast.KindSourceFile {
|
|
755
|
+
return cur.AsSourceFile()
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
return nil
|
|
759
759
|
}
|
|
760
760
|
|
|
761
761
|
func isMutableTypeReference(node *shimast.Node) bool {
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
762
|
+
ref := node.AsTypeReferenceNode()
|
|
763
|
+
if ref == nil || ref.TypeName == nil {
|
|
764
|
+
return false
|
|
765
|
+
}
|
|
766
|
+
switch identifierText(ref.TypeName) {
|
|
767
|
+
case "Array", "Map", "Set", "WeakMap", "WeakSet":
|
|
768
|
+
return true
|
|
769
|
+
default:
|
|
770
|
+
return false
|
|
771
|
+
}
|
|
772
772
|
}
|
|
773
773
|
|
|
774
774
|
func functionalTypeLiteralIsMutable(node *shimast.Node) bool {
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
775
|
+
lit := node.AsTypeLiteralNode()
|
|
776
|
+
if lit == nil || lit.Members == nil {
|
|
777
|
+
return false
|
|
778
|
+
}
|
|
779
|
+
for _, member := range lit.Members.Nodes {
|
|
780
|
+
if member == nil {
|
|
781
|
+
continue
|
|
782
|
+
}
|
|
783
|
+
if member.Kind == shimast.KindPropertySignature && !hasModifier(member, shimast.KindReadonlyKeyword) {
|
|
784
|
+
return true
|
|
785
|
+
}
|
|
786
|
+
if functionalMutableType(declarationTypeNode(member)) {
|
|
787
|
+
return true
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
return false
|
|
791
791
|
}
|
|
792
792
|
|
|
793
793
|
func compactFunctionalWhitespace(text string) string {
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
794
|
+
text = strings.TrimSpace(text)
|
|
795
|
+
text = strings.Join(strings.Fields(text), "")
|
|
796
|
+
return strings.TrimSuffix(text, ";")
|
|
797
797
|
}
|
|
798
798
|
|
|
799
799
|
func isTacitWrapperText(text string) bool {
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
800
|
+
parts := strings.Split(text, "=>")
|
|
801
|
+
if len(parts) != 2 {
|
|
802
|
+
return false
|
|
803
|
+
}
|
|
804
|
+
param := tacitWrapperParameterName(strings.Trim(parts[0], "()"))
|
|
805
|
+
if param == "" {
|
|
806
|
+
return false
|
|
807
|
+
}
|
|
808
|
+
call := parts[1]
|
|
809
|
+
if !strings.HasSuffix(call, ")") {
|
|
810
|
+
return false
|
|
811
|
+
}
|
|
812
|
+
open := strings.LastIndex(call, "(")
|
|
813
|
+
if open <= 0 {
|
|
814
|
+
return false
|
|
815
|
+
}
|
|
816
|
+
callee := call[:open]
|
|
817
|
+
arg := strings.TrimSuffix(call[open+1:], ")")
|
|
818
|
+
return arg == param && isFunctionalMemberChain(callee)
|
|
819
819
|
}
|
|
820
820
|
|
|
821
821
|
// tacitWrapperParameterName returns the bare identifier of a single
|
|
@@ -825,143 +825,143 @@ func isTacitWrapperText(text string) bool {
|
|
|
825
825
|
// list is empty, contains a destructured pattern, or has more than one
|
|
826
826
|
// parameter (a multi-arg list is split by `=>` further upstream).
|
|
827
827
|
func tacitWrapperParameterName(param string) string {
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
828
|
+
if param == "" {
|
|
829
|
+
return ""
|
|
830
|
+
}
|
|
831
|
+
// Strip default value: `x = 0`. The default would re-evaluate
|
|
832
|
+
// inside the wrapper, so the tacit form would lose it — bail.
|
|
833
|
+
if strings.ContainsRune(param, '=') {
|
|
834
|
+
return ""
|
|
835
|
+
}
|
|
836
|
+
// Strip optional marker and type annotation.
|
|
837
|
+
if i := strings.IndexRune(param, ':'); i >= 0 {
|
|
838
|
+
param = param[:i]
|
|
839
|
+
}
|
|
840
|
+
param = strings.TrimSuffix(param, "?")
|
|
841
|
+
param = strings.TrimSpace(param)
|
|
842
|
+
if !isFunctionalIdentifier(param) {
|
|
843
|
+
return ""
|
|
844
|
+
}
|
|
845
|
+
return param
|
|
846
846
|
}
|
|
847
847
|
|
|
848
848
|
func isFunctionalMemberChain(text string) bool {
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
849
|
+
parts := strings.Split(text, ".")
|
|
850
|
+
for _, part := range parts {
|
|
851
|
+
if !isFunctionalIdentifier(part) {
|
|
852
|
+
return false
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
return true
|
|
856
856
|
}
|
|
857
857
|
|
|
858
858
|
func isFunctionalIdentifier(text string) bool {
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
859
|
+
if text == "" {
|
|
860
|
+
return false
|
|
861
|
+
}
|
|
862
|
+
for i, r := range text {
|
|
863
|
+
if i == 0 {
|
|
864
|
+
if r == '_' || r == '$' || ('A' <= r && r <= 'Z') || ('a' <= r && r <= 'z') {
|
|
865
|
+
continue
|
|
866
|
+
}
|
|
867
|
+
return false
|
|
868
|
+
}
|
|
869
|
+
if r == '_' || r == '$' || ('A' <= r && r <= 'Z') || ('a' <= r && r <= 'z') || ('0' <= r && r <= '9') {
|
|
870
|
+
continue
|
|
871
|
+
}
|
|
872
|
+
return false
|
|
873
|
+
}
|
|
874
|
+
return true
|
|
875
875
|
}
|
|
876
876
|
|
|
877
877
|
func functionalTypeDeclarationName(node *shimast.Node) string {
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
878
|
+
switch node.Kind {
|
|
879
|
+
case shimast.KindInterfaceDeclaration:
|
|
880
|
+
if decl := node.AsInterfaceDeclaration(); decl != nil {
|
|
881
|
+
return identifierText(decl.Name())
|
|
882
|
+
}
|
|
883
|
+
case shimast.KindTypeAliasDeclaration:
|
|
884
|
+
if decl := node.AsTypeAliasDeclaration(); decl != nil {
|
|
885
|
+
return identifierText(decl.Name())
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
return ""
|
|
889
889
|
}
|
|
890
890
|
|
|
891
891
|
func functionalDeclarationRuleApplies(opts functionalImmutabilityDeclarationOptions, name string) bool {
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
892
|
+
if len(opts.Rules) == 0 {
|
|
893
|
+
return true
|
|
894
|
+
}
|
|
895
|
+
for _, rule := range opts.Rules {
|
|
896
|
+
if functionalPatternOptionMatches(rule.Identifiers, name) {
|
|
897
|
+
return true
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
return false
|
|
901
901
|
}
|
|
902
902
|
|
|
903
903
|
func functionalPatternOptionMatches(raw interface{}, text string) bool {
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
904
|
+
switch value := raw.(type) {
|
|
905
|
+
case string:
|
|
906
|
+
return functionalPatternMatches(value, text)
|
|
907
|
+
case []interface{}:
|
|
908
|
+
for _, item := range value {
|
|
909
|
+
if pattern, ok := item.(string); ok && functionalPatternMatches(pattern, text) {
|
|
910
|
+
return true
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
return false
|
|
915
915
|
}
|
|
916
916
|
|
|
917
917
|
func functionalPatternMatches(pattern, name string) bool {
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
918
|
+
if pattern == "" || name == "" {
|
|
919
|
+
return false
|
|
920
|
+
}
|
|
921
|
+
if pattern == name {
|
|
922
|
+
return true
|
|
923
|
+
}
|
|
924
|
+
re, err := regexp.Compile(pattern)
|
|
925
|
+
return err == nil && re.MatchString(name)
|
|
926
926
|
}
|
|
927
927
|
|
|
928
928
|
func functionalDeclarationIsMutable(node *shimast.Node) bool {
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
929
|
+
switch node.Kind {
|
|
930
|
+
case shimast.KindInterfaceDeclaration:
|
|
931
|
+
for _, member := range containerMembers(node) {
|
|
932
|
+
if member.Kind == shimast.KindPropertySignature && !hasModifier(member, shimast.KindReadonlyKeyword) {
|
|
933
|
+
return true
|
|
934
|
+
}
|
|
935
|
+
if functionalMutableType(declarationTypeNode(member)) {
|
|
936
|
+
return true
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
case shimast.KindTypeAliasDeclaration:
|
|
940
|
+
decl := node.AsTypeAliasDeclaration()
|
|
941
|
+
return decl != nil && functionalMutableType(decl.Type)
|
|
942
|
+
}
|
|
943
|
+
return false
|
|
944
944
|
}
|
|
945
945
|
|
|
946
946
|
func init() {
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
947
|
+
Register(functionalParameters{})
|
|
948
|
+
Register(functionalImmutableData{})
|
|
949
|
+
Register(functionalNoClassInheritance{})
|
|
950
|
+
Register(functionalNoClasses{})
|
|
951
|
+
Register(functionalNoConditionalStatements{})
|
|
952
|
+
Register(functionalNoExpressionStatements{})
|
|
953
|
+
Register(functionalNoLet{})
|
|
954
|
+
Register(functionalNoLoopStatements{})
|
|
955
|
+
Register(functionalNoMixedTypes{})
|
|
956
|
+
Register(functionalNoPromiseReject{})
|
|
957
|
+
Register(functionalNoReturnVoid{})
|
|
958
|
+
Register(functionalNoThisExpressions{})
|
|
959
|
+
Register(functionalNoThrowStatements{})
|
|
960
|
+
Register(functionalNoTryStatements{})
|
|
961
|
+
Register(functionalPreferImmutableTypes{})
|
|
962
|
+
Register(functionalPreferPropertySignatures{})
|
|
963
|
+
Register(functionalPreferReadonlyType{})
|
|
964
|
+
Register(functionalPreferTacit{})
|
|
965
|
+
Register(functionalReadonlyType{})
|
|
966
|
+
Register(functionalTypeDeclarationImmutability{})
|
|
967
967
|
}
|