@ttsc/lint 0.14.0-dev.20260529.1 → 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 +85 -87
- 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,8 +1,8 @@
|
|
|
1
1
|
package linthost
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
5
|
+
shimchecker "github.com/microsoft/typescript-go/shim/checker"
|
|
6
6
|
)
|
|
7
7
|
|
|
8
8
|
const promiseRulePrefix = "promise/"
|
|
@@ -22,42 +22,42 @@ type awaitThenable struct{}
|
|
|
22
22
|
|
|
23
23
|
func (awaitThenable) Name() string { return "typescript/await-thenable" }
|
|
24
24
|
func (awaitThenable) NeedsTypeChecker() bool {
|
|
25
|
-
|
|
25
|
+
return true
|
|
26
26
|
}
|
|
27
27
|
func (awaitThenable) Visits() []shimast.Kind {
|
|
28
|
-
|
|
28
|
+
return []shimast.Kind{shimast.KindAwaitExpression}
|
|
29
29
|
}
|
|
30
30
|
func (awaitThenable) Check(ctx *Context, node *shimast.Node) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
31
|
+
if ctx.Checker == nil {
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
expr := node.AsAwaitExpression()
|
|
35
|
+
if expr == nil || expr.Expression == nil {
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
operandType := ctx.Checker.GetTypeAtLocation(expr.Expression)
|
|
39
|
+
if operandType == nil {
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
if isAwaitable(ctx.Checker, operandType) {
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
message := "Unexpected `await` of a non-Promise (non-thenable) value."
|
|
46
|
+
// Fix: drop the `await ` keyword and the following whitespace by
|
|
47
|
+
// replacing [node.Pos(), expr.Expression.Pos()) with empty text.
|
|
48
|
+
// `node.Pos()` may include leading trivia; use tokenRange to anchor
|
|
49
|
+
// the start at the actual `await` token.
|
|
50
|
+
startPos, _ := tokenRange(ctx.File, node)
|
|
51
|
+
operandStart := expr.Expression.Pos()
|
|
52
|
+
if startPos < 0 || operandStart <= startPos {
|
|
53
|
+
ctx.Report(node, message)
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
ctx.ReportFix(
|
|
57
|
+
node,
|
|
58
|
+
message,
|
|
59
|
+
TextEdit{Pos: startPos, End: operandStart, Text: ""},
|
|
60
|
+
)
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
// isAwaitable reports whether `t` is safe to `await`. A type is awaitable
|
|
@@ -79,48 +79,48 @@ func (awaitThenable) Check(ctx *Context, node *shimast.Node) {
|
|
|
79
79
|
// necessary because GetPromisedTypeOfPromise returns nil on composite types
|
|
80
80
|
// like `Promise<X> | number` even though the expression can legally be awaited.
|
|
81
81
|
func isAwaitable(checker *shimchecker.Checker, t *shimchecker.Type) bool {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
82
|
+
if checker == nil || t == nil {
|
|
83
|
+
return false
|
|
84
|
+
}
|
|
85
|
+
flags := t.Flags()
|
|
86
|
+
if flags&shimchecker.TypeFlagsAny != 0 ||
|
|
87
|
+
flags&shimchecker.TypeFlagsUnknown != 0 ||
|
|
88
|
+
flags&shimchecker.TypeFlagsNever != 0 {
|
|
89
|
+
return true
|
|
90
|
+
}
|
|
91
|
+
if flags&(shimchecker.TypeFlagsUnion|shimchecker.TypeFlagsIntersection) != 0 {
|
|
92
|
+
for _, part := range t.Types() {
|
|
93
|
+
if part == nil {
|
|
94
|
+
continue
|
|
95
|
+
}
|
|
96
|
+
if isAwaitable(checker, part) {
|
|
97
|
+
return true
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return false
|
|
101
|
+
}
|
|
102
|
+
if checker.GetPromisedTypeOfPromise(t) != nil {
|
|
103
|
+
return true
|
|
104
|
+
}
|
|
105
|
+
return isThenableType(checker, t)
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
// isThenableType reports whether t has a callable `then` property, which is
|
|
109
109
|
// the runtime-observable contract for "thenable" in the ES spec. The check
|
|
110
110
|
// intentionally mirrors what the JS engine uses at await-time.
|
|
111
111
|
func isThenableType(checker *shimchecker.Checker, t *shimchecker.Type) bool {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
112
|
+
if checker == nil || t == nil {
|
|
113
|
+
return false
|
|
114
|
+
}
|
|
115
|
+
prop := checker.GetPropertyOfType(t, "then")
|
|
116
|
+
if prop == nil {
|
|
117
|
+
return false
|
|
118
|
+
}
|
|
119
|
+
propType := checker.GetTypeOfSymbol(prop)
|
|
120
|
+
if propType == nil {
|
|
121
|
+
return false
|
|
122
|
+
}
|
|
123
|
+
return len(checker.GetSignaturesOfType(propType, shimchecker.SignatureKindCall)) > 0
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
// noFloatingPromises: an `ExpressionStatement` whose value is a Promise but
|
|
@@ -140,37 +140,37 @@ type noFloatingPromises struct{}
|
|
|
140
140
|
|
|
141
141
|
func (noFloatingPromises) Name() string { return "typescript/no-floating-promises" }
|
|
142
142
|
func (noFloatingPromises) NeedsTypeChecker() bool {
|
|
143
|
-
|
|
143
|
+
return true
|
|
144
144
|
}
|
|
145
145
|
func (noFloatingPromises) Visits() []shimast.Kind {
|
|
146
|
-
|
|
146
|
+
return []shimast.Kind{shimast.KindExpressionStatement}
|
|
147
147
|
}
|
|
148
148
|
func (noFloatingPromises) Check(ctx *Context, node *shimast.Node) {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
149
|
+
if ctx.Checker == nil {
|
|
150
|
+
return
|
|
151
|
+
}
|
|
152
|
+
stmt := node.AsExpressionStatement()
|
|
153
|
+
if stmt == nil || stmt.Expression == nil {
|
|
154
|
+
return
|
|
155
|
+
}
|
|
156
|
+
expr := stripParens(stmt.Expression)
|
|
157
|
+
if expr == nil {
|
|
158
|
+
return
|
|
159
|
+
}
|
|
160
|
+
// Syntactic discharges short-circuit the Checker call: any of these
|
|
161
|
+
// expression shapes already signals that the author opted out of the
|
|
162
|
+
// "discarded" reading, so the rule never needs to walk the type system.
|
|
163
|
+
if isPromiseHandledExpression(expr) {
|
|
164
|
+
return
|
|
165
|
+
}
|
|
166
|
+
t := ctx.Checker.GetTypeAtLocation(expr)
|
|
167
|
+
if t == nil {
|
|
168
|
+
return
|
|
169
|
+
}
|
|
170
|
+
if !isPromiseTypedExpression(ctx.Checker, t) {
|
|
171
|
+
return
|
|
172
|
+
}
|
|
173
|
+
ctx.Report(node, "Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler, or be explicitly marked as ignored with the `void` operator.")
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
// isPromiseHandledExpression reports whether the expression is syntactically
|
|
@@ -180,29 +180,29 @@ func (noFloatingPromises) Check(ctx *Context, node *shimast.Node) {
|
|
|
180
180
|
// `then` only defuses it when an explicit rejection handler is supplied as the
|
|
181
181
|
// second argument.
|
|
182
182
|
func isPromiseHandledExpression(expr *shimast.Node) bool {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
183
|
+
if expr == nil {
|
|
184
|
+
return false
|
|
185
|
+
}
|
|
186
|
+
switch expr.Kind {
|
|
187
|
+
case shimast.KindAwaitExpression, shimast.KindVoidExpression:
|
|
188
|
+
return true
|
|
189
|
+
case shimast.KindCallExpression:
|
|
190
|
+
call := expr.AsCallExpression()
|
|
191
|
+
if call == nil {
|
|
192
|
+
return false
|
|
193
|
+
}
|
|
194
|
+
method, ok := promiseMethodCallName(call)
|
|
195
|
+
if !ok {
|
|
196
|
+
return false
|
|
197
|
+
}
|
|
198
|
+
switch method {
|
|
199
|
+
case "catch", "finally":
|
|
200
|
+
return true
|
|
201
|
+
case "then":
|
|
202
|
+
return call.Arguments != nil && len(call.Arguments.Nodes) >= 2
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return false
|
|
206
206
|
}
|
|
207
207
|
|
|
208
208
|
// promiseMethodCallName returns the trailing property name when the call's
|
|
@@ -213,14 +213,14 @@ func isPromiseHandledExpression(expr *shimast.Node) bool {
|
|
|
213
213
|
// constraint would otherwise reject legitimate handlers on user-typed
|
|
214
214
|
// objects such as `repo.users.findById(id).catch(reportError)`.
|
|
215
215
|
func promiseMethodCallName(call *shimast.CallExpression) (string, bool) {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
216
|
+
if call == nil || call.Expression == nil {
|
|
217
|
+
return "", false
|
|
218
|
+
}
|
|
219
|
+
_, method, ok := promisePropertyAccessParts(call.Expression)
|
|
220
|
+
if !ok {
|
|
221
|
+
return "", false
|
|
222
|
+
}
|
|
223
|
+
return method, true
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
// isPromiseTypedExpression reports whether `t` represents a Promise (or thenable)
|
|
@@ -229,28 +229,28 @@ func promiseMethodCallName(call *shimast.CallExpression) (string, bool) {
|
|
|
229
229
|
// generic-helper boundaries; `never` is also skipped because a function whose
|
|
230
230
|
// return type is `never` cannot float a real Promise.
|
|
231
231
|
func isPromiseTypedExpression(checker *shimchecker.Checker, t *shimchecker.Type) bool {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
232
|
+
if checker == nil || t == nil {
|
|
233
|
+
return false
|
|
234
|
+
}
|
|
235
|
+
flags := t.Flags()
|
|
236
|
+
if flags&(shimchecker.TypeFlagsAny|shimchecker.TypeFlagsUnknown|shimchecker.TypeFlagsNever) != 0 {
|
|
237
|
+
return false
|
|
238
|
+
}
|
|
239
|
+
if flags&(shimchecker.TypeFlagsUnion|shimchecker.TypeFlagsIntersection) != 0 {
|
|
240
|
+
for _, part := range t.Types() {
|
|
241
|
+
if part == nil {
|
|
242
|
+
continue
|
|
243
|
+
}
|
|
244
|
+
if isPromiseTypedExpression(checker, part) {
|
|
245
|
+
return true
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return false
|
|
249
|
+
}
|
|
250
|
+
if checker.GetPromisedTypeOfPromise(t) != nil {
|
|
251
|
+
return true
|
|
252
|
+
}
|
|
253
|
+
return isThenableType(checker, t)
|
|
254
254
|
}
|
|
255
255
|
|
|
256
256
|
// returnAwait: `return promise;` inside try/catch/finally lets the rejection
|
|
@@ -276,38 +276,38 @@ type returnAwait struct{}
|
|
|
276
276
|
|
|
277
277
|
func (returnAwait) Name() string { return "typescript/return-await" }
|
|
278
278
|
func (returnAwait) NeedsTypeChecker() bool {
|
|
279
|
-
|
|
279
|
+
return true
|
|
280
280
|
}
|
|
281
281
|
func (returnAwait) Visits() []shimast.Kind {
|
|
282
|
-
|
|
282
|
+
return []shimast.Kind{shimast.KindReturnStatement}
|
|
283
283
|
}
|
|
284
284
|
func (returnAwait) Check(ctx *Context, node *shimast.Node) {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
285
|
+
if ctx.Checker == nil {
|
|
286
|
+
return
|
|
287
|
+
}
|
|
288
|
+
ret := node.AsReturnStatement()
|
|
289
|
+
if ret == nil || ret.Expression == nil {
|
|
290
|
+
return
|
|
291
|
+
}
|
|
292
|
+
expr := stripParens(ret.Expression)
|
|
293
|
+
if expr == nil {
|
|
294
|
+
return
|
|
295
|
+
}
|
|
296
|
+
// Already `return await promise;` — author opted in.
|
|
297
|
+
if expr.Kind == shimast.KindAwaitExpression {
|
|
298
|
+
return
|
|
299
|
+
}
|
|
300
|
+
if !returnAwaitInsideHandler(node) {
|
|
301
|
+
return
|
|
302
|
+
}
|
|
303
|
+
t := ctx.Checker.GetTypeAtLocation(expr)
|
|
304
|
+
if t == nil {
|
|
305
|
+
return
|
|
306
|
+
}
|
|
307
|
+
if ctx.Checker.GetPromisedTypeOfPromise(t) == nil {
|
|
308
|
+
return
|
|
309
|
+
}
|
|
310
|
+
ctx.Report(node, "Returning a Promise from a try/catch/finally block requires `await` so the surrounding handler observes the rejection.")
|
|
311
311
|
}
|
|
312
312
|
|
|
313
313
|
// returnAwaitInsideHandler walks the parent chain from `node` upward, stops at
|
|
@@ -319,35 +319,35 @@ func (returnAwait) Check(ctx *Context, node *shimast.Node) {
|
|
|
319
319
|
// inside a nested function targets that inner function, so it cannot escape
|
|
320
320
|
// the outer try/catch/finally and must not trip the rule.
|
|
321
321
|
func returnAwaitInsideHandler(node *shimast.Node) bool {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
322
|
+
cur := node.Parent
|
|
323
|
+
for cur != nil {
|
|
324
|
+
if isFunctionLikeKind(cur) || cur.Kind == shimast.KindSourceFile {
|
|
325
|
+
return false
|
|
326
|
+
}
|
|
327
|
+
if cur.Kind == shimast.KindBlock {
|
|
328
|
+
grand := cur.Parent
|
|
329
|
+
if grand != nil && grand.Kind == shimast.KindTryStatement {
|
|
330
|
+
try := grand.AsTryStatement()
|
|
331
|
+
if try != nil {
|
|
332
|
+
if try.TryBlock == cur {
|
|
333
|
+
return true
|
|
334
|
+
}
|
|
335
|
+
if try.FinallyBlock == cur {
|
|
336
|
+
return true
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
if cur.Kind == shimast.KindCatchClause {
|
|
342
|
+
// Inside a catch: only fires when another try/catch/finally
|
|
343
|
+
// wraps this one so the rejection can be re-observed.
|
|
344
|
+
if hasEnclosingTryContext(cur.Parent) {
|
|
345
|
+
return true
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
cur = cur.Parent
|
|
349
|
+
}
|
|
350
|
+
return false
|
|
351
351
|
}
|
|
352
352
|
|
|
353
353
|
// hasEnclosingTryContext walks upward from `node` and reports whether the path
|
|
@@ -355,24 +355,24 @@ func returnAwaitInsideHandler(node *shimast.Node) bool {
|
|
|
355
355
|
// finally block. Used by the catch-clause arm of returnAwaitInsideHandler to
|
|
356
356
|
// decide whether the catch is itself wrapped by another handler.
|
|
357
357
|
func hasEnclosingTryContext(node *shimast.Node) bool {
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
358
|
+
for cur := node; cur != nil; cur = cur.Parent {
|
|
359
|
+
if isFunctionLikeKind(cur) || cur.Kind == shimast.KindSourceFile {
|
|
360
|
+
return false
|
|
361
|
+
}
|
|
362
|
+
if cur.Kind == shimast.KindBlock {
|
|
363
|
+
grand := cur.Parent
|
|
364
|
+
if grand != nil && grand.Kind == shimast.KindTryStatement {
|
|
365
|
+
try := grand.AsTryStatement()
|
|
366
|
+
if try != nil && (try.TryBlock == cur || try.FinallyBlock == cur) {
|
|
367
|
+
return true
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
if cur.Kind == shimast.KindCatchClause {
|
|
372
|
+
return true
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
return false
|
|
376
376
|
}
|
|
377
377
|
|
|
378
378
|
// promise/param-names mirrors eslint-plugin-promise's constructor convention:
|
|
@@ -382,800 +382,800 @@ type promiseParamNames struct{}
|
|
|
382
382
|
|
|
383
383
|
func (promiseParamNames) Name() string { return promiseRulePrefix + "param-names" }
|
|
384
384
|
func (promiseParamNames) Visits() []shimast.Kind {
|
|
385
|
-
|
|
385
|
+
return []shimast.Kind{shimast.KindNewExpression}
|
|
386
386
|
}
|
|
387
387
|
func (promiseParamNames) Check(ctx *Context, node *shimast.Node) {
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
388
|
+
executor := promiseExecutor(node)
|
|
389
|
+
if executor == nil {
|
|
390
|
+
return
|
|
391
|
+
}
|
|
392
|
+
params := executor.Parameters()
|
|
393
|
+
if len(params) > 0 {
|
|
394
|
+
name := parameterIdentifierName(params[0])
|
|
395
|
+
if name != "" && name != "resolve" && name != "_resolve" {
|
|
396
|
+
ctx.Report(params[0], "Promise constructor first parameter should be named resolve.")
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
if len(params) > 1 {
|
|
400
|
+
name := parameterIdentifierName(params[1])
|
|
401
|
+
if name != "" && name != "reject" && name != "_reject" {
|
|
402
|
+
ctx.Report(params[1], "Promise constructor second parameter should be named reject.")
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
405
|
}
|
|
406
406
|
|
|
407
407
|
type promiseAvoidNew struct{}
|
|
408
408
|
|
|
409
409
|
func (promiseAvoidNew) Name() string { return promiseRulePrefix + "avoid-new" }
|
|
410
410
|
func (promiseAvoidNew) Visits() []shimast.Kind {
|
|
411
|
-
|
|
411
|
+
return []shimast.Kind{shimast.KindNewExpression}
|
|
412
412
|
}
|
|
413
413
|
func (promiseAvoidNew) Check(ctx *Context, node *shimast.Node) {
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
414
|
+
ne := node.AsNewExpression()
|
|
415
|
+
if ne != nil && identifierText(ne.Expression) == "Promise" {
|
|
416
|
+
ctx.Report(node, "Avoid creating new promises directly.")
|
|
417
|
+
}
|
|
418
418
|
}
|
|
419
419
|
|
|
420
420
|
type promiseNoNewStatics struct{}
|
|
421
421
|
|
|
422
422
|
func (promiseNoNewStatics) Name() string { return promiseRulePrefix + "no-new-statics" }
|
|
423
423
|
func (promiseNoNewStatics) Visits() []shimast.Kind {
|
|
424
|
-
|
|
424
|
+
return []shimast.Kind{shimast.KindNewExpression}
|
|
425
425
|
}
|
|
426
426
|
func (promiseNoNewStatics) Check(ctx *Context, node *shimast.Node) {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
427
|
+
ne := node.AsNewExpression()
|
|
428
|
+
if ne == nil {
|
|
429
|
+
return
|
|
430
|
+
}
|
|
431
|
+
method, ok := promiseStaticMethod(ne.Expression)
|
|
432
|
+
if ok {
|
|
433
|
+
ctx.Report(node, "Avoid calling new on Promise."+method+"().")
|
|
434
|
+
}
|
|
435
435
|
}
|
|
436
436
|
|
|
437
437
|
type promiseValidParams struct{}
|
|
438
438
|
|
|
439
439
|
func (promiseValidParams) Name() string { return promiseRulePrefix + "valid-params" }
|
|
440
440
|
func (promiseValidParams) Visits() []shimast.Kind {
|
|
441
|
-
|
|
441
|
+
return []shimast.Kind{shimast.KindCallExpression}
|
|
442
442
|
}
|
|
443
443
|
func (promiseValidParams) Check(ctx *Context, node *shimast.Node) {
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
444
|
+
call := node.AsCallExpression()
|
|
445
|
+
if call == nil || call.Arguments == nil {
|
|
446
|
+
return
|
|
447
|
+
}
|
|
448
|
+
_, method, ok := promiseCallMethod(call)
|
|
449
|
+
if !ok {
|
|
450
|
+
return
|
|
451
|
+
}
|
|
452
|
+
count := len(call.Arguments.Nodes)
|
|
453
|
+
switch method {
|
|
454
|
+
case "resolve", "reject":
|
|
455
|
+
if count > 1 {
|
|
456
|
+
ctx.Report(node, "Promise."+method+"() accepts at most one argument.")
|
|
457
|
+
}
|
|
458
|
+
case "then":
|
|
459
|
+
if count < 1 || count > 2 {
|
|
460
|
+
ctx.Report(node, "Promise then() expects one or two arguments.")
|
|
461
|
+
}
|
|
462
|
+
case "race", "all", "allSettled", "any", "catch", "finally":
|
|
463
|
+
if count != 1 {
|
|
464
|
+
ctx.Report(node, "Promise "+method+"() expects exactly one argument.")
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
467
|
}
|
|
468
468
|
|
|
469
469
|
type promiseSpecOnly struct{}
|
|
470
470
|
|
|
471
471
|
func (promiseSpecOnly) Name() string { return promiseRulePrefix + "spec-only" }
|
|
472
472
|
func (promiseSpecOnly) Visits() []shimast.Kind {
|
|
473
|
-
|
|
473
|
+
return []shimast.Kind{shimast.KindPropertyAccessExpression}
|
|
474
474
|
}
|
|
475
475
|
func (promiseSpecOnly) Check(ctx *Context, node *shimast.Node) {
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
476
|
+
obj, prop, ok := promisePropertyAccessParts(node)
|
|
477
|
+
if !ok {
|
|
478
|
+
return
|
|
479
|
+
}
|
|
480
|
+
if identifierText(obj) == "Promise" {
|
|
481
|
+
if prop == "prototype" {
|
|
482
|
+
return
|
|
483
|
+
}
|
|
484
|
+
if !isPromiseStaticMethod(prop) {
|
|
485
|
+
ctx.Report(node, "Avoid using non-standard Promise."+prop+".")
|
|
486
|
+
}
|
|
487
|
+
return
|
|
488
|
+
}
|
|
489
|
+
base, baseProp, baseOK := promisePropertyAccessParts(obj)
|
|
490
|
+
if baseOK && identifierText(base) == "Promise" && baseProp == "prototype" && !isPromiseInstanceMethod(prop) {
|
|
491
|
+
ctx.Report(node, "Avoid using non-standard Promise.prototype."+prop+".")
|
|
492
|
+
}
|
|
493
493
|
}
|
|
494
494
|
|
|
495
495
|
type promiseNoNative struct{}
|
|
496
496
|
|
|
497
497
|
func (promiseNoNative) Name() string { return promiseRulePrefix + "no-native" }
|
|
498
498
|
func (promiseNoNative) Visits() []shimast.Kind {
|
|
499
|
-
|
|
499
|
+
return []shimast.Kind{shimast.KindSourceFile}
|
|
500
500
|
}
|
|
501
501
|
func (promiseNoNative) Check(ctx *Context, node *shimast.Node) {
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
502
|
+
if ctx.File == nil || fileDeclaresPromise(node) {
|
|
503
|
+
return
|
|
504
|
+
}
|
|
505
|
+
reported := false
|
|
506
|
+
walkDescendants(node, func(child *shimast.Node) {
|
|
507
|
+
if reported || child == nil {
|
|
508
|
+
return
|
|
509
|
+
}
|
|
510
|
+
switch child.Kind {
|
|
511
|
+
case shimast.KindNewExpression:
|
|
512
|
+
ne := child.AsNewExpression()
|
|
513
|
+
if ne != nil && identifierText(ne.Expression) == "Promise" {
|
|
514
|
+
reported = true
|
|
515
|
+
ctx.Report(ne.Expression, "\"Promise\" is not defined in ES5 environments.")
|
|
516
|
+
}
|
|
517
|
+
case shimast.KindPropertyAccessExpression:
|
|
518
|
+
obj, _, ok := promisePropertyAccessParts(child)
|
|
519
|
+
if ok && identifierText(obj) == "Promise" {
|
|
520
|
+
reported = true
|
|
521
|
+
ctx.Report(obj, "\"Promise\" is not defined in ES5 environments.")
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
})
|
|
525
525
|
}
|
|
526
526
|
|
|
527
527
|
type promisePreferAwaitToThen struct{}
|
|
528
528
|
|
|
529
529
|
func (promisePreferAwaitToThen) Name() string { return promiseRulePrefix + "prefer-await-to-then" }
|
|
530
530
|
func (promisePreferAwaitToThen) Visits() []shimast.Kind {
|
|
531
|
-
|
|
531
|
+
return []shimast.Kind{shimast.KindCallExpression}
|
|
532
532
|
}
|
|
533
533
|
func (promisePreferAwaitToThen) Check(ctx *Context, node *shimast.Node) {
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
534
|
+
call := node.AsCallExpression()
|
|
535
|
+
_, method, ok := promiseCallMethod(call)
|
|
536
|
+
if ok && isPromiseInstanceMethod(method) {
|
|
537
|
+
ctx.Report(node, "Prefer async/await to promise "+method+"() chains.")
|
|
538
|
+
}
|
|
539
539
|
}
|
|
540
540
|
|
|
541
541
|
type promisePreferCatch struct{}
|
|
542
542
|
|
|
543
543
|
func (promisePreferCatch) Name() string { return promiseRulePrefix + "prefer-catch" }
|
|
544
544
|
func (promisePreferCatch) Visits() []shimast.Kind {
|
|
545
|
-
|
|
545
|
+
return []shimast.Kind{shimast.KindCallExpression}
|
|
546
546
|
}
|
|
547
547
|
func (promisePreferCatch) Check(ctx *Context, node *shimast.Node) {
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
548
|
+
call := node.AsCallExpression()
|
|
549
|
+
_, method, ok := promiseCallMethod(call)
|
|
550
|
+
if !ok || method != "then" || call.Arguments == nil || len(call.Arguments.Nodes) < 2 {
|
|
551
|
+
return
|
|
552
|
+
}
|
|
553
|
+
ctx.Report(call.Arguments.Nodes[1], "Prefer catch() to passing a rejection handler to then().")
|
|
554
554
|
}
|
|
555
555
|
|
|
556
556
|
type promiseCatchOrReturn struct{}
|
|
557
557
|
|
|
558
558
|
func (promiseCatchOrReturn) Name() string { return promiseRulePrefix + "catch-or-return" }
|
|
559
559
|
func (promiseCatchOrReturn) Visits() []shimast.Kind {
|
|
560
|
-
|
|
560
|
+
return []shimast.Kind{shimast.KindExpressionStatement}
|
|
561
561
|
}
|
|
562
562
|
func (promiseCatchOrReturn) Check(ctx *Context, node *shimast.Node) {
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
563
|
+
stmt := node.AsExpressionStatement()
|
|
564
|
+
if stmt == nil || stmt.Expression == nil {
|
|
565
|
+
return
|
|
566
|
+
}
|
|
567
|
+
if promiseChainHasMethod(stmt.Expression, "then") && !promiseChainHasMethod(stmt.Expression, "catch") {
|
|
568
|
+
ctx.Report(node, "Promise chains should be returned or terminated with catch().")
|
|
569
|
+
}
|
|
570
570
|
}
|
|
571
571
|
|
|
572
572
|
type promiseAlwaysReturn struct{}
|
|
573
573
|
|
|
574
574
|
func (promiseAlwaysReturn) Name() string { return promiseRulePrefix + "always-return" }
|
|
575
575
|
func (promiseAlwaysReturn) Visits() []shimast.Kind {
|
|
576
|
-
|
|
576
|
+
return []shimast.Kind{shimast.KindCallExpression}
|
|
577
577
|
}
|
|
578
578
|
func (promiseAlwaysReturn) Check(ctx *Context, node *shimast.Node) {
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
579
|
+
call := node.AsCallExpression()
|
|
580
|
+
_, method, ok := promiseCallMethod(call)
|
|
581
|
+
if !ok || method != "then" || call.Arguments == nil || len(call.Arguments.Nodes) == 0 {
|
|
582
|
+
return
|
|
583
|
+
}
|
|
584
|
+
callback := stripParens(call.Arguments.Nodes[0])
|
|
585
|
+
if callback == nil || !isFunctionLikeKind(callback) {
|
|
586
|
+
return
|
|
587
|
+
}
|
|
588
|
+
body := callback.Body()
|
|
589
|
+
if body == nil || body.Kind != shimast.KindBlock {
|
|
590
|
+
return
|
|
591
|
+
}
|
|
592
|
+
if !blockReturnsOrThrows(body) {
|
|
593
|
+
ctx.Report(callback, "Each then() callback should return a value or throw.")
|
|
594
|
+
}
|
|
595
595
|
}
|
|
596
596
|
|
|
597
597
|
type promiseNoReturnWrap struct{}
|
|
598
598
|
|
|
599
599
|
func (promiseNoReturnWrap) Name() string { return promiseRulePrefix + "no-return-wrap" }
|
|
600
600
|
func (promiseNoReturnWrap) Visits() []shimast.Kind {
|
|
601
|
-
|
|
601
|
+
return []shimast.Kind{shimast.KindReturnStatement, shimast.KindArrowFunction}
|
|
602
602
|
}
|
|
603
603
|
func (promiseNoReturnWrap) Check(ctx *Context, node *shimast.Node) {
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
604
|
+
switch node.Kind {
|
|
605
|
+
case shimast.KindReturnStatement:
|
|
606
|
+
ret := node.AsReturnStatement()
|
|
607
|
+
if ret == nil || ret.Expression == nil || !isInsidePromiseCallbackFunction(node) {
|
|
608
|
+
return
|
|
609
|
+
}
|
|
610
|
+
if method, ok := promiseResolveRejectCall(ret.Expression); ok {
|
|
611
|
+
ctx.Report(ret.Expression, "Avoid wrapping return values in Promise."+method+"().")
|
|
612
|
+
}
|
|
613
|
+
case shimast.KindArrowFunction:
|
|
614
|
+
arrow := node.AsArrowFunction()
|
|
615
|
+
if arrow == nil || arrow.Body == nil || arrow.Body.Kind == shimast.KindBlock || !isPromiseCallbackFunction(node) {
|
|
616
|
+
return
|
|
617
|
+
}
|
|
618
|
+
if method, ok := promiseResolveRejectCall(arrow.Body); ok {
|
|
619
|
+
ctx.Report(arrow.Body, "Avoid wrapping return values in Promise."+method+"().")
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
622
|
}
|
|
623
623
|
|
|
624
624
|
type promiseNoReturnInFinally struct{}
|
|
625
625
|
|
|
626
626
|
func (promiseNoReturnInFinally) Name() string { return promiseRulePrefix + "no-return-in-finally" }
|
|
627
627
|
func (promiseNoReturnInFinally) Visits() []shimast.Kind {
|
|
628
|
-
|
|
628
|
+
return []shimast.Kind{shimast.KindReturnStatement}
|
|
629
629
|
}
|
|
630
630
|
func (promiseNoReturnInFinally) Check(ctx *Context, node *shimast.Node) {
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
631
|
+
if fn := nearestFunctionLike(node); fn != nil && isPromiseCallbackFunctionFor(fn, "finally") {
|
|
632
|
+
ctx.Report(node, "Do not return from a Promise finally() callback.")
|
|
633
|
+
}
|
|
634
634
|
}
|
|
635
635
|
|
|
636
636
|
type promiseNoNesting struct{}
|
|
637
637
|
|
|
638
638
|
func (promiseNoNesting) Name() string { return promiseRulePrefix + "no-nesting" }
|
|
639
639
|
func (promiseNoNesting) Visits() []shimast.Kind {
|
|
640
|
-
|
|
640
|
+
return []shimast.Kind{shimast.KindCallExpression}
|
|
641
641
|
}
|
|
642
642
|
func (promiseNoNesting) Check(ctx *Context, node *shimast.Node) {
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
643
|
+
call := node.AsCallExpression()
|
|
644
|
+
_, method, ok := promiseCallMethod(call)
|
|
645
|
+
if !ok || (method != "then" && method != "catch") {
|
|
646
|
+
return
|
|
647
|
+
}
|
|
648
|
+
if fn := nearestFunctionLike(node); fn != nil && isPromiseCallbackFunction(fn) {
|
|
649
|
+
ctx.Report(node, "Avoid nesting promise callbacks.")
|
|
650
|
+
}
|
|
651
651
|
}
|
|
652
652
|
|
|
653
653
|
type promiseNoCallbackInPromise struct{}
|
|
654
654
|
|
|
655
655
|
func (promiseNoCallbackInPromise) Name() string { return promiseRulePrefix + "no-callback-in-promise" }
|
|
656
656
|
func (promiseNoCallbackInPromise) Visits() []shimast.Kind {
|
|
657
|
-
|
|
657
|
+
return []shimast.Kind{shimast.KindCallExpression}
|
|
658
658
|
}
|
|
659
659
|
func (promiseNoCallbackInPromise) Check(ctx *Context, node *shimast.Node) {
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
660
|
+
call := node.AsCallExpression()
|
|
661
|
+
if call == nil {
|
|
662
|
+
return
|
|
663
|
+
}
|
|
664
|
+
if isCallbackCall(call) {
|
|
665
|
+
if fn := nearestFunctionLike(node); fn != nil && isPromiseCallbackFunction(fn) {
|
|
666
|
+
ctx.Report(node, "Avoid calling callbacks inside promise callbacks.")
|
|
667
|
+
}
|
|
668
|
+
return
|
|
669
|
+
}
|
|
670
|
+
_, method, ok := promiseCallMethod(call)
|
|
671
|
+
if !ok || (method != "then" && method != "catch") || call.Arguments == nil || len(call.Arguments.Nodes) == 0 {
|
|
672
|
+
return
|
|
673
|
+
}
|
|
674
|
+
first := stripParens(call.Arguments.Nodes[0])
|
|
675
|
+
if first != nil && first.Kind == shimast.KindIdentifier && isCallbackName(identifierText(first)) {
|
|
676
|
+
ctx.Report(first, "Avoid passing callbacks into promise chains.")
|
|
677
|
+
}
|
|
678
678
|
}
|
|
679
679
|
|
|
680
680
|
type promiseNoPromiseInCallback struct{}
|
|
681
681
|
|
|
682
682
|
func (promiseNoPromiseInCallback) Name() string { return promiseRulePrefix + "no-promise-in-callback" }
|
|
683
683
|
func (promiseNoPromiseInCallback) Visits() []shimast.Kind {
|
|
684
|
-
|
|
684
|
+
return []shimast.Kind{shimast.KindCallExpression}
|
|
685
685
|
}
|
|
686
686
|
func (promiseNoPromiseInCallback) Check(ctx *Context, node *shimast.Node) {
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
687
|
+
call := node.AsCallExpression()
|
|
688
|
+
if call == nil || !isPromiseLikeCall(call) || isDirectReturnValue(node) {
|
|
689
|
+
return
|
|
690
|
+
}
|
|
691
|
+
if fn := nearestFunctionLike(node); fn != nil && isErrorFirstCallback(fn) {
|
|
692
|
+
ctx.Report(call.Expression, "Avoid using promises inside callbacks.")
|
|
693
|
+
}
|
|
694
694
|
}
|
|
695
695
|
|
|
696
696
|
type promisePreferAwaitToCallbacks struct{}
|
|
697
697
|
|
|
698
698
|
func (promisePreferAwaitToCallbacks) Name() string {
|
|
699
|
-
|
|
699
|
+
return promiseRulePrefix + "prefer-await-to-callbacks"
|
|
700
700
|
}
|
|
701
701
|
func (promisePreferAwaitToCallbacks) Visits() []shimast.Kind {
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
702
|
+
return []shimast.Kind{
|
|
703
|
+
shimast.KindCallExpression,
|
|
704
|
+
shimast.KindFunctionDeclaration,
|
|
705
|
+
shimast.KindFunctionExpression,
|
|
706
|
+
shimast.KindArrowFunction,
|
|
707
|
+
}
|
|
708
708
|
}
|
|
709
709
|
func (promisePreferAwaitToCallbacks) Check(ctx *Context, node *shimast.Node) {
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
710
|
+
switch node.Kind {
|
|
711
|
+
case shimast.KindCallExpression:
|
|
712
|
+
call := node.AsCallExpression()
|
|
713
|
+
if call == nil {
|
|
714
|
+
return
|
|
715
|
+
}
|
|
716
|
+
if isCallbackCall(call) {
|
|
717
|
+
ctx.Report(node, "Avoid callbacks. Prefer async/await.")
|
|
718
|
+
return
|
|
719
|
+
}
|
|
720
|
+
if hasErrorFirstCallbackArgument(call) && !isInsideAwaitOrYield(node) {
|
|
721
|
+
ctx.Report(node, "Avoid callbacks. Prefer async/await.")
|
|
722
|
+
}
|
|
723
|
+
default:
|
|
724
|
+
params := node.Parameters()
|
|
725
|
+
if len(params) == 0 {
|
|
726
|
+
return
|
|
727
|
+
}
|
|
728
|
+
lastName := parameterIdentifierName(params[len(params)-1])
|
|
729
|
+
if lastName == "callback" || lastName == "cb" {
|
|
730
|
+
ctx.Report(params[len(params)-1], "Avoid callbacks. Prefer async/await.")
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
733
|
}
|
|
734
734
|
|
|
735
735
|
type promiseNoMultipleResolved struct{}
|
|
736
736
|
|
|
737
737
|
func (promiseNoMultipleResolved) Name() string { return promiseRulePrefix + "no-multiple-resolved" }
|
|
738
738
|
func (promiseNoMultipleResolved) Visits() []shimast.Kind {
|
|
739
|
-
|
|
739
|
+
return []shimast.Kind{shimast.KindNewExpression}
|
|
740
740
|
}
|
|
741
741
|
func (promiseNoMultipleResolved) Check(ctx *Context, node *shimast.Node) {
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
742
|
+
executor := promiseExecutor(node)
|
|
743
|
+
if executor == nil {
|
|
744
|
+
return
|
|
745
|
+
}
|
|
746
|
+
params := executor.Parameters()
|
|
747
|
+
resolverNames := map[string]bool{}
|
|
748
|
+
for i := 0; i < len(params) && i < 2; i++ {
|
|
749
|
+
if name := parameterIdentifierName(params[i]); name != "" {
|
|
750
|
+
resolverNames[name] = true
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
if len(resolverNames) == 0 {
|
|
754
|
+
return
|
|
755
|
+
}
|
|
756
|
+
count := 0
|
|
757
|
+
walkFunctionBody(executor, func(child *shimast.Node) {
|
|
758
|
+
if child == nil || child.Kind != shimast.KindCallExpression {
|
|
759
|
+
return
|
|
760
|
+
}
|
|
761
|
+
call := child.AsCallExpression()
|
|
762
|
+
if call == nil || !resolverNames[callCalleeName(call)] {
|
|
763
|
+
return
|
|
764
|
+
}
|
|
765
|
+
count++
|
|
766
|
+
if count > 1 {
|
|
767
|
+
ctx.Report(child, "Promise should not be resolved multiple times.")
|
|
768
|
+
}
|
|
769
|
+
})
|
|
770
770
|
}
|
|
771
771
|
|
|
772
772
|
func promiseExecutor(node *shimast.Node) *shimast.Node {
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
773
|
+
ne := node.AsNewExpression()
|
|
774
|
+
if ne == nil || identifierText(ne.Expression) != "Promise" || ne.Arguments == nil || len(ne.Arguments.Nodes) == 0 {
|
|
775
|
+
return nil
|
|
776
|
+
}
|
|
777
|
+
executor := stripParens(ne.Arguments.Nodes[0])
|
|
778
|
+
if executor == nil || !isFunctionLikeKind(executor) {
|
|
779
|
+
return nil
|
|
780
|
+
}
|
|
781
|
+
return executor
|
|
782
782
|
}
|
|
783
783
|
|
|
784
784
|
func parameterIdentifierName(node *shimast.Node) string {
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
785
|
+
if node == nil {
|
|
786
|
+
return ""
|
|
787
|
+
}
|
|
788
|
+
param := node.AsParameterDeclaration()
|
|
789
|
+
if param == nil {
|
|
790
|
+
return ""
|
|
791
|
+
}
|
|
792
|
+
return identifierText(param.Name())
|
|
793
793
|
}
|
|
794
794
|
|
|
795
795
|
func promisePropertyAccessParts(node *shimast.Node) (*shimast.Node, string, bool) {
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
796
|
+
node = stripParens(node)
|
|
797
|
+
if node == nil || node.Kind != shimast.KindPropertyAccessExpression {
|
|
798
|
+
return nil, "", false
|
|
799
|
+
}
|
|
800
|
+
access := node.AsPropertyAccessExpression()
|
|
801
|
+
if access == nil {
|
|
802
|
+
return nil, "", false
|
|
803
|
+
}
|
|
804
|
+
prop := identifierText(access.Name())
|
|
805
|
+
return access.Expression, prop, prop != ""
|
|
806
806
|
}
|
|
807
807
|
|
|
808
808
|
func promiseCallMethod(call *shimast.CallExpression) (*shimast.Node, string, bool) {
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
809
|
+
if call == nil || call.Expression == nil {
|
|
810
|
+
return nil, "", false
|
|
811
|
+
}
|
|
812
|
+
object, method, ok := promisePropertyAccessParts(call.Expression)
|
|
813
|
+
if !ok {
|
|
814
|
+
return nil, "", false
|
|
815
|
+
}
|
|
816
|
+
if identifierText(object) == "Promise" && !isPromiseStaticMethod(method) {
|
|
817
|
+
return nil, "", false
|
|
818
|
+
}
|
|
819
|
+
return object, method, true
|
|
820
820
|
}
|
|
821
821
|
|
|
822
822
|
func promiseStaticMethod(node *shimast.Node) (string, bool) {
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
823
|
+
object, method, ok := promisePropertyAccessParts(node)
|
|
824
|
+
if !ok || identifierText(object) != "Promise" || !isPromiseStaticMethod(method) {
|
|
825
|
+
return "", false
|
|
826
|
+
}
|
|
827
|
+
return method, true
|
|
828
828
|
}
|
|
829
829
|
|
|
830
830
|
func isPromiseStaticMethod(method string) bool {
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
831
|
+
switch method {
|
|
832
|
+
case "all", "allSettled", "any", "race", "reject", "resolve", "withResolvers":
|
|
833
|
+
return true
|
|
834
|
+
}
|
|
835
|
+
return false
|
|
836
836
|
}
|
|
837
837
|
|
|
838
838
|
func isPromiseInstanceMethod(method string) bool {
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
839
|
+
switch method {
|
|
840
|
+
case "then", "catch", "finally":
|
|
841
|
+
return true
|
|
842
|
+
}
|
|
843
|
+
return false
|
|
844
844
|
}
|
|
845
845
|
|
|
846
846
|
func isPromiseLikeCall(call *shimast.CallExpression) bool {
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
847
|
+
object, method, ok := promiseCallMethod(call)
|
|
848
|
+
if !ok {
|
|
849
|
+
return false
|
|
850
|
+
}
|
|
851
|
+
if isPromiseInstanceMethod(method) {
|
|
852
|
+
return true
|
|
853
|
+
}
|
|
854
|
+
return identifierText(object) == "Promise" && isPromiseStaticMethod(method)
|
|
855
855
|
}
|
|
856
856
|
|
|
857
857
|
func promiseChainHasMethod(node *shimast.Node, want string) bool {
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
858
|
+
node = stripParens(node)
|
|
859
|
+
for node != nil && node.Kind == shimast.KindCallExpression {
|
|
860
|
+
call := node.AsCallExpression()
|
|
861
|
+
object, method, ok := promiseCallMethod(call)
|
|
862
|
+
if !ok {
|
|
863
|
+
return false
|
|
864
|
+
}
|
|
865
|
+
if method == want {
|
|
866
|
+
return true
|
|
867
|
+
}
|
|
868
|
+
node = object
|
|
869
|
+
}
|
|
870
|
+
return false
|
|
871
871
|
}
|
|
872
872
|
|
|
873
873
|
func promiseResolveRejectCall(node *shimast.Node) (string, bool) {
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
874
|
+
node = stripParens(node)
|
|
875
|
+
if node == nil || node.Kind != shimast.KindCallExpression {
|
|
876
|
+
return "", false
|
|
877
|
+
}
|
|
878
|
+
call := node.AsCallExpression()
|
|
879
|
+
object, method, ok := promiseCallMethod(call)
|
|
880
|
+
if !ok || identifierText(object) != "Promise" || (method != "resolve" && method != "reject") {
|
|
881
|
+
return "", false
|
|
882
|
+
}
|
|
883
|
+
return method, true
|
|
884
884
|
}
|
|
885
885
|
|
|
886
886
|
func nearestFunctionLike(node *shimast.Node) *shimast.Node {
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
887
|
+
for cur := node.Parent; cur != nil; cur = cur.Parent {
|
|
888
|
+
if isFunctionLikeKind(cur) {
|
|
889
|
+
return cur
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
return nil
|
|
893
893
|
}
|
|
894
894
|
|
|
895
895
|
func isInsidePromiseCallbackFunction(node *shimast.Node) bool {
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
896
|
+
if fn := nearestFunctionLike(node); fn != nil {
|
|
897
|
+
return isPromiseCallbackFunction(fn)
|
|
898
|
+
}
|
|
899
|
+
return false
|
|
900
900
|
}
|
|
901
901
|
|
|
902
902
|
func isPromiseCallbackFunction(fn *shimast.Node) bool {
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
903
|
+
return isPromiseCallbackFunctionFor(fn, "then") ||
|
|
904
|
+
isPromiseCallbackFunctionFor(fn, "catch") ||
|
|
905
|
+
isPromiseCallbackFunctionFor(fn, "finally")
|
|
906
906
|
}
|
|
907
907
|
|
|
908
908
|
func isPromiseCallbackFunctionFor(fn *shimast.Node, method string) bool {
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
909
|
+
if fn == nil || !isFunctionLikeKind(fn) {
|
|
910
|
+
return false
|
|
911
|
+
}
|
|
912
|
+
for parent := fn.Parent; parent != nil && parent.Kind == shimast.KindParenthesizedExpression; parent = parent.Parent {
|
|
913
|
+
fn = parent
|
|
914
|
+
}
|
|
915
|
+
callNode := fn.Parent
|
|
916
|
+
if callNode == nil || callNode.Kind != shimast.KindCallExpression {
|
|
917
|
+
return false
|
|
918
|
+
}
|
|
919
|
+
call := callNode.AsCallExpression()
|
|
920
|
+
if call == nil || call.Arguments == nil {
|
|
921
|
+
return false
|
|
922
|
+
}
|
|
923
|
+
found := false
|
|
924
|
+
for _, arg := range call.Arguments.Nodes {
|
|
925
|
+
if stripParens(arg) == fn {
|
|
926
|
+
found = true
|
|
927
|
+
break
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
if !found {
|
|
931
|
+
return false
|
|
932
|
+
}
|
|
933
|
+
_, actual, ok := promiseCallMethod(call)
|
|
934
|
+
return ok && actual == method
|
|
935
935
|
}
|
|
936
936
|
|
|
937
937
|
func blockReturnsOrThrows(block *shimast.Node) bool {
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
938
|
+
if block == nil || block.Kind != shimast.KindBlock {
|
|
939
|
+
return false
|
|
940
|
+
}
|
|
941
|
+
return statementsReturnOrThrow(block.Statements())
|
|
942
942
|
}
|
|
943
943
|
|
|
944
944
|
func statementsReturnOrThrow(statements []*shimast.Node) bool {
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
945
|
+
for _, stmt := range statements {
|
|
946
|
+
if statementReturnsOrThrows(stmt) {
|
|
947
|
+
return true
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
return false
|
|
951
951
|
}
|
|
952
952
|
|
|
953
953
|
func statementReturnsOrThrows(stmt *shimast.Node) bool {
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
954
|
+
if stmt == nil {
|
|
955
|
+
return false
|
|
956
|
+
}
|
|
957
|
+
switch stmt.Kind {
|
|
958
|
+
case shimast.KindReturnStatement, shimast.KindThrowStatement:
|
|
959
|
+
return true
|
|
960
|
+
case shimast.KindBlock:
|
|
961
|
+
return statementsReturnOrThrow(stmt.Statements())
|
|
962
|
+
case shimast.KindIfStatement:
|
|
963
|
+
ifStmt := stmt.AsIfStatement()
|
|
964
|
+
if ifStmt == nil || ifStmt.ThenStatement == nil || ifStmt.ElseStatement == nil {
|
|
965
|
+
return false
|
|
966
|
+
}
|
|
967
|
+
return statementReturnsOrThrows(ifStmt.ThenStatement) &&
|
|
968
|
+
statementReturnsOrThrows(ifStmt.ElseStatement)
|
|
969
|
+
case shimast.KindTryStatement:
|
|
970
|
+
return tryStatementReturnsOrThrows(stmt)
|
|
971
|
+
case shimast.KindSwitchStatement:
|
|
972
|
+
return switchStatementReturnsOrThrows(stmt)
|
|
973
|
+
case shimast.KindLabeledStatement:
|
|
974
|
+
labeled := stmt.AsLabeledStatement()
|
|
975
|
+
return labeled != nil && statementReturnsOrThrows(labeled.Statement)
|
|
976
|
+
}
|
|
977
|
+
return false
|
|
978
978
|
}
|
|
979
979
|
|
|
980
980
|
func tryStatementReturnsOrThrows(stmt *shimast.Node) bool {
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
981
|
+
tryStmt := stmt.AsTryStatement()
|
|
982
|
+
if tryStmt == nil {
|
|
983
|
+
return false
|
|
984
|
+
}
|
|
985
|
+
if tryStmt.FinallyBlock != nil && statementsReturnOrThrow(tryStmt.FinallyBlock.Statements()) {
|
|
986
|
+
return true
|
|
987
|
+
}
|
|
988
|
+
if tryStmt.TryBlock == nil || !statementsReturnOrThrow(tryStmt.TryBlock.Statements()) {
|
|
989
|
+
return false
|
|
990
|
+
}
|
|
991
|
+
if tryStmt.CatchClause == nil {
|
|
992
|
+
return true
|
|
993
|
+
}
|
|
994
|
+
catchClause := tryStmt.CatchClause.AsCatchClause()
|
|
995
|
+
return catchClause != nil &&
|
|
996
|
+
catchClause.Block != nil &&
|
|
997
|
+
statementsReturnOrThrow(catchClause.Block.Statements())
|
|
998
998
|
}
|
|
999
999
|
|
|
1000
1000
|
func switchStatementReturnsOrThrows(stmt *shimast.Node) bool {
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1001
|
+
switchStmt := stmt.AsSwitchStatement()
|
|
1002
|
+
if switchStmt == nil || switchStmt.CaseBlock == nil {
|
|
1003
|
+
return false
|
|
1004
|
+
}
|
|
1005
|
+
caseBlock := switchStmt.CaseBlock.AsCaseBlock()
|
|
1006
|
+
if caseBlock == nil || caseBlock.Clauses == nil {
|
|
1007
|
+
return false
|
|
1008
|
+
}
|
|
1009
|
+
clauses := caseBlock.Clauses.Nodes
|
|
1010
|
+
hasDefault := false
|
|
1011
|
+
for index, clauseNode := range clauses {
|
|
1012
|
+
if clauseNode == nil {
|
|
1013
|
+
return false
|
|
1014
|
+
}
|
|
1015
|
+
if clauseNode.Kind == shimast.KindDefaultClause {
|
|
1016
|
+
hasDefault = true
|
|
1017
|
+
}
|
|
1018
|
+
if !switchClauseEntryReturnsOrThrows(clauses[index:]) {
|
|
1019
|
+
return false
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
return hasDefault
|
|
1023
1023
|
}
|
|
1024
1024
|
|
|
1025
1025
|
func switchClauseEntryReturnsOrThrows(clauses []*shimast.Node) bool {
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1026
|
+
for _, clauseNode := range clauses {
|
|
1027
|
+
clause := clauseNode.AsCaseOrDefaultClause()
|
|
1028
|
+
if clause == nil || clause.Statements == nil {
|
|
1029
|
+
return false
|
|
1030
|
+
}
|
|
1031
|
+
if statementsReturnOrThrow(clause.Statements.Nodes) {
|
|
1032
|
+
return true
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
return false
|
|
1036
1036
|
}
|
|
1037
1037
|
|
|
1038
1038
|
func walkFunctionBody(root *shimast.Node, visit func(*shimast.Node)) {
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1039
|
+
if root == nil {
|
|
1040
|
+
return
|
|
1041
|
+
}
|
|
1042
|
+
var walk func(*shimast.Node)
|
|
1043
|
+
walk = func(node *shimast.Node) {
|
|
1044
|
+
if node == nil {
|
|
1045
|
+
return
|
|
1046
|
+
}
|
|
1047
|
+
if node != root && isFunctionLikeKind(node) {
|
|
1048
|
+
return
|
|
1049
|
+
}
|
|
1050
|
+
visit(node)
|
|
1051
|
+
node.ForEachChild(func(child *shimast.Node) bool {
|
|
1052
|
+
walk(child)
|
|
1053
|
+
return false
|
|
1054
|
+
})
|
|
1055
|
+
}
|
|
1056
|
+
walk(root)
|
|
1057
1057
|
}
|
|
1058
1058
|
|
|
1059
1059
|
func isCallbackName(name string) bool {
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1060
|
+
switch name {
|
|
1061
|
+
case "callback", "cb", "next", "done":
|
|
1062
|
+
return true
|
|
1063
|
+
}
|
|
1064
|
+
return false
|
|
1065
1065
|
}
|
|
1066
1066
|
|
|
1067
1067
|
func isCallbackCall(call *shimast.CallExpression) bool {
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1068
|
+
if call == nil {
|
|
1069
|
+
return false
|
|
1070
|
+
}
|
|
1071
|
+
if isCallbackName(callCalleeName(call)) {
|
|
1072
|
+
return true
|
|
1073
|
+
}
|
|
1074
|
+
return false
|
|
1075
1075
|
}
|
|
1076
1076
|
|
|
1077
1077
|
func isErrorFirstCallback(fn *shimast.Node) bool {
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1078
|
+
if fn == nil || !isFunctionLikeKind(fn) || isPromiseCallbackFunction(fn) {
|
|
1079
|
+
return false
|
|
1080
|
+
}
|
|
1081
|
+
params := fn.Parameters()
|
|
1082
|
+
if len(params) == 0 {
|
|
1083
|
+
return false
|
|
1084
|
+
}
|
|
1085
|
+
switch parameterIdentifierName(params[0]) {
|
|
1086
|
+
case "err", "error":
|
|
1087
|
+
return true
|
|
1088
|
+
}
|
|
1089
|
+
return false
|
|
1090
1090
|
}
|
|
1091
1091
|
|
|
1092
1092
|
func hasErrorFirstCallbackArgument(call *shimast.CallExpression) bool {
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1093
|
+
if call == nil || call.Arguments == nil || len(call.Arguments.Nodes) == 0 {
|
|
1094
|
+
return false
|
|
1095
|
+
}
|
|
1096
|
+
last := stripParens(call.Arguments.Nodes[len(call.Arguments.Nodes)-1])
|
|
1097
|
+
if last == nil || !isFunctionLikeKind(last) || isArrayIterationCallback(call) {
|
|
1098
|
+
return false
|
|
1099
|
+
}
|
|
1100
|
+
params := last.Parameters()
|
|
1101
|
+
return len(params) > 0 && (parameterIdentifierName(params[0]) == "err" || parameterIdentifierName(params[0]) == "error")
|
|
1102
1102
|
}
|
|
1103
1103
|
|
|
1104
1104
|
func isArrayIterationCallback(call *shimast.CallExpression) bool {
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1105
|
+
_, method, ok := promiseCallMethod(call)
|
|
1106
|
+
if !ok {
|
|
1107
|
+
return false
|
|
1108
|
+
}
|
|
1109
|
+
switch method {
|
|
1110
|
+
case "map", "every", "forEach", "some", "find", "filter", "on", "once":
|
|
1111
|
+
return true
|
|
1112
|
+
}
|
|
1113
|
+
return false
|
|
1114
1114
|
}
|
|
1115
1115
|
|
|
1116
1116
|
func isInsideAwaitOrYield(node *shimast.Node) bool {
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1117
|
+
for cur := node.Parent; cur != nil; cur = cur.Parent {
|
|
1118
|
+
if cur.Kind == shimast.KindAwaitExpression || cur.Kind == shimast.KindYieldExpression {
|
|
1119
|
+
return true
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
return false
|
|
1123
1123
|
}
|
|
1124
1124
|
|
|
1125
1125
|
func isDirectReturnValue(node *shimast.Node) bool {
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1126
|
+
parent := node.Parent
|
|
1127
|
+
if parent == nil {
|
|
1128
|
+
return false
|
|
1129
|
+
}
|
|
1130
|
+
if parent.Kind == shimast.KindReturnStatement {
|
|
1131
|
+
return true
|
|
1132
|
+
}
|
|
1133
|
+
if parent.Kind == shimast.KindArrowFunction {
|
|
1134
|
+
arrow := parent.AsArrowFunction()
|
|
1135
|
+
return arrow != nil && arrow.Body == node
|
|
1136
|
+
}
|
|
1137
|
+
return false
|
|
1138
1138
|
}
|
|
1139
1139
|
|
|
1140
1140
|
func fileDeclaresPromise(file *shimast.Node) bool {
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1141
|
+
declared := false
|
|
1142
|
+
walkDescendants(file, func(node *shimast.Node) {
|
|
1143
|
+
if declared || node == nil {
|
|
1144
|
+
return
|
|
1145
|
+
}
|
|
1146
|
+
switch node.Kind {
|
|
1147
|
+
case shimast.KindImportClause, shimast.KindImportSpecifier, shimast.KindNamespaceImport:
|
|
1148
|
+
if node.Name() != nil && identifierText(node.Name()) == "Promise" {
|
|
1149
|
+
declared = true
|
|
1150
|
+
}
|
|
1151
|
+
case shimast.KindVariableDeclaration, shimast.KindFunctionDeclaration, shimast.KindClassDeclaration, shimast.KindInterfaceDeclaration, shimast.KindTypeAliasDeclaration:
|
|
1152
|
+
if node.Name() != nil && identifierText(node.Name()) == "Promise" {
|
|
1153
|
+
declared = true
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
})
|
|
1157
|
+
return declared
|
|
1158
1158
|
}
|
|
1159
1159
|
|
|
1160
1160
|
func init() {
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1161
|
+
Register(awaitThenable{})
|
|
1162
|
+
Register(noFloatingPromises{})
|
|
1163
|
+
Register(returnAwait{})
|
|
1164
|
+
Register(promiseAlwaysReturn{})
|
|
1165
|
+
Register(promiseAvoidNew{})
|
|
1166
|
+
Register(promiseCatchOrReturn{})
|
|
1167
|
+
Register(promiseNoCallbackInPromise{})
|
|
1168
|
+
Register(promiseNoMultipleResolved{})
|
|
1169
|
+
Register(promiseNoNative{})
|
|
1170
|
+
Register(promiseNoNesting{})
|
|
1171
|
+
Register(promiseNoNewStatics{})
|
|
1172
|
+
Register(promiseNoPromiseInCallback{})
|
|
1173
|
+
Register(promiseNoReturnInFinally{})
|
|
1174
|
+
Register(promiseNoReturnWrap{})
|
|
1175
|
+
Register(promiseParamNames{})
|
|
1176
|
+
Register(promisePreferAwaitToCallbacks{})
|
|
1177
|
+
Register(promisePreferAwaitToThen{})
|
|
1178
|
+
Register(promisePreferCatch{})
|
|
1179
|
+
Register(promiseSpecOnly{})
|
|
1180
|
+
Register(promiseValidParams{})
|
|
1181
1181
|
}
|