@ttsc/lint 0.30.3 → 0.31.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 +753 -741
- package/go.mod +7 -5
- package/internal/rulecode/rule_code_allocator_is_order_independent_and_append_only_test.go +119 -0
- package/internal/rulecode/rule_code_allocator_rejects_invalid_or_exhausted_ledgers_test.go +60 -0
- package/internal/rulecode/rulecode.go +18 -0
- package/lib/createTtscPlugin.d.ts +84 -0
- package/lib/createTtscPlugin.js +2704 -0
- package/lib/createTtscPlugin.js.map +1 -0
- package/lib/index.d.ts +1 -74
- package/lib/index.js +4 -2644
- package/lib/index.js.map +1 -1
- package/lib/internal/configEvaluatorFailure.d.ts +17 -9
- package/lib/internal/configEvaluatorFailure.js +17 -9
- package/lib/internal/configEvaluatorFailure.js.map +1 -1
- package/lib/internal/lintTrace.d.ts +18 -0
- package/lib/internal/lintTrace.js +99 -0
- package/lib/internal/lintTrace.js.map +1 -0
- package/lib/internal/normalizeContributors.d.ts +25 -0
- package/lib/internal/normalizeContributors.js +65 -0
- package/lib/internal/normalizeContributors.js.map +1 -0
- package/lib/structures/ITtscLintConfig.d.ts +25 -8
- package/lib/structures/ITtscLintPlugin.d.ts +13 -8
- package/lib/structures/ITtscLintPluginConfig.d.ts +18 -7
- package/lib/structures/ITtscLintPluginMeta.d.ts +10 -7
- package/lib/structures/TtscLintRuleSetting.d.ts +18 -13
- package/lib/structures/TtscLintSeverity.d.ts +5 -0
- package/lib/structures/format/ITtscLintFormat.d.ts +14 -8
- package/lib/structures/format/ITtscLintFormatJsDoc.d.ts +8 -1
- package/lib/structures/format/ITtscLintFormatSortImports.d.ts +14 -8
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.d.ts +133 -25
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js +3 -3
- package/lib/structures/rules/ITtscLintBoundariesRules.d.ts +10 -5
- package/lib/structures/rules/ITtscLintContributorRules.d.ts +20 -13
- package/lib/structures/rules/ITtscLintCoreRuleOptions.d.ts +212 -24
- package/lib/structures/rules/ITtscLintCoreRules.d.ts +92 -72
- package/lib/structures/rules/ITtscLintCypressRuleOptions.d.ts +8 -1
- package/lib/structures/rules/ITtscLintCypressRules.d.ts +24 -21
- package/lib/structures/rules/ITtscLintFunctionalRuleOptions.d.ts +140 -24
- package/lib/structures/rules/ITtscLintFunctionalRules.d.ts +20 -12
- package/lib/structures/rules/ITtscLintJestRules.d.ts +22 -16
- package/lib/structures/rules/ITtscLintJsdocRules.d.ts +5 -0
- package/lib/structures/rules/ITtscLintJsxA11yRules.d.ts +24 -21
- package/lib/structures/rules/ITtscLintNextjsRules.d.ts +40 -42
- package/lib/structures/rules/ITtscLintPlaywrightRules.d.ts +24 -14
- package/lib/structures/rules/ITtscLintPromiseRules.d.ts +23 -14
- package/lib/structures/rules/ITtscLintReactPerfRuleOptions.d.ts +8 -1
- package/lib/structures/rules/ITtscLintReactPerfRules.d.ts +18 -15
- package/lib/structures/rules/ITtscLintReactRuleOptions.d.ts +14 -4
- package/lib/structures/rules/ITtscLintReactRules.d.ts +33 -27
- package/lib/structures/rules/ITtscLintRegexpRules.d.ts +18 -4
- package/lib/structures/rules/ITtscLintRuleOptionsMap.d.ts +88 -15
- package/lib/structures/rules/ITtscLintRules.d.ts +13 -9
- package/lib/structures/rules/ITtscLintSecurityRules.d.ts +33 -23
- package/lib/structures/rules/ITtscLintSolidRules.d.ts +57 -47
- package/lib/structures/rules/ITtscLintStorybookRuleOptions.d.ts +10 -2
- package/lib/structures/rules/ITtscLintStorybookRules.d.ts +52 -62
- package/lib/structures/rules/ITtscLintTanstackQueryRules.d.ts +34 -30
- package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.d.ts +12 -3
- package/lib/structures/rules/ITtscLintTestingLibraryRules.d.ts +20 -15
- package/lib/structures/rules/ITtscLintTypeScriptRuleOptions.d.ts +105 -16
- package/lib/structures/rules/ITtscLintTypeScriptRules.d.ts +62 -51
- package/lib/structures/rules/ITtscLintUnicornRuleOptions.d.ts +234 -46
- package/lib/structures/rules/ITtscLintUnicornRules.d.ts +97 -44
- package/lib/structures/rules/ITtscLintVitestRules.d.ts +19 -11
- package/lib/structures/rules/TtscLintContributorOverlay.d.ts +34 -0
- package/lib/structures/rules/TtscLintContributorOverlay.js +3 -0
- package/lib/structures/rules/TtscLintContributorOverlay.js.map +1 -0
- package/lib/structures/rules/index.d.ts +1 -0
- package/lib/structures/rules/index.js +1 -0
- package/lib/structures/rules/index.js.map +1 -1
- package/linthost/all_rule_names_returns_sorted_caller_owned_enumeration_test.go +72 -0
- package/linthost/as_bool_rejects_non_boolean_value_test.go +39 -0
- package/linthost/as_int_accepts_all_integer_types_and_rejects_fractional_test.go +77 -0
- package/linthost/as_string_rejects_non_string_value_test.go +35 -0
- package/linthost/as_string_slice_rejects_non_array_and_non_string_elements_test.go +45 -0
- package/linthost/ast_helpers.go +28 -89
- package/linthost/ast_helpers_destructuring_target_rejects_reads_inside_member_and_call_test.go +61 -0
- package/linthost/ast_selector_expression_class_excludes_type_literals_test.go +32 -0
- package/linthost/ast_selector_matcher.go +5 -0
- package/linthost/ast_selector_parser.go +5 -0
- package/linthost/astutil_find_keyword_is_identifier_aware_test.go +89 -0
- package/linthost/astutil_keyword_start_locates_leading_keyword_test.go +79 -0
- package/linthost/astutil_node_text_strips_leading_trivia_test.go +48 -0
- package/linthost/astutil_token_range_strips_leading_trivia_test.go +58 -0
- package/linthost/async_query_event_and_util_promises_test.go +55 -0
- package/linthost/await_thenable_await_expression_offers_exact_suggestion_test.go +40 -0
- package/linthost/await_thenable_await_union_with_promise_allows_test.go +42 -0
- package/linthost/await_thenable_await_using_async_disposable_allows_test.go +65 -0
- package/linthost/await_thenable_await_using_async_method_under_dispose_symbol_reports_test.go +57 -0
- package/linthost/await_thenable_await_using_helpers_test.go +44 -0
- package/linthost/await_thenable_await_using_multi_declarator_reports_only_sync_resource_test.go +65 -0
- package/linthost/await_thenable_await_using_protocol_abstractions_allows_test.go +67 -0
- package/linthost/await_thenable_await_using_protocol_abstractions_reports_test.go +75 -0
- package/linthost/await_thenable_await_using_sync_disposable_reports_test.go +62 -0
- package/linthost/await_thenable_await_using_sync_only_union_reports_test.go +64 -0
- package/linthost/await_thenable_await_using_union_with_async_disposable_allows_test.go +56 -0
- package/linthost/await_thenable_awaitability_type_parameter_boundaries_test.go +51 -0
- package/linthost/await_thenable_for_await_of_async_iterable_allows_test.go +63 -0
- package/linthost/await_thenable_for_await_of_protocol_abstractions_allows_test.go +67 -0
- package/linthost/await_thenable_for_await_of_protocol_abstractions_reports_test.go +75 -0
- package/linthost/await_thenable_for_await_of_sync_iterable_reports_test.go +65 -0
- package/linthost/await_thenable_for_await_of_sync_only_union_reports_test.go +55 -0
- package/linthost/await_thenable_preserves_migrated_all_family_contexts_test.go +20 -0
- package/linthost/await_thenable_promise_aggregator_awaitable_inputs_allow_test.go +50 -0
- package/linthost/await_thenable_promise_aggregator_container_shapes_report_test.go +53 -0
- package/linthost/await_thenable_promise_aggregator_generic_constraint_reports_test.go +45 -0
- package/linthost/await_thenable_promise_aggregator_iteration_yields_allow_test.go +50 -0
- package/linthost/await_thenable_promise_aggregator_iteration_yields_report_test.go +64 -0
- package/linthost/await_thenable_promise_aggregator_literal_members_report_test.go +56 -0
- package/linthost/await_thenable_promise_aggregator_native_identity_test.go +60 -0
- package/linthost/await_thenable_promise_aggregator_native_methods_report_test.go +50 -0
- package/linthost/await_thenable_promise_aggregator_noniterable_boundaries_allow_test.go +39 -0
- package/linthost/await_thenable_protocol_members_must_be_callable_test.go +70 -0
- package/linthost/await_thenable_structural_thenable_signature_boundary_test.go +53 -0
- package/linthost/ban_ts_comment_block_comment_ignores_directive_before_last_line_test.go +32 -0
- package/linthost/ban_ts_comment_block_comment_reports_directive_on_last_line_test.go +57 -0
- package/linthost/ban_ts_comment_block_comment_splits_last_line_on_all_line_terminators_test.go +55 -0
- package/linthost/ban_ts_comment_default_allows_described_expect_error_test.go +27 -0
- package/linthost/ban_ts_comment_default_allows_ts_check_test.go +26 -0
- package/linthost/ban_ts_comment_default_allows_ts_nocheck_after_first_statement_test.go +32 -0
- package/linthost/ban_ts_comment_default_does_not_fix_ts_ignore_test.go +25 -0
- package/linthost/ban_ts_comment_default_reports_ignore_with_upgrade_message_test.go +56 -0
- package/linthost/ban_ts_comment_default_reports_indented_ignore_with_position_test.go +39 -0
- package/linthost/ban_ts_comment_default_reports_ts_nocheck_before_code_test.go +44 -0
- package/linthost/ban_ts_comment_default_reports_ts_nocheck_without_statements_test.go +34 -0
- package/linthost/ban_ts_comment_default_requires_description_for_bare_expect_error_test.go +51 -0
- package/linthost/ban_ts_comment_description_length_counts_grapheme_clusters_test.go +58 -0
- package/linthost/ban_ts_comment_description_length_follows_unicode_16_graphemes_test.go +91 -0
- package/linthost/ban_ts_comment_follows_regex_in_nested_template_test.go +39 -0
- package/linthost/ban_ts_comment_ignores_directive_text_inside_strings_and_templates_test.go +48 -0
- package/linthost/ban_ts_comment_ignores_prose_and_near_miss_comments_test.go +34 -0
- package/linthost/ban_ts_comment_option_description_format_accepts_matching_description_test.go +36 -0
- package/linthost/ban_ts_comment_option_description_format_checks_length_first_test.go +49 -0
- package/linthost/ban_ts_comment_option_description_format_reports_mismatch_test.go +46 -0
- package/linthost/ban_ts_comment_option_empty_object_directive_allows_directive_test.go +26 -0
- package/linthost/ban_ts_comment_option_expect_error_false_allows_directive_test.go +28 -0
- package/linthost/ban_ts_comment_option_expect_error_true_reports_despite_description_test.go +41 -0
- package/linthost/ban_ts_comment_option_invalid_description_format_keeps_length_gate_test.go +52 -0
- package/linthost/ban_ts_comment_option_minimum_description_length_boundary_test.go +67 -0
- package/linthost/ban_ts_comment_option_ts_check_true_reports_pragma_anywhere_test.go +50 -0
- package/linthost/ban_ts_comment_option_ts_ignore_allow_with_description_test.go +57 -0
- package/linthost/ban_ts_comment_option_ts_nocheck_allow_with_description_test.go +57 -0
- package/linthost/ban_ts_comment_option_ts_nocheck_false_allows_directive_test.go +27 -0
- package/linthost/ban_ts_comment_option_unrecognized_value_keeps_default_policy_test.go +53 -0
- package/linthost/ban_ts_comment_pragma_ignores_block_comments_test.go +33 -0
- package/linthost/ban_ts_comment_pragma_requires_two_or_three_slashes_test.go +49 -0
- package/linthost/ban_ts_comment_pragma_wins_over_error_suppression_match_test.go +29 -0
- package/linthost/ban_ts_comment_preserves_migrated_defaults_and_options_test.go +29 -0
- package/linthost/ban_ts_comment_respects_inline_disable_next_line_test.go +28 -0
- package/linthost/ban_ts_comment_suggestion_compiler_error_boundary_test.go +56 -0
- package/linthost/ban_ts_comment_suggestion_rewrites_block_comment_ignore_test.go +40 -0
- package/linthost/ban_ts_comment_suggestion_rewrites_many_slash_line_comment_test.go +41 -0
- package/linthost/base_chain_walk_crosses_generic_boundary_test.go +165 -0
- package/linthost/behavioral_witness_audit_accepts_production_prerequisite_kinds_test.go +57 -0
- package/linthost/behavioral_witness_audit_publishes_one_deterministic_route_per_rule_test.go +45 -0
- package/linthost/behavioral_witness_audit_rejects_inert_public_rule_test.go +46 -0
- package/linthost/behavioral_witness_audit_rejects_invalid_non_canonical_candidate_test.go +49 -0
- package/linthost/behavioral_witness_coverage_test.go +379 -0
- package/linthost/behavioral_witness_kind_follows_rule_checker_requirement_test.go +69 -0
- package/linthost/binding_diagnostic_sites_helpers_test.go +31 -0
- package/linthost/blank_line_between_statements_returns_false_for_out_of_range_test.go +51 -0
- package/linthost/block_has_non_statement_comment_returns_false_for_out_of_range_test.go +56 -0
- package/linthost/block_has_non_statement_comment_skips_nil_stmts_test.go +42 -0
- package/linthost/boundaries_dependencies_alias_resolution_test.go +60 -0
- package/linthost/boundaries_dependencies_bare_core_builtin_test.go +36 -0
- package/linthost/boundaries_dependencies_command_test.go +67 -0
- package/linthost/boundaries_dependencies_declaration_file_test.go +50 -0
- package/linthost/boundaries_dependencies_default_test.go +36 -0
- package/linthost/boundaries_dependencies_from_to_test.go +66 -0
- package/linthost/boundaries_dependencies_import_kind_test.go +46 -0
- package/linthost/boundaries_dependencies_import_type_kinds_test.go +56 -0
- package/linthost/boundaries_dependencies_legacy_to_direction_test.go +43 -0
- package/linthost/boundaries_dependencies_local_gates_test.go +43 -0
- package/linthost/boundaries_dependencies_messages_test.go +58 -0
- package/linthost/boundaries_dependencies_options_test.go +66 -0
- package/linthost/boundaries_dependencies_origins_test.go +38 -0
- package/linthost/boundaries_dependencies_path_separators_test.go +36 -0
- package/linthost/boundaries_dependencies_policy_order_test.go +41 -0
- package/linthost/boundaries_dependencies_syntax_test.go +86 -0
- package/linthost/boundaries_dependencies_test.go +38 -0
- package/linthost/boundaries_dependencies_visibility_selectors_test.go +52 -0
- package/linthost/boundaries_element_types_deny_only_names_nothing_test.go +36 -0
- package/linthost/boundaries_element_types_ignores_dynamic_syntax_test.go +44 -0
- package/linthost/boundaries_element_types_names_the_allowed_set_test.go +40 -0
- package/linthost/boundaries_element_types_rejects_disallowed_import_test.go +43 -0
- package/linthost/boundaries_entry_point_rejects_non_entry_import_test.go +43 -0
- package/linthost/boundaries_external_deny_only_names_nothing_test.go +25 -0
- package/linthost/boundaries_external_names_the_allowed_set_test.go +30 -0
- package/linthost/boundaries_external_rejects_disallowed_package_test.go +34 -0
- package/linthost/boundaries_helpers_test.go +162 -0
- package/linthost/boundaries_no_private_rejects_cross_element_private_import_test.go +39 -0
- package/linthost/boundaries_no_unknown_rejects_unknown_import_target_test.go +43 -0
- package/linthost/check_observations.go +236 -0
- package/linthost/check_observations_retains_failed_program_and_raw_inputs_test.go +266 -0
- package/linthost/check_serve.go +23 -3
- package/linthost/check_serve_reuses_program_and_matches_cold_cycles_test.go +168 -0
- package/linthost/check_tag_names_publishes_canonical_hints_test.go +62 -0
- package/linthost/check_tag_names_test.go +30 -0
- package/linthost/check_values_test.go +31 -0
- package/linthost/command_build_emits_project_output_test.go +55 -0
- package/linthost/command_build_rejects_conflicting_emit_flags_test.go +32 -0
- package/linthost/command_check_applies_a_forwarded_null_reset_test.go +62 -0
- package/linthost/command_check_applies_forwarded_tsgo_flag_test.go +61 -0
- package/linthost/command_check_corpus_clean_project_exits_zero_test.go +41 -0
- package/linthost/command_check_corpus_ignores_future_optional_flags_test.go +34 -0
- package/linthost/command_check_corpus_reports_unknown_rule_names_test.go +25 -0
- package/linthost/command_check_honors_no_restricted_syntax_options_test.go +59 -0
- package/linthost/command_check_no_param_reassign_honors_props_config_test.go +46 -0
- package/linthost/command_check_no_restricted_imports_uses_real_config_options_test.go +53 -0
- package/linthost/command_check_preserves_compiler_argument_cwd_test.go +78 -0
- package/linthost/command_check_preserves_severity_exit_contract_test.go +54 -0
- package/linthost/command_check_rejects_invalid_no_param_reassign_options_before_linting_test.go +85 -0
- package/linthost/command_check_rejects_invalid_no_restricted_imports_options_before_linting_test.go +52 -0
- package/linthost/command_check_rejects_invalid_no_restricted_syntax_selector_test.go +41 -0
- package/linthost/command_check_relates_files_to_the_project_directory_test.go +40 -0
- package/linthost/command_check_reports_imported_sibling_workspace_source_test.go +45 -0
- package/linthost/command_check_reports_lint_diagnostic_test.go +44 -0
- package/linthost/command_check_reports_the_malformed_brace_it_used_to_bless_test.go +31 -0
- package/linthost/command_check_scopes_extends_rule_options_per_file_test.go +70 -0
- package/linthost/command_check_uses_parser_context_for_comment_consumers_test.go +61 -0
- package/linthost/command_check_warns_unknown_rules_test.go +41 -0
- package/linthost/command_fix_applies_both_lint_and_format_rule_edits_test.go +51 -0
- package/linthost/command_fix_applies_native_autofixes_test.go +48 -0
- package/linthost/command_fix_leaves_suggestion_only_rules_unchanged_test.go +46 -0
- package/linthost/command_fix_owns_its_source_reached_through_a_link_test.go +63 -0
- package/linthost/command_fix_rejects_emit_flag_test.go +39 -0
- package/linthost/command_fix_reports_but_never_rewrites_imported_sibling_source_test.go +65 -0
- package/linthost/command_fix_skips_default_formatting_that_format_applies_test.go +87 -0
- package/linthost/command_fix_unicorn_prevent_abbreviations_keeps_cross_file_merges_diagnostic_only_test.go +44 -0
- package/linthost/command_fix_unicorn_prevent_abbreviations_reparses_and_is_idempotent_test.go +37 -0
- package/linthost/command_fix_unicorn_switch_case_break_position_converges_and_is_idempotent_test.go +58 -0
- package/linthost/command_fix_unicorn_template_indent_converges_and_is_idempotent_test.go +43 -0
- package/linthost/command_format_applies_format_block_reflow_test.go +50 -0
- package/linthost/command_format_applies_format_rule_edits_test.go +54 -0
- package/linthost/command_format_arg_hugging_test.go +329 -0
- package/linthost/command_format_array_of_arrays_break_test.go +62 -0
- package/linthost/command_format_blank_line_in_list_test.go +69 -0
- package/linthost/command_format_brace_ownership_negative_twins_test.go +94 -0
- package/linthost/command_format_cedes_chained_arrow_body_test.go +50 -0
- package/linthost/command_format_cedes_closing_brace_under_wrapped_head_test.go +54 -0
- package/linthost/command_format_class_heritage_break_test.go +108 -0
- package/linthost/command_format_converges_on_leading_semi_guard_in_callback_test.go +69 -0
- package/linthost/command_format_decorated_declaration_indent_is_idempotent_test.go +57 -0
- package/linthost/command_format_default_import_single_specifier_break_test.go +26 -0
- package/linthost/command_format_display_width_test.go +33 -0
- package/linthost/command_format_expands_expression_nested_block_test.go +86 -0
- package/linthost/command_format_expression_nested_block_honors_crlf_test.go +39 -0
- package/linthost/command_format_fixture_corpus_test.go +179 -0
- package/linthost/command_format_honors_entry_ignores_alongside_rules_test.go +79 -0
- package/linthost/command_format_import_multi_specifier_from_overflow_break_test.go +27 -0
- package/linthost/command_format_indent_idempotency_helper_test.go +57 -0
- package/linthost/command_format_keeps_commented_statement_body_whole_test.go +23 -0
- package/linthost/command_format_keeps_empty_expression_nested_block_test.go +29 -0
- package/linthost/command_format_lays_out_a_statement_body_test.go +90 -0
- package/linthost/command_format_leaves_a_braceless_control_flow_body_alone_test.go +30 -0
- package/linthost/command_format_leaves_imported_sibling_source_untouched_test.go +68 -0
- package/linthost/command_format_leaves_prettier_shaped_mapped_types_untouched_test.go +39 -0
- package/linthost/command_format_leaves_prettier_shaped_type_members_untouched_test.go +41 -0
- package/linthost/command_format_leaves_token_spacing_untouched_test.go +66 -0
- package/linthost/command_format_multiple_callbacks_test.go +150 -0
- package/linthost/command_format_nested_ternary_indent_test.go +67 -0
- package/linthost/command_format_nested_ternary_parens_test.go +74 -0
- package/linthost/command_format_numeric_array_fill_test.go +94 -0
- package/linthost/command_format_preserves_braceless_for_body_indent_test.go +28 -0
- package/linthost/command_format_preserves_braceless_if_try_body_indent_test.go +30 -0
- package/linthost/command_format_preserves_class_typeparam_heritage_inline_test.go +27 -0
- package/linthost/command_format_preserves_comments_in_reflow_test.go +66 -0
- package/linthost/command_format_preserves_crlf_across_reflow_rules_test.go +73 -0
- package/linthost/command_format_preserves_generic_arg_multiline_type_literal_indent_test.go +30 -0
- package/linthost/command_format_preserves_generic_arg_type_literal_indent_test.go +30 -0
- package/linthost/command_format_preserves_interface_qualified_heritage_own_line_test.go +28 -0
- package/linthost/command_format_preserves_intersection_generic_type_literal_indent_test.go +36 -0
- package/linthost/command_format_preserves_multi_type_heritage_empty_body_test.go +28 -0
- package/linthost/command_format_preserves_multiline_type_param_heritage_test.go +30 -0
- package/linthost/command_format_preserves_nested_variable_type_literal_indent_test.go +27 -0
- package/linthost/command_format_preserves_param_type_literal_indent_test.go +62 -0
- package/linthost/command_format_preserves_union_member_type_literal_indent_test.go +28 -0
- package/linthost/command_format_print_width_abstains_inside_binary_expression_test.go +84 -0
- package/linthost/command_format_print_width_cascades_with_semi_and_quotes_test.go +62 -0
- package/linthost/command_format_print_width_converges_on_unbraced_control_flow_test.go +176 -0
- package/linthost/command_format_rejects_emit_flag_test.go +39 -0
- package/linthost/command_format_respects_resolved_entry_applicability_test.go +219 -0
- package/linthost/command_format_restores_class_member_indent_from_flat_test.go +61 -0
- package/linthost/command_format_restores_closing_braces_from_flat_test.go +64 -0
- package/linthost/command_format_restores_decorated_member_indent_from_flat_test.go +61 -0
- package/linthost/command_format_restores_decorated_namespace_class_indent_from_flat_test.go +62 -0
- package/linthost/command_format_restores_decorated_nested_class_indent_from_flat_test.go +64 -0
- package/linthost/command_format_restores_decorated_nested_function_indent_from_flat_test.go +60 -0
- package/linthost/command_format_restores_decorated_nested_interface_indent_from_flat_test.go +59 -0
- package/linthost/command_format_restores_nested_class_indent_from_flat_test.go +60 -0
- package/linthost/command_format_restores_stranded_brace_from_one_line_block_test.go +140 -0
- package/linthost/command_format_restores_switch_indent_from_flat_test.go +63 -0
- package/linthost/command_format_return_typed_arrow_hug_test.go +74 -0
- package/linthost/command_format_round2_coverage_test.go +57 -0
- package/linthost/command_format_round2_hug_fixes_test.go +70 -0
- package/linthost/command_format_round3_force_break_test.go +49 -0
- package/linthost/command_format_settles_a_member_terminator_on_a_padded_line_test.go +34 -0
- package/linthost/command_format_single_specifier_abstain_does_not_block_multi_break_test.go +56 -0
- package/linthost/command_format_single_specifier_stays_inline_test.go +60 -0
- package/linthost/command_format_split_call_collapses_flat_once_isolated_test.go +54 -0
- package/linthost/command_format_spread_comment_test.go +36 -0
- package/linthost/command_format_stranded_brace_honors_crlf_test.go +51 -0
- package/linthost/command_format_structural_rules_are_idempotent_on_their_own_output_test.go +51 -0
- package/linthost/command_format_structural_rules_converge_on_headline_input_test.go +56 -0
- package/linthost/command_format_structural_rules_converge_on_nested_block_test.go +56 -0
- package/linthost/command_format_switch_case_block_indent_test.go +80 -0
- package/linthost/command_format_terminates_a_split_interface_member_test.go +34 -0
- package/linthost/command_format_test_call_hug_test.go +92 -0
- package/linthost/command_format_wrapped_function_body_indent_test.go +43 -0
- package/linthost/command_lint_corpus_semantics_helpers_test.go +29 -0
- package/linthost/command_prints_version_test.go +38 -0
- package/linthost/command_rejects_conflicting_emit_flags_test.go +33 -0
- package/linthost/command_rejects_unknown_test.go +32 -0
- package/linthost/command_requires_argument_test.go +32 -0
- package/linthost/command_transform_normalizes_dot_segments_in_file_path_test.go +49 -0
- package/linthost/command_transform_outputs_requested_file_test.go +43 -0
- package/linthost/command_transform_requires_file_test.go +32 -0
- package/linthost/comment_scan.go +3 -2
- package/linthost/comment_scan_handles_malformed_parser_recovery_test.go +59 -0
- package/linthost/comment_scan_uses_parser_lexical_ranges_across_source_modes_test.go +109 -0
- package/linthost/compile.go +177 -38
- package/linthost/compile_user_pattern_caches_option_regex_test.go +70 -0
- package/linthost/config.go +954 -269
- package/linthost/config_cache_does_not_memoize_failed_evaluation_test.go +63 -0
- package/linthost/config_cache_portable_dependency_policies_test.go +471 -0
- package/linthost/config_cache_preserves_pattern_precedence_test.go +96 -0
- package/linthost/config_cache_reuses_evaluation_until_content_changes_test.go +81 -0
- package/linthost/config_fixture_helpers_test.go +70 -0
- package/linthost/config_format.go +5 -5
- package/linthost/config_glob.go +517 -0
- package/linthost/config_glob_bounds_matching_work_test.go +115 -0
- package/linthost/config_glob_preserves_expansion_semantics_test.go +128 -0
- package/linthost/config_glob_preserves_stored_case_recovery_test.go +64 -0
- package/linthost/config_json.go +85 -0
- package/linthost/config_loader_sources_escape_every_literal_percent_test.go +81 -0
- package/linthost/config_store_option_fold_honors_both_entry_orders_test.go +70 -0
- package/linthost/config_store_resolves_options_with_entry_scope_test.go +95 -0
- package/linthost/config_store_severity_only_override_inherits_matching_options_test.go +53 -0
- package/linthost/config_store_validates_every_scoped_option_variant_test.go +55 -0
- package/linthost/consistent_return_accepts_functions_that_return_on_every_path_through_switch_and_try_test.go +43 -0
- package/linthost/context_report_range_suggestion_separates_opt_in_edits_test.go +76 -0
- package/linthost/contrib_adapter.go +3 -1
- package/linthost/contrib_adapter_to_internal_text_edits_returns_nil_for_empty_input_test.go +34 -0
- package/linthost/contrib_adapter_to_internal_text_edits_round_trips_three_edits_test.go +40 -0
- package/linthost/contributor_ast_only_marker_skips_standalone_checker_test.go +52 -0
- package/linthost/contributor_bootstrap_is_single_owner_for_reusable_main_test.go +425 -0
- package/linthost/contributor_cannot_mutate_later_invocation_options_test.go +55 -0
- package/linthost/contributor_diagnostic_ranges_are_bounded_test.go +139 -0
- package/linthost/contributor_generic_accepts_options_method_keeps_legacy_payload_test.go +81 -0
- package/linthost/contributor_metadata_panic_is_rejected_test.go +84 -0
- package/linthost/contributor_optionless_marker_rejects_payload_test.go +63 -0
- package/linthost/contributor_panics_preserve_other_rules_in_process_test.go +111 -0
- package/linthost/contributor_range_fix_bounds_diagnostic_independently_from_edit_test.go +52 -0
- package/linthost/contributor_report_related_reaches_finding_test.go +101 -0
- package/linthost/contributor_rule_decodes_options_through_public_context_test.go +75 -0
- package/linthost/contributor_rule_opt_out_skips_declaration_files_test.go +56 -0
- package/linthost/contributor_rule_receives_and_reports_configured_severity_test.go +65 -0
- package/linthost/contributor_rules_visit_declaration_files_by_default_test.go +50 -0
- package/linthost/contributor_tagged_rule_marks_findings_test.go +78 -0
- package/linthost/contributor_type_aware_marker_keeps_checker_test.go +50 -0
- package/linthost/contributor_without_tag_marker_leaves_findings_untagged_test.go +61 -0
- package/linthost/cypress_assertion_before_screenshot_allows_immediately_prior_assertion_test.go +33 -0
- package/linthost/cypress_assertion_before_screenshot_allows_same_chain_assertion_test.go +31 -0
- package/linthost/cypress_assertion_before_screenshot_reports_unchecked_screenshot_test.go +34 -0
- package/linthost/cypress_assertion_before_screenshot_reports_unrelated_prior_assertion_test.go +36 -0
- package/linthost/cypress_finding_helpers_test.go +14 -0
- package/linthost/cypress_no_and_reports_chain_starting_and_test.go +35 -0
- package/linthost/cypress_no_assigning_return_values_reports_cy_assignment_test.go +35 -0
- package/linthost/cypress_no_async_before_reports_async_before_each_test.go +37 -0
- package/linthost/cypress_no_async_tests_reports_async_it_test.go +37 -0
- package/linthost/cypress_no_chained_get_reports_second_get_test.go +34 -0
- package/linthost/cypress_no_debug_reports_debug_command_test.go +34 -0
- package/linthost/cypress_no_force_reports_force_true_option_test.go +34 -0
- package/linthost/cypress_no_pause_reports_pause_command_test.go +34 -0
- package/linthost/cypress_no_unnecessary_waiting_reports_numeric_wait_test.go +35 -0
- package/linthost/cypress_no_xpath_reports_xpath_command_test.go +34 -0
- package/linthost/cypress_require_data_selectors_reports_class_selector_test.go +36 -0
- package/linthost/cypress_unsafe_to_chain_command_reports_action_middle_test.go +35 -0
- package/linthost/declaration_file_allowlist_names_are_registered_rules_test.go +50 -0
- package/linthost/default_case_accepts_block_comment_marker_test.go +28 -0
- package/linthost/default_case_accepts_case_insensitive_marker_test.go +28 -0
- package/linthost/default_case_accepts_empty_switch_test.go +24 -0
- package/linthost/default_case_accepts_existing_default_clause_test.go +29 -0
- package/linthost/default_case_accepts_no_default_marker_test.go +28 -0
- package/linthost/default_case_custom_pattern_replaces_default_marker_test.go +30 -0
- package/linthost/default_case_helpers_test.go +58 -0
- package/linthost/default_case_honors_custom_comment_pattern_test.go +28 -0
- package/linthost/default_case_invalid_comment_pattern_falls_back_to_default_test.go +28 -0
- package/linthost/default_case_rejects_marker_with_trailing_text_test.go +28 -0
- package/linthost/default_case_rejects_unrelated_trailing_comment_test.go +28 -0
- package/linthost/default_case_reports_switch_without_default_test.go +27 -0
- package/linthost/default_case_requires_marker_to_be_last_comment_test.go +30 -0
- package/linthost/diagnostic_codes_distinguish_former_collision_across_cli_and_lsp_test.go +97 -0
- package/linthost/dispatch.go +29 -9
- package/linthost/dispatch_array_literal_breaks_when_overflows_test.go +38 -0
- package/linthost/dispatch_array_literal_falls_back_when_element_nil_test.go +53 -0
- package/linthost/dispatch_array_literal_falls_back_when_elements_nil_test.go +48 -0
- package/linthost/dispatch_array_literal_flat_when_fits_test.go +34 -0
- package/linthost/dispatch_array_literal_returns_empty_for_nil_node_test.go +31 -0
- package/linthost/dispatch_arrow_function_block_body_reindents_consistently_test.go +41 -0
- package/linthost/dispatch_arrow_function_returns_covered_for_nil_node_test.go +38 -0
- package/linthost/dispatch_arrow_function_returns_verbatim_for_nil_body_test.go +46 -0
- package/linthost/dispatch_block_collapses_empty_body_to_braces_test.go +40 -0
- package/linthost/dispatch_block_keeps_covered_for_single_line_statements_test.go +42 -0
- package/linthost/dispatch_block_preserves_blank_line_between_statements_test.go +41 -0
- package/linthost/dispatch_block_reports_uncovered_for_comment_only_body_test.go +37 -0
- package/linthost/dispatch_block_reports_uncovered_for_inter_statement_comment_test.go +37 -0
- package/linthost/dispatch_block_returns_covered_for_nil_node_test.go +34 -0
- package/linthost/dispatch_block_returns_verbatim_for_nil_statement_test.go +47 -0
- package/linthost/dispatch_block_returns_verbatim_for_nil_statements_test.go +44 -0
- package/linthost/dispatch_call_breaks_expression_body_arrow_argument_when_overflows_test.go +44 -0
- package/linthost/dispatch_call_breaks_hugged_object_when_flat_form_overflows_test.go +42 -0
- package/linthost/dispatch_call_explodes_when_hugged_callback_header_overflows_test.go +45 -0
- package/linthost/dispatch_call_explodes_when_hugged_object_header_overflows_test.go +43 -0
- package/linthost/dispatch_call_expression_breaks_arguments_when_overflows_test.go +40 -0
- package/linthost/dispatch_call_expression_flat_when_fits_test.go +33 -0
- package/linthost/dispatch_call_hugs_last_callback_argument_test.go +41 -0
- package/linthost/dispatch_call_keeps_hugged_object_flat_when_it_fits_test.go +40 -0
- package/linthost/dispatch_expression_statement_returns_covered_for_nil_node_test.go +36 -0
- package/linthost/dispatch_expression_statement_returns_verbatim_for_dirty_tail_test.go +44 -0
- package/linthost/dispatch_expression_statement_returns_verbatim_for_nil_expression_test.go +44 -0
- package/linthost/dispatch_function_expression_block_body_reindents_test.go +43 -0
- package/linthost/dispatch_function_expression_returns_covered_for_nil_node_test.go +36 -0
- package/linthost/dispatch_function_expression_returns_verbatim_for_nil_body_test.go +44 -0
- package/linthost/dispatch_function_like_returns_verbatim_for_out_of_range_body_test.go +50 -0
- package/linthost/dispatch_function_like_taints_covered_for_multiline_signature_test.go +38 -0
- package/linthost/dispatch_import_declaration_falls_back_for_default_import_test.go +32 -0
- package/linthost/dispatch_import_declaration_falls_back_for_import_attributes_test.go +33 -0
- package/linthost/dispatch_import_declaration_falls_back_for_namespace_import_test.go +37 -0
- package/linthost/dispatch_import_declaration_falls_back_for_side_effect_import_test.go +36 -0
- package/linthost/dispatch_import_declaration_omits_semicolon_when_absent_test.go +37 -0
- package/linthost/dispatch_import_declaration_preserves_type_only_keyword_test.go +34 -0
- package/linthost/dispatch_import_declaration_returns_empty_for_nil_node_test.go +30 -0
- package/linthost/dispatch_import_declaration_threads_clauses_test.go +35 -0
- package/linthost/dispatch_named_exports_breaks_when_overflows_test.go +38 -0
- package/linthost/dispatch_named_exports_falls_back_when_elements_nil_test.go +49 -0
- package/linthost/dispatch_named_exports_falls_back_when_specifier_nil_test.go +51 -0
- package/linthost/dispatch_named_exports_flat_when_fits_test.go +33 -0
- package/linthost/dispatch_named_exports_returns_empty_for_nil_node_test.go +31 -0
- package/linthost/dispatch_named_imports_breaks_when_overflows_test.go +37 -0
- package/linthost/dispatch_named_imports_falls_back_when_elements_nil_test.go +50 -0
- package/linthost/dispatch_named_imports_falls_back_when_specifier_nil_test.go +54 -0
- package/linthost/dispatch_named_imports_flat_when_fits_test.go +34 -0
- package/linthost/dispatch_named_imports_returns_empty_for_nil_node_test.go +30 -0
- package/linthost/dispatch_nested_callback_reflows_at_every_depth_test.go +52 -0
- package/linthost/dispatch_new_expression_breaks_arguments_when_overflows_test.go +39 -0
- package/linthost/dispatch_new_expression_flat_when_fits_test.go +36 -0
- package/linthost/dispatch_object_literal_breaks_when_overflows_test.go +40 -0
- package/linthost/dispatch_object_literal_falls_back_when_properties_nil_test.go +49 -0
- package/linthost/dispatch_object_literal_falls_back_when_property_nil_test.go +52 -0
- package/linthost/dispatch_object_literal_flat_when_fits_test.go +33 -0
- package/linthost/dispatch_object_literal_returns_empty_for_nil_node_test.go +31 -0
- package/linthost/dispatch_parenthesized_expression_reflows_inner_test.go +42 -0
- package/linthost/dispatch_parenthesized_expression_returns_covered_for_nil_node_test.go +35 -0
- package/linthost/dispatch_parenthesized_expression_returns_verbatim_for_nil_inner_test.go +44 -0
- package/linthost/dispatch_reports_uncovered_for_multiline_verbatim_subtree_test.go +42 -0
- package/linthost/dispatch_return_statement_reflows_returned_expression_test.go +45 -0
- package/linthost/dispatch_return_statement_returns_covered_for_nil_node_test.go +36 -0
- package/linthost/dispatch_return_statement_returns_verbatim_for_bare_return_test.go +41 -0
- package/linthost/dispatch_return_statement_returns_verbatim_for_dirty_tail_test.go +43 -0
- package/linthost/dispatch_verbatim_fallback_preserves_unknown_kinds_test.go +41 -0
- package/linthost/display_width.go +29 -5
- package/linthost/display_width_after_last_newline_measures_tail_test.go +33 -0
- package/linthost/display_width_from_column_expands_tabs_to_stops_test.go +49 -0
- package/linthost/display_width_matches_prettier_get_string_width_test.go +124 -0
- package/linthost/display_width_oracle_preconditions_test.go +32 -0
- package/linthost/doc_join_returns_nil_for_empty_parts_test.go +33 -0
- package/linthost/dot_notation_declines_fix_when_comment_in_bracket_span_test.go +40 -0
- package/linthost/dot_notation_fix_bracket_to_dot_for_identifier_key_test.go +27 -0
- package/linthost/dot_notation_fix_keeps_bracket_for_reserved_word_test.go +28 -0
- package/linthost/dot_notation_fix_spaces_decimal_integer_receiver_test.go +76 -0
- package/linthost/dot_notation_offers_reserved_word_collapse_as_suggestion_test.go +36 -0
- package/linthost/dot_notation_offers_withheld_bracket_collapse_as_suggestion_test.go +37 -0
- package/linthost/dot_notation_skips_invalid_identifier_key_test.go +27 -0
- package/linthost/editor_format_overrides_accepts_utf8_bom_test.go +155 -0
- package/linthost/editor_format_overrides_combined_sections_follow_source_order_test.go +58 -0
- package/linthost/editor_format_overrides_drive_idempotent_output_test.go +69 -0
- package/linthost/editor_format_overrides_duplicate_language_section_uses_last_value_test.go +55 -0
- package/linthost/editor_format_overrides_equivalent_exact_sections_use_last_scope_test.go +52 -0
- package/linthost/editor_format_overrides_language_section_wins_test.go +37 -0
- package/linthost/editor_format_overrides_normalize_full_language_selectors_test.go +44 -0
- package/linthost/editor_format_overrides_reads_vscode_settings_test.go +45 -0
- package/linthost/editor_format_overrides_reject_malformed_language_selectors_test.go +36 -0
- package/linthost/editor_format_overrides_single_language_precedence_is_deterministic_test.go +51 -0
- package/linthost/editor_format_overrides_supported_language_ids_test.go +60 -0
- package/linthost/empty_tags_test.go +27 -0
- package/linthost/engine.go +523 -91
- package/linthost/engine_accepts_null_tuple_slot_as_absent_options_test.go +37 -0
- package/linthost/engine_accepts_payload_for_option_rule_test.go +36 -0
- package/linthost/engine_accepts_severity_only_optionless_rule_test.go +28 -0
- package/linthost/engine_align_uses_current_column_test.go +27 -0
- package/linthost/engine_block_disable_after_code_does_not_suppress_earlier_same_line_test.go +47 -0
- package/linthost/engine_conditional_group_empty_renders_nothing_test.go +24 -0
- package/linthost/engine_conditional_group_falls_back_to_last_option_test.go +30 -0
- package/linthost/engine_conditional_group_picks_first_fitting_option_test.go +31 -0
- package/linthost/engine_crlf_terminator_emits_carriage_returns_test.go +24 -0
- package/linthost/engine_dedupes_duplicate_kinds_in_visits_test.go +64 -0
- package/linthost/engine_detects_files_without_enabled_rules_test.go +40 -0
- package/linthost/engine_directive_accepts_typescript_namespace_prefix_test.go +48 -0
- package/linthost/engine_directive_after_template_expression_test.go +37 -0
- package/linthost/engine_directive_records_unknown_rule_in_unknown_channel_test.go +65 -0
- package/linthost/engine_directive_rejects_legacy_typescript_eslint_prefix_test.go +50 -0
- package/linthost/engine_directive_without_rules_disables_all_rules_on_target_line_test.go +57 -0
- package/linthost/engine_disable_line_multiline_block_comment_targets_end_line_test.go +50 -0
- package/linthost/engine_dispatches_only_to_interested_rules_test.go +81 -0
- package/linthost/engine_end_of_line_defaults_to_lf_when_empty_test.go +23 -0
- package/linthost/engine_fits_first_line_counts_flat_group_lines_test.go +25 -0
- package/linthost/engine_fits_first_line_stops_at_first_break_test.go +85 -0
- package/linthost/engine_fits_measures_conditional_group_as_first_option_test.go +25 -0
- package/linthost/engine_fits_rejects_forced_break_group_test.go +22 -0
- package/linthost/engine_fits_returns_false_when_remaining_negative_test.go +21 -0
- package/linthost/engine_fits_treats_indent_align_as_transparent_in_flat_test.go +34 -0
- package/linthost/engine_flatten_resolves_breaks_to_flat_form_test.go +57 -0
- package/linthost/engine_group_break_flag_forces_broken_layout_test.go +29 -0
- package/linthost/engine_group_breaks_when_overflows_width_test.go +30 -0
- package/linthost/engine_group_collapses_when_fits_width_test.go +28 -0
- package/linthost/engine_hardline_forces_break_regardless_of_width_test.go +23 -0
- package/linthost/engine_ifbreak_picks_broken_branch_when_group_breaks_test.go +32 -0
- package/linthost/engine_ifbreak_picks_flat_branch_when_group_fits_test.go +28 -0
- package/linthost/engine_ignores_directive_text_inside_strings_test.go +45 -0
- package/linthost/engine_ignores_jsx_text_inline_disable_markers_test.go +54 -0
- package/linthost/engine_indent_compounds_inside_group_test.go +20 -0
- package/linthost/engine_line_suffix_attaches_to_next_break_test.go +33 -0
- package/linthost/engine_line_suffix_drain_preserves_embedded_newline_test.go +23 -0
- package/linthost/engine_line_suffix_drains_inline_when_no_break_follows_test.go +28 -0
- package/linthost/engine_line_suffix_flush_preserves_embedded_newline_test.go +28 -0
- package/linthost/engine_literalline_emits_newline_at_column_zero_test.go +24 -0
- package/linthost/engine_preserves_migrated_disable_directive_population_test.go +46 -0
- package/linthost/engine_print_width_defaults_when_zero_test.go +39 -0
- package/linthost/engine_quarantines_panicking_rule_per_file_test.go +110 -0
- package/linthost/engine_records_unknown_rules_test.go +42 -0
- package/linthost/engine_recovers_from_rule_panic_test.go +68 -0
- package/linthost/engine_rejects_legacy_typescript_eslint_prefix_test.go +39 -0
- package/linthost/engine_rejects_optionless_payload_while_rule_is_off_test.go +37 -0
- package/linthost/engine_rejects_payload_shapes_for_optionless_rule_test.go +46 -0
- package/linthost/engine_requires_type_checker_for_contributor_rule_test.go +43 -0
- package/linthost/engine_requires_type_checker_for_prefer_const_test.go +33 -0
- package/linthost/engine_requires_type_checker_for_type_aware_rule_test.go +35 -0
- package/linthost/engine_respects_block_disable_enable_test.go +48 -0
- package/linthost/engine_respects_eslint_disable_line_test.go +45 -0
- package/linthost/engine_respects_eslint_disable_next_line_test.go +48 -0
- package/linthost/engine_respects_lint_disable_next_line_alias_test.go +46 -0
- package/linthost/engine_run_parallel_matches_serial_finding_set_test.go +86 -0
- package/linthost/engine_runs_format_rules_on_declaration_files_test.go +37 -0
- package/linthost/engine_runs_opt_in_rules_on_declaration_files_test.go +39 -0
- package/linthost/engine_skips_off_rules_test.go +41 -0
- package/linthost/engine_skips_type_checker_for_ast_only_rule_test.go +35 -0
- package/linthost/engine_skips_value_rules_on_declaration_files_test.go +40 -0
- package/linthost/engine_softline_emits_newline_when_group_breaks_test.go +23 -0
- package/linthost/engine_softline_renders_empty_when_flat_test.go +22 -0
- package/linthost/engine_starting_indent_offsets_break_decision_test.go +29 -0
- package/linthost/engine_tab_width_defaults_when_zero_test.go +24 -0
- package/linthost/engine_text_renders_verbatim_test.go +29 -0
- package/linthost/engine_text_with_embedded_newline_forces_break_test.go +24 -0
- package/linthost/engine_use_tabs_emits_remainder_spaces_test.go +27 -0
- package/linthost/engine_use_tabs_emits_tab_characters_test.go +24 -0
- package/linthost/eqeqeq_offers_unsafe_operator_rewrite_as_suggestion_test.go +45 -0
- package/linthost/expect_matchers_without_argument_do_not_panic_test.go +50 -0
- package/linthost/file_path_from_uri_preserves_literal_percent_escapes_test.go +36 -0
- package/linthost/file_url_matches_node_shape_test.go +64 -0
- package/linthost/files_selector_scopes_rules_away_from_an_imported_sibling_test.go +70 -0
- package/linthost/filter_format_findings_keeps_only_format_rule_findings_test.go +56 -0
- package/linthost/filter_known_flags_preserves_known_values_and_skips_unknowns_test.go +49 -0
- package/linthost/filter_known_flags_resolves_names_case_insensitively_test.go +43 -0
- package/linthost/filter_lint_findings_drops_format_rule_findings_test.go +43 -0
- package/linthost/find_lint_config_file_discovers_nearest_ancestor_test.go +37 -0
- package/linthost/find_lint_config_file_discovers_plain_lint_config_test.go +37 -0
- package/linthost/find_lint_config_file_falls_back_to_cwd_for_out_of_tree_tsconfig_test.go +43 -0
- package/linthost/find_lint_config_file_prefers_nearest_directory_test.go +38 -0
- package/linthost/find_lint_config_file_rejects_same_directory_conflicts_test.go +38 -0
- package/linthost/find_lint_config_file_uses_tsconfig_directory_when_outside_cwd_test.go +45 -0
- package/linthost/find_lint_entry_accepts_sorted_check_plugin_payload_test.go +53 -0
- package/linthost/fix.go +37 -11
- package/linthost/fix_eqeqeq_replaces_same_type_literal_operator_test.go +26 -0
- package/linthost/fix_eqeqeq_replaces_typeof_operator_test.go +26 -0
- package/linthost/fix_eqeqeq_requires_both_operands_to_share_a_primitive_kind_test.go +29 -0
- package/linthost/fix_eqeqeq_skips_unsafe_identifier_comparison_test.go +25 -0
- package/linthost/fix_interleaved_import_type_and_bracket_spacing_stays_valid_test.go +113 -0
- package/linthost/fix_no_extra_bind_removes_safe_member_and_call_syntax_test.go +45 -0
- package/linthost/fix_no_extra_bind_skips_effectful_or_commented_removals_test.go +55 -0
- package/linthost/fix_no_extra_non_null_assertion_drops_trailing_bang_test.go +39 -0
- package/linthost/fix_no_import_type_side_effects_hoists_type_keyword_test.go +29 -0
- package/linthost/fix_no_import_type_side_effects_preserves_leading_comment_test.go +30 -0
- package/linthost/fix_no_import_type_side_effects_skips_comment_import_keyword_test.go +31 -0
- package/linthost/fix_no_import_type_side_effects_skips_mixed_import_test.go +28 -0
- package/linthost/fix_no_unnecessary_type_constraint_disambiguates_cts_generic_arrow_test.go +20 -0
- package/linthost/fix_no_unnecessary_type_constraint_disambiguates_mts_generic_arrow_test.go +20 -0
- package/linthost/fix_no_unnecessary_type_constraint_disambiguates_tsx_generic_arrow_test.go +20 -0
- package/linthost/fix_no_unnecessary_type_constraint_drops_extends_clause_test.go +28 -0
- package/linthost/fix_no_unnecessary_type_constraint_keeps_default_unambiguous_test.go +20 -0
- package/linthost/fix_no_unnecessary_type_constraint_keeps_multiple_parameters_unambiguous_test.go +20 -0
- package/linthost/fix_no_unnecessary_type_constraint_keeps_non_arrow_declarations_minimal_test.go +28 -0
- package/linthost/fix_no_unnecessary_type_constraint_keeps_ts_generic_arrow_minimal_test.go +20 -0
- package/linthost/fix_no_unnecessary_type_constraint_preserves_comma_comments_test.go +22 -0
- package/linthost/fix_no_unnecessary_type_constraint_preserves_existing_trailing_comma_test.go +20 -0
- package/linthost/fix_no_useless_escape_drops_backslash_test.go +28 -0
- package/linthost/fix_no_useless_escape_drops_nondigit_neighbors_of_octal_exemption_test.go +31 -0
- package/linthost/fix_no_useless_escape_skips_backslash_digit_escapes_test.go +48 -0
- package/linthost/fix_no_useless_escape_skips_tagged_template_test.go +29 -0
- package/linthost/fix_no_useless_escape_skips_template_substitution_escape_test.go +45 -0
- package/linthost/fix_no_useless_rename_drops_rename_tail_test.go +39 -0
- package/linthost/fix_no_useless_rename_skips_string_literal_alias_test.go +34 -0
- package/linthost/fix_no_var_fixes_despite_label_before_test.go +30 -0
- package/linthost/fix_no_var_fixes_despite_member_name_before_test.go +29 -0
- package/linthost/fix_no_var_fixes_despite_object_key_before_test.go +30 -0
- package/linthost/fix_no_var_fixes_despite_type_reference_before_test.go +32 -0
- package/linthost/fix_no_var_keeps_bindings_observable_by_direct_eval_test.go +41 -0
- package/linthost/fix_no_var_preserves_script_global_object_bindings_test.go +30 -0
- package/linthost/fix_no_var_replaces_closure_reference_without_loop_test.go +30 -0
- package/linthost/fix_no_var_replaces_for_header_binding_test.go +31 -0
- package/linthost/fix_no_var_replaces_for_in_header_binding_test.go +31 -0
- package/linthost/fix_no_var_replaces_for_of_header_binding_test.go +31 -0
- package/linthost/fix_no_var_replaces_loop_local_without_closure_test.go +30 -0
- package/linthost/fix_no_var_replaces_namespace_block_binding_test.go +28 -0
- package/linthost/fix_no_var_replaces_reassigned_binding_test.go +30 -0
- package/linthost/fix_no_var_replaces_reference_in_nested_block_test.go +30 -0
- package/linthost/fix_no_var_replaces_reference_inside_with_body_test.go +30 -0
- package/linthost/fix_no_var_replaces_same_block_references_test.go +30 -0
- package/linthost/fix_no_var_replaces_same_case_clause_references_test.go +30 -0
- package/linthost/fix_no_var_replaces_unique_binding_test.go +30 -0
- package/linthost/fix_no_var_replaces_var_keyword_test.go +28 -0
- package/linthost/fix_no_var_skips_block_scope_escape_test.go +37 -0
- package/linthost/fix_no_var_skips_catch_binding_redeclaration_test.go +36 -0
- package/linthost/fix_no_var_skips_class_field_capture_in_loop_test.go +38 -0
- package/linthost/fix_no_var_skips_cross_case_reference_test.go +36 -0
- package/linthost/fix_no_var_skips_cross_scope_same_name_over_decline_test.go +36 -0
- package/linthost/fix_no_var_skips_deferred_self_reference_in_init_test.go +45 -0
- package/linthost/fix_no_var_skips_direct_self_reference_in_init_test.go +37 -0
- package/linthost/fix_no_var_skips_for_header_closure_capture_test.go +38 -0
- package/linthost/fix_no_var_skips_for_header_multi_declarator_test.go +32 -0
- package/linthost/fix_no_var_skips_for_header_redeclaration_test.go +36 -0
- package/linthost/fix_no_var_skips_for_header_use_after_loop_test.go +37 -0
- package/linthost/fix_no_var_skips_for_in_annex_b_initializer_test.go +33 -0
- package/linthost/fix_no_var_skips_for_in_header_expression_self_reference_test.go +37 -0
- package/linthost/fix_no_var_skips_for_of_destructuring_header_test.go +32 -0
- package/linthost/fix_no_var_skips_for_of_header_closure_capture_test.go +38 -0
- package/linthost/fix_no_var_skips_for_of_header_expression_self_reference_test.go +36 -0
- package/linthost/fix_no_var_skips_function_declaration_redeclaration_test.go +39 -0
- package/linthost/fix_no_var_skips_function_scope_escape_test.go +28 -0
- package/linthost/fix_no_var_skips_iife_self_reference_in_init_test.go +39 -0
- package/linthost/fix_no_var_skips_let_as_binding_name_test.go +32 -0
- package/linthost/fix_no_var_skips_loop_closure_capture_test.go +37 -0
- package/linthost/fix_no_var_skips_mixed_destructure_redeclaration_test.go +38 -0
- package/linthost/fix_no_var_skips_mixed_destructure_use_before_test.go +36 -0
- package/linthost/fix_no_var_skips_parameter_redeclaration_test.go +28 -0
- package/linthost/fix_no_var_skips_redeclaration_test.go +37 -0
- package/linthost/fix_no_var_skips_shorthand_value_before_test.go +37 -0
- package/linthost/fix_no_var_skips_single_statement_position_test.go +33 -0
- package/linthost/fix_no_var_skips_typeof_self_reference_in_init_test.go +38 -0
- package/linthost/fix_no_var_skips_use_before_declaration_test.go +36 -0
- package/linthost/fix_no_var_skips_use_before_for_header_test.go +36 -0
- package/linthost/fix_no_var_skips_while_loop_closure_capture_test.go +35 -0
- package/linthost/fix_no_var_skips_with_statement_body_test.go +35 -0
- package/linthost/fix_no_wrapper_object_types_replaces_typename_test.go +28 -0
- package/linthost/fix_no_wrapper_object_types_replaces_unshadowed_const_test.go +30 -0
- package/linthost/fix_no_wrapper_object_types_skips_function_shadow_test.go +27 -0
- package/linthost/fix_no_wrapper_object_types_skips_import_equals_shadow_test.go +26 -0
- package/linthost/fix_no_wrapper_object_types_skips_imported_name_test.go +26 -0
- package/linthost/fix_no_wrapper_object_types_skips_user_shadowed_name_test.go +27 -0
- package/linthost/fix_object_shorthand_drops_value_tail_test.go +28 -0
- package/linthost/fix_object_shorthand_preserves_the_prototype_setter_test.go +28 -0
- package/linthost/fix_prefer_as_const_preserves_comment_before_literal_type_test.go +27 -0
- package/linthost/fix_prefer_as_const_replaces_angle_bracket_type_with_const_test.go +27 -0
- package/linthost/fix_prefer_as_const_replaces_literal_type_with_const_test.go +27 -0
- package/linthost/fix_prefer_as_const_replaces_parenthesized_literal_assertion_test.go +28 -0
- package/linthost/fix_prefer_as_const_replaces_parenthesized_literal_type_test.go +28 -0
- package/linthost/fix_prefer_as_const_skips_null_literal_assertion_test.go +26 -0
- package/linthost/fix_prefer_as_const_skips_property_annotation_rewrite_test.go +27 -0
- package/linthost/fix_prefer_as_const_skips_template_literal_assertion_test.go +28 -0
- package/linthost/fix_prefer_as_const_skips_variable_annotation_rewrite_test.go +27 -0
- package/linthost/fix_prefer_const_counts_nested_write_in_shorthand_default_test.go +25 -0
- package/linthost/fix_prefer_const_keeps_nonlocal_rewrites_diagnostic_only_test.go +54 -0
- package/linthost/fix_prefer_const_preserves_assertion_wrapped_assignment_targets_test.go +68 -0
- package/linthost/fix_prefer_const_replaces_let_with_fresh_for_of_binding_test.go +29 -0
- package/linthost/fix_prefer_const_replaces_single_let_keyword_test.go +26 -0
- package/linthost/fix_prefer_const_replaces_wholly_stable_destructuring_keyword_test.go +26 -0
- package/linthost/fix_prefer_const_skips_destructuring_assignment_targets_test.go +42 -0
- package/linthost/fix_prefer_const_skips_for_in_reassignment_test.go +28 -0
- package/linthost/fix_prefer_const_skips_for_of_reassignment_test.go +29 -0
- package/linthost/fix_prefer_const_skips_multi_declaration_list_test.go +32 -0
- package/linthost/fix_prefer_namespace_keyword_replaces_module_keyword_test.go +29 -0
- package/linthost/fix_regexp_no_useless_flag_deletes_the_flag_it_named_test.go +74 -0
- package/linthost/fix_regexp_no_useless_quantifier_drops_exactly_one_repeat_test.go +57 -0
- package/linthost/fix_regexp_no_useless_two_nums_quantifier_collapses_equal_bounds_test.go +50 -0
- package/linthost/fix_regexp_no_zero_quantifier_stays_diagnostic_only_test.go +39 -0
- package/linthost/fix_regexp_prefer_d_replaces_spelled_out_digit_class_test.go +49 -0
- package/linthost/fix_regexp_prefer_plus_quantifier_replaces_open_ended_one_test.go +45 -0
- package/linthost/fix_regexp_prefer_question_quantifier_replaces_zero_to_one_test.go +43 -0
- package/linthost/fix_regexp_prefer_star_quantifier_replaces_open_ended_zero_test.go +43 -0
- package/linthost/fix_regexp_prefer_w_replaces_spelled_out_word_class_test.go +46 -0
- package/linthost/fix_regexp_require_unicode_regexp_offers_u_and_v_suggestions_test.go +71 -0
- package/linthost/fix_regexp_require_unicode_sets_regexp_offers_the_v_flag_test.go +76 -0
- package/linthost/fix_regexp_sort_flags_rewrites_flag_run_in_canonical_order_test.go +48 -0
- package/linthost/fix_regexp_withholds_a_rewrite_the_regex_parser_rejects_test.go +62 -0
- package/linthost/fix_security_detect_new_buffer_offers_three_successors_test.go +93 -0
- package/linthost/fix_security_detect_pseudo_random_bytes_proves_automatic_rename_test.go +95 -0
- package/linthost/fix_select_text_edit_groups_collapses_duplicate_edit_within_finding_test.go +42 -0
- package/linthost/fix_select_text_edit_groups_drops_partially_overlapped_finding_whole_test.go +43 -0
- package/linthost/fix_select_text_edit_groups_drops_self_overlapping_finding_test.go +32 -0
- package/linthost/fix_select_text_edit_groups_keeps_disjoint_multi_edit_finding_whole_test.go +41 -0
- package/linthost/fix_select_text_edits_drops_coincident_zero_width_insert_test.go +57 -0
- package/linthost/fix_select_text_edits_drops_duplicate_edits_test.go +38 -0
- package/linthost/fix_select_text_edits_drops_overlapping_ranges_test.go +32 -0
- package/linthost/fix_solid_imports_rewrites_sole_specifier_module_test.go +65 -0
- package/linthost/fix_solid_no_react_specific_props_renames_react_props_test.go +66 -0
- package/linthost/fix_storybook_no_renderer_packages_offers_framework_packages_test.go +95 -0
- package/linthost/fix_tsx_grammar_keeps_jsx_while_rewriting_var_and_let_test.go +36 -0
- package/linthost/flags_gen.go +2 -2
- package/linthost/for_direction_honors_a_negated_compound_step_test.go +37 -0
- package/linthost/format.go +14 -4
- package/linthost/format_arrow_parens_abstains_on_comment_near_trailing_comma_test.go +68 -0
- package/linthost/format_arrow_parens_abstains_on_param_comment_test.go +44 -0
- package/linthost/format_arrow_parens_avoid_keeps_return_type_parens_test.go +24 -0
- package/linthost/format_arrow_parens_avoid_keeps_type_parameter_parens_test.go +23 -0
- package/linthost/format_arrow_parens_idempotent_on_wrapped_test.go +24 -0
- package/linthost/format_arrow_parens_keeps_destructured_param_under_avoid_test.go +24 -0
- package/linthost/format_arrow_parens_keeps_ineligible_trailing_comma_params_test.go +66 -0
- package/linthost/format_arrow_parens_keeps_trailing_comma_param_under_always_test.go +48 -0
- package/linthost/format_arrow_parens_keeps_typed_param_under_avoid_test.go +24 -0
- package/linthost/format_arrow_parens_strips_async_single_param_test.go +26 -0
- package/linthost/format_arrow_parens_strips_single_param_under_avoid_test.go +24 -0
- package/linthost/format_arrow_parens_strips_trailing_comma_param_under_avoid_test.go +51 -0
- package/linthost/format_arrow_parens_strips_wrapped_param_before_list_comma_test.go +32 -0
- package/linthost/format_arrow_parens_wraps_bare_single_param_test.go +25 -0
- package/linthost/format_block_absent_keeps_format_rules_off_test.go +42 -0
- package/linthost/format_block_default_severity_off_keeps_format_rules_out_of_check_test.go +48 -0
- package/linthost/format_block_drops_format_rule_in_rules_map_test.go +45 -0
- package/linthost/format_block_expands_nil_raw_to_empty_map_test.go +32 -0
- package/linthost/format_block_jsdoc_false_skips_rule_test.go +37 -0
- package/linthost/format_block_propagates_jsdoc_sort_tags_option_test.go +59 -0
- package/linthost/format_block_propagates_prettier_options_to_rule_test.go +159 -0
- package/linthost/format_block_propagates_sort_imports_options_test.go +70 -0
- package/linthost/format_block_rejects_empty_sort_imports_order_test.go +37 -0
- package/linthost/format_block_rejects_invalid_jsdoc_options_test.go +68 -0
- package/linthost/format_block_rejects_invalid_severity_test.go +33 -0
- package/linthost/format_block_rejects_invalid_trailing_comma_value_test.go +36 -0
- package/linthost/format_block_rejects_non_array_sort_imports_order_test.go +32 -0
- package/linthost/format_block_rejects_non_bool_or_object_jsdoc_test.go +36 -0
- package/linthost/format_block_rejects_non_bool_or_object_sort_imports_test.go +30 -0
- package/linthost/format_block_rejects_non_bool_semi_test.go +32 -0
- package/linthost/format_block_rejects_non_bool_single_quote_test.go +31 -0
- package/linthost/format_block_rejects_non_bool_sort_imports_options_test.go +45 -0
- package/linthost/format_block_rejects_non_bool_use_tabs_test.go +31 -0
- package/linthost/format_block_rejects_non_int_print_width_test.go +31 -0
- package/linthost/format_block_rejects_non_int_tab_width_test.go +32 -0
- package/linthost/format_block_rejects_non_string_end_of_line_test.go +48 -0
- package/linthost/format_block_rejects_non_string_trailing_comma_test.go +32 -0
- package/linthost/format_block_rejects_unknown_key_test.go +39 -0
- package/linthost/format_block_rejects_unknown_sort_imports_key_test.go +36 -0
- package/linthost/format_block_severity_warning_enables_check_diagnostics_test.go +48 -0
- package/linthost/format_block_sort_imports_false_keeps_rule_off_test.go +27 -0
- package/linthost/format_block_sort_imports_true_enables_defaults_test.go +37 -0
- package/linthost/format_block_targets_option_accepting_rules_test.go +90 -0
- package/linthost/format_block_threads_end_of_line_into_sort_imports_test.go +55 -0
- package/linthost/format_block_wins_over_vscode_settings_test.go +36 -0
- package/linthost/format_brace_continuation_corrects_a_pushed_keyword_at_the_wrong_column_test.go +28 -0
- package/linthost/format_brace_continuation_honors_crlf_end_of_line_test.go +29 -0
- package/linthost/format_brace_continuation_indents_a_pushed_keyword_to_its_statement_test.go +27 -0
- package/linthost/format_brace_continuation_is_idempotent_in_both_directions_test.go +32 -0
- package/linthost/format_brace_continuation_leaves_an_if_without_an_else_alone_test.go +23 -0
- package/linthost/format_brace_continuation_normalizes_a_zero_width_gap_test.go +27 -0
- package/linthost/format_brace_continuation_pulls_catch_and_finally_onto_their_braces_test.go +28 -0
- package/linthost/format_brace_continuation_pulls_do_while_onto_the_closing_brace_test.go +27 -0
- package/linthost/format_brace_continuation_pulls_else_onto_the_closing_brace_test.go +27 -0
- package/linthost/format_brace_continuation_pulls_finally_onto_a_try_without_a_catch_test.go +28 -0
- package/linthost/format_brace_continuation_pushes_a_do_while_off_a_statement_body_test.go +28 -0
- package/linthost/format_brace_continuation_pushes_else_off_a_statement_consequent_test.go +28 -0
- package/linthost/format_brace_continuation_pushes_past_a_brace_terminated_non_block_test.go +28 -0
- package/linthost/format_brace_continuation_pushes_past_a_label_prefix_test.go +48 -0
- package/linthost/format_brace_continuation_settles_a_shared_line_through_the_cascade_test.go +44 -0
- package/linthost/format_brace_continuation_skips_a_commented_gap_test.go +28 -0
- package/linthost/format_brace_continuation_waits_for_a_statement_to_own_its_line_test.go +27 -0
- package/linthost/format_bracket_spacing_idempotent_on_padded_test.go +23 -0
- package/linthost/format_bracket_spacing_leaves_a_prettier_shaped_type_literal_alone_test.go +27 -0
- package/linthost/format_bracket_spacing_leaves_empty_object_test.go +74 -0
- package/linthost/format_bracket_spacing_pads_an_unspaced_type_literal_test.go +29 -0
- package/linthost/format_bracket_spacing_pads_destructure_test.go +24 -0
- package/linthost/format_bracket_spacing_pads_import_attributes_test.go +28 -0
- package/linthost/format_bracket_spacing_pads_mapped_type_test.go +27 -0
- package/linthost/format_bracket_spacing_pads_named_imports_test.go +24 -0
- package/linthost/format_bracket_spacing_pads_object_literal_test.go +26 -0
- package/linthost/format_bracket_spacing_strips_object_literal_under_false_test.go +26 -0
- package/linthost/format_clause_join_charges_the_else_width_budget_at_its_limit_test.go +37 -0
- package/linthost/format_clause_join_charges_the_shift_to_the_header_lines_indent_test.go +45 -0
- package/linthost/format_clause_join_emits_no_shift_when_the_column_is_unchanged_test.go +50 -0
- package/linthost/format_clause_join_hoists_across_a_multiline_template_without_moving_it_test.go +30 -0
- package/linthost/format_clause_join_idempotent_on_joined_body_test.go +27 -0
- package/linthost/format_clause_join_joins_do_body_test.go +27 -0
- package/linthost/format_clause_join_joins_else_body_test.go +27 -0
- package/linthost/format_clause_join_joins_else_if_chain_across_lines_test.go +44 -0
- package/linthost/format_clause_join_joins_for_and_while_bodies_test.go +32 -0
- package/linthost/format_clause_join_joins_labeled_block_body_test.go +31 -0
- package/linthost/format_clause_join_joins_single_if_body_test.go +28 -0
- package/linthost/format_clause_join_joins_with_body_test.go +27 -0
- package/linthost/format_clause_join_keeps_a_blank_line_inside_a_hoisted_body_test.go +45 -0
- package/linthost/format_clause_join_keeps_overlong_body_broken_test.go +31 -0
- package/linthost/format_clause_join_leaves_a_block_comment_interior_untouched_test.go +45 -0
- package/linthost/format_clause_join_leaves_a_string_continuation_untouched_test.go +45 -0
- package/linthost/format_clause_join_leaves_a_template_literal_type_untouched_test.go +49 -0
- package/linthost/format_clause_join_reindents_a_hoisted_body_inside_a_function_test.go +43 -0
- package/linthost/format_clause_join_reindents_a_hoisted_else_if_chain_test.go +45 -0
- package/linthost/format_clause_join_reindents_a_hoisted_labeled_block_test.go +27 -0
- package/linthost/format_clause_join_reindents_an_indentable_block_comment_test.go +50 -0
- package/linthost/format_clause_join_settles_a_deep_staircase_within_the_cascade_budget_test.go +44 -0
- package/linthost/format_clause_join_shifts_a_tab_indented_body_with_tabs_test.go +44 -0
- package/linthost/format_clause_join_skips_braced_body_test.go +31 -0
- package/linthost/format_clause_join_skips_braced_else_and_do_bodies_test.go +38 -0
- package/linthost/format_clause_join_skips_commented_else_gap_test.go +29 -0
- package/linthost/format_clause_join_skips_empty_else_and_do_bodies_test.go +33 -0
- package/linthost/format_clause_join_skips_empty_statement_body_test.go +36 -0
- package/linthost/format_command_resolver_keeps_configured_options_inside_matching_entry_test.go +64 -0
- package/linthost/format_command_resolver_skips_upgrade_for_entry_ignored_file_test.go +60 -0
- package/linthost/format_command_resolver_skips_upgrade_for_file_outside_entry_files_test.go +61 -0
- package/linthost/format_command_resolver_variants_replace_bare_options_with_reachable_defaults_test.go +34 -0
- package/linthost/format_declaration_header_abstains_on_comment_in_header_test.go +25 -0
- package/linthost/format_declaration_header_abstains_on_type_params_with_multi_clause_test.go +27 -0
- package/linthost/format_declaration_header_breaks_empty_body_at_width_boundary_test.go +32 -0
- package/linthost/format_declaration_header_breaks_generic_heritage_type_args_test.go +28 -0
- package/linthost/format_declaration_header_breaks_multi_type_interface_test.go +29 -0
- package/linthost/format_declaration_header_breaks_multiple_clauses_test.go +25 -0
- package/linthost/format_declaration_header_breaks_single_type_clause_in_multi_clause_test.go +73 -0
- package/linthost/format_declaration_header_breaks_type_param_default_after_equals_test.go +29 -0
- package/linthost/format_declaration_header_collapses_fitting_header_test.go +29 -0
- package/linthost/format_declaration_header_drops_brace_for_class_body_test.go +28 -0
- package/linthost/format_declaration_header_explodes_and_drops_brace_for_class_body_test.go +27 -0
- package/linthost/format_declaration_header_explodes_type_parameters_test.go +26 -0
- package/linthost/format_declaration_header_generic_heritage_honors_crlf_end_of_line_test.go +32 -0
- package/linthost/format_declaration_header_glues_brace_for_empty_body_test.go +27 -0
- package/linthost/format_declaration_header_idempotent_on_broken_clauses_test.go +24 -0
- package/linthost/format_declaration_header_idempotent_on_broken_heritage_type_args_test.go +25 -0
- package/linthost/format_declaration_header_idempotent_on_exploded_class_body_test.go +25 -0
- package/linthost/format_declaration_header_keeps_multi_type_inline_after_break_test.go +30 -0
- package/linthost/format_declaration_header_keeps_single_generic_heritage_arg_inline_test.go +25 -0
- package/linthost/format_declaration_header_keeps_single_heritage_type_inline_test.go +26 -0
- package/linthost/format_declaration_header_multi_clause_honors_crlf_end_of_line_test.go +30 -0
- package/linthost/format_declaration_header_multi_type_honors_crlf_end_of_line_test.go +30 -0
- package/linthost/format_declaration_header_type_param_explode_honors_crlf_end_of_line_test.go +32 -0
- package/linthost/format_defaults_apply_without_format_config_test.go +46 -0
- package/linthost/format_indent_case_block_body_matches_case_depth_test.go +30 -0
- package/linthost/format_indent_cedes_body_under_multiline_arrow_head_test.go +39 -0
- package/linthost/format_indent_cedes_callback_argument_body_test.go +31 -0
- package/linthost/format_indent_defers_shared_line_to_statement_split_test.go +32 -0
- package/linthost/format_indent_honors_custom_tab_width_test.go +28 -0
- package/linthost/format_indent_honors_use_tabs_option_test.go +28 -0
- package/linthost/format_indent_idempotent_on_correct_class_body_test.go +27 -0
- package/linthost/format_indent_idempotent_on_correct_nested_block_test.go +26 -0
- package/linthost/format_indent_idempotent_on_decorated_member_test.go +29 -0
- package/linthost/format_indent_normalizes_class_method_body_depth_test.go +29 -0
- package/linthost/format_indent_normalizes_decorated_member_declaration_line_test.go +31 -0
- package/linthost/format_indent_normalizes_multiple_decorator_lines_test.go +30 -0
- package/linthost/format_indent_normalizes_over_indented_block_statement_test.go +27 -0
- package/linthost/format_indent_normalizes_plain_member_header_test.go +29 -0
- package/linthost/format_indent_normalizes_same_line_decorated_member_test.go +49 -0
- package/linthost/format_indent_normalizes_switch_case_body_depth_test.go +29 -0
- package/linthost/format_indent_still_fixes_single_line_head_arrow_body_test.go +27 -0
- package/linthost/format_indent_strips_leading_indent_from_top_level_statement_test.go +27 -0
- package/linthost/format_jsdoc_honors_custom_tag_synonyms_option_test.go +26 -0
- package/linthost/format_jsdoc_preserves_example_block_body_test.go +63 -0
- package/linthost/format_jsdoc_rejects_malformed_tag_synonym_value_test.go +60 -0
- package/linthost/format_jsdoc_rewrites_arg_synonyms_to_param_test.go +25 -0
- package/linthost/format_jsdoc_rewrites_return_to_returns_test.go +24 -0
- package/linthost/format_jsdoc_skips_canonical_tags_test.go +32 -0
- package/linthost/format_jsdoc_skips_inline_at_text_test.go +34 -0
- package/linthost/format_jsdoc_skips_jsdoc_like_strings_in_source_test.go +41 -0
- package/linthost/format_orphan_semi_inert_under_semi_true_test.go +24 -0
- package/linthost/format_orphan_semi_merges_guard_under_no_semi_test.go +35 -0
- package/linthost/format_orphan_semi_skips_comment_between_guard_and_statement_test.go +28 -0
- package/linthost/format_orphan_semi_skips_non_hazard_successor_test.go +29 -0
- package/linthost/format_parameter_properties_breaks_multi_param_constructor_test.go +30 -0
- package/linthost/format_parameter_properties_breaks_override_only_constructor_test.go +31 -0
- package/linthost/format_parameter_properties_honors_crlf_end_of_line_test.go +29 -0
- package/linthost/format_parameter_properties_idempotent_on_broken_list_test.go +28 -0
- package/linthost/format_parameter_properties_ignores_decorated_plain_params_test.go +31 -0
- package/linthost/format_parameter_properties_ignores_plain_params_test.go +27 -0
- package/linthost/format_parameter_properties_keeps_single_param_inline_test.go +30 -0
- package/linthost/format_prettier_conformance_e2e_test.go +367 -0
- package/linthost/format_print_width_abstains_inside_jsx_expression_test.go +50 -0
- package/linthost/format_print_width_abstains_inside_template_substitution_test.go +31 -0
- package/linthost/format_print_width_abstains_when_callback_body_holds_uncovered_statement_test.go +37 -0
- package/linthost/format_print_width_abstains_when_inter_member_comment_present_test.go +32 -0
- package/linthost/format_print_width_abstains_when_trailing_block_comment_before_close_bracket_test.go +35 -0
- package/linthost/format_print_width_breaks_array_rest_assignment_target_without_comma_test.go +31 -0
- package/linthost/format_print_width_breaks_call_when_trailing_semicolon_overflows_test.go +26 -0
- package/linthost/format_print_width_breaks_default_plus_named_import_shape_test.go +29 -0
- package/linthost/format_print_width_breaks_long_call_arguments_test.go +31 -0
- package/linthost/format_print_width_breaks_long_named_exports_test.go +30 -0
- package/linthost/format_print_width_breaks_long_named_imports_test.go +30 -0
- package/linthost/format_print_width_breaks_long_new_expression_arguments_test.go +31 -0
- package/linthost/format_print_width_breaks_long_object_literal_test.go +27 -0
- package/linthost/format_print_width_breaks_overflowing_react_hook_deps_array_test.go +29 -0
- package/linthost/format_print_width_check_abstains_when_ctx_is_nil_test.go +24 -0
- package/linthost/format_print_width_check_abstains_when_node_is_nil_test.go +48 -0
- package/linthost/format_print_width_check_abstains_when_node_range_exceeds_context_source_test.go +71 -0
- package/linthost/format_print_width_declines_last_arg_hug_after_arrow_lead_test.go +29 -0
- package/linthost/format_print_width_declines_last_arg_hug_after_callback_test.go +28 -0
- package/linthost/format_print_width_default_width_is_80_columns_test.go +31 -0
- package/linthost/format_print_width_explodes_call_when_hugged_header_overflows_test.go +26 -0
- package/linthost/format_print_width_hangs_broken_ternary_arm_under_arm_column_test.go +40 -0
- package/linthost/format_print_width_has_non_child_comments_returns_false_when_node_is_nil_test.go +46 -0
- package/linthost/format_print_width_has_reflow_ancestor_returns_false_when_node_is_nil_test.go +40 -0
- package/linthost/format_print_width_honors_crlf_end_of_line_test.go +30 -0
- package/linthost/format_print_width_honors_custom_tab_width_test.go +27 -0
- package/linthost/format_print_width_honors_tab_leading_source_test.go +27 -0
- package/linthost/format_print_width_honors_use_tabs_option_test.go +25 -0
- package/linthost/format_print_width_hugs_arrow_with_object_body_test.go +32 -0
- package/linthost/format_print_width_hugs_first_callback_argument_test.go +31 -0
- package/linthost/format_print_width_hugs_first_callback_with_array_arg_test.go +27 -0
- package/linthost/format_print_width_hugs_object_argument_despite_long_trailing_suffix_test.go +32 -0
- package/linthost/format_print_width_idempotent_on_already_reflowed_input_test.go +26 -0
- package/linthost/format_print_width_idempotent_on_first_hugged_call_test.go +25 -0
- package/linthost/format_print_width_idempotent_on_hugged_callback_call_test.go +25 -0
- package/linthost/format_print_width_idempotent_on_nested_ternary_staircase_test.go +25 -0
- package/linthost/format_print_width_indents_nested_alternate_ternary_test.go +30 -0
- package/linthost/format_print_width_indents_nested_consequent_ternary_test.go +30 -0
- package/linthost/format_print_width_indents_relative_to_line_leading_indent_test.go +42 -0
- package/linthost/format_print_width_inserts_after_non_rest_object_assignment_target_test.go +30 -0
- package/linthost/format_print_width_inserts_after_object_spread_in_value_literal_test.go +30 -0
- package/linthost/format_print_width_keeps_call_with_trailing_line_comment_inline_test.go +24 -0
- package/linthost/format_print_width_keeps_empty_array_literal_flat_test.go +25 -0
- package/linthost/format_print_width_keeps_empty_object_literal_flat_test.go +28 -0
- package/linthost/format_print_width_keeps_nested_object_that_fits_test.go +24 -0
- package/linthost/format_print_width_keeps_object_rest_assignment_target_without_comma_test.go +29 -0
- package/linthost/format_print_width_keeps_react_hook_hugged_past_open_line_test.go +26 -0
- package/linthost/format_print_width_keeps_short_call_with_callback_hugged_test.go +32 -0
- package/linthost/format_print_width_keeps_short_ternary_flat_test.go +27 -0
- package/linthost/format_print_width_leading_column_returns_zero_when_pos_is_nonpositive_test.go +51 -0
- package/linthost/format_print_width_line_leading_indent_uses_two_when_tab_width_nonpositive_test.go +47 -0
- package/linthost/format_print_width_max_line_width_uses_two_when_tab_width_nonpositive_test.go +47 -0
- package/linthost/format_print_width_preserves_blank_line_in_reflowed_callback_body_test.go +29 -0
- package/linthost/format_print_width_preserves_call_type_arguments_test.go +32 -0
- package/linthost/format_print_width_preserves_leading_jsdoc_above_reflowed_node_test.go +44 -0
- package/linthost/format_print_width_preserves_multiline_object_test.go +30 -0
- package/linthost/format_print_width_preserves_optional_call_token_test.go +32 -0
- package/linthost/format_print_width_preserves_terminator_decision_on_imports_test.go +42 -0
- package/linthost/format_print_width_reflows_call_with_nested_object_argument_test.go +33 -0
- package/linthost/format_print_width_reflows_wide_array_with_slash_strings_test.go +34 -0
- package/linthost/format_print_width_reindents_callback_body_inside_indented_block_test.go +33 -0
- package/linthost/format_print_width_skips_namespace_import_shape_test.go +28 -0
- package/linthost/format_print_width_skips_nested_target_when_ancestor_covers_it_test.go +58 -0
- package/linthost/format_print_width_skips_short_object_literal_test.go +29 -0
- package/linthost/format_print_width_slice_contains_newline_clamps_out_of_range_bounds_test.go +57 -0
- package/linthost/format_print_width_ternary_arm_indent_bonus_test.go +44 -0
- package/linthost/format_print_width_trailing_line_width_excludes_trailing_line_comment_test.go +38 -0
- package/linthost/format_print_width_trailing_line_width_handles_guards_and_tabs_test.go +51 -0
- package/linthost/format_quote_props_consistent_preserves_cooked_identifier_keys_test.go +37 -0
- package/linthost/format_quote_props_consistent_quotes_mixed_object_test.go +28 -0
- package/linthost/format_quote_props_consistent_unquotes_all_identifier_keys_test.go +24 -0
- package/linthost/format_quote_props_consistent_unquotes_proto_with_identifier_keys_test.go +21 -0
- package/linthost/format_quote_props_keeps_non_identifier_key_test.go +24 -0
- package/linthost/format_quote_props_keeps_numeric_key_test.go +20 -0
- package/linthost/format_quote_props_preserve_is_noop_test.go +23 -0
- package/linthost/format_quote_props_unquotes_class_method_test.go +30 -0
- package/linthost/format_quote_props_unquotes_identifier_keys_test.go +25 -0
- package/linthost/format_quote_props_unquotes_interface_member_test.go +28 -0
- package/linthost/format_quote_props_unquotes_proto_key_without_changing_setter_semantics_test.go +21 -0
- package/linthost/format_quote_props_unquotes_reserved_word_key_test.go +25 -0
- package/linthost/format_quote_props_unquotes_type_literal_member_test.go +28 -0
- package/linthost/format_quotes_converts_double_to_single_preserving_apostrophe_escape_test.go +23 -0
- package/linthost/format_quotes_converts_single_to_double_test.go +22 -0
- package/linthost/format_quotes_escapes_double_quote_when_converting_test.go +22 -0
- package/linthost/format_quotes_honors_prefer_single_option_test.go +27 -0
- package/linthost/format_quotes_keeps_double_on_escape_tie_test.go +29 -0
- package/linthost/format_quotes_keeps_double_with_redundant_single_escape_test.go +31 -0
- package/linthost/format_quotes_keeps_single_with_redundant_double_escape_test.go +31 -0
- package/linthost/format_quotes_preserves_strings_with_unescaped_double_quotes_test.go +34 -0
- package/linthost/format_quotes_skips_double_quoted_literals_test.go +24 -0
- package/linthost/format_quotes_skips_jsx_attribute_strings_test.go +44 -0
- package/linthost/format_quotes_skips_template_literals_test.go +38 -0
- package/linthost/format_quotes_switches_double_to_single_to_minimize_escapes_test.go +31 -0
- package/linthost/format_quotes_switches_single_to_double_to_minimize_escapes_test.go +22 -0
- package/linthost/format_quotes_unescapes_apostrophe_when_converting_test.go +30 -0
- package/linthost/format_reflow_preserves_import_default_gap_comment_test.go +29 -0
- package/linthost/format_reflow_preserves_import_type_gap_comment_test.go +29 -0
- package/linthost/format_reflow_preserves_nested_call_arg_comment_test.go +24 -0
- package/linthost/format_reflow_preserves_new_constructee_gap_comment_test.go +21 -0
- package/linthost/format_reflow_preserves_return_comment_test.go +24 -0
- package/linthost/format_reflow_preserves_ternary_paren_comment_test.go +26 -0
- package/linthost/format_semi_fires_for_every_asi_statement_kind_test.go +103 -0
- package/linthost/format_semi_honors_prefer_never_option_test.go +28 -0
- package/linthost/format_semi_idempotent_on_stripped_interface_test.go +28 -0
- package/linthost/format_semi_idempotent_on_terminated_members_test.go +38 -0
- package/linthost/format_semi_inserts_after_missing_terminator_test.go +28 -0
- package/linthost/format_semi_inserts_member_terminator_before_trailing_comment_test.go +29 -0
- package/linthost/format_semi_keeps_a_flat_mapped_type_bare_test.go +31 -0
- package/linthost/format_semi_keeps_a_flat_object_types_last_member_bare_test.go +36 -0
- package/linthost/format_semi_keeps_braced_and_object_literal_accessors_bare_test.go +40 -0
- package/linthost/format_semi_keeps_class_field_semi_before_computed_member_test.go +32 -0
- package/linthost/format_semi_keeps_object_literal_accessor_separators_untouched_test.go +49 -0
- package/linthost/format_semi_keeps_one_line_interface_body_bare_test.go +29 -0
- package/linthost/format_semi_keeps_same_line_type_member_separator_test.go +31 -0
- package/linthost/format_semi_keeps_type_member_semi_before_call_signature_test.go +32 -0
- package/linthost/format_semi_normalizes_a_comma_member_separator_test.go +39 -0
- package/linthost/format_semi_prefer_never_block_comment_is_not_hazard_test.go +49 -0
- package/linthost/format_semi_prefer_never_keeps_a_flat_object_types_separator_test.go +38 -0
- package/linthost/format_semi_prefer_never_keeps_do_while_separator_test.go +32 -0
- package/linthost/format_semi_prefer_never_keeps_same_line_else_separator_test.go +31 -0
- package/linthost/format_semi_prefer_never_keeps_same_line_statement_separator_test.go +29 -0
- package/linthost/format_semi_prefer_never_keeps_semi_before_asi_hazard_test.go +58 -0
- package/linthost/format_semi_prefer_never_keeps_semi_before_regex_hazard_test.go +51 -0
- package/linthost/format_semi_prefer_never_keeps_semi_before_same_line_comment_gap_test.go +30 -0
- package/linthost/format_semi_prefer_never_line_comment_is_not_hazard_test.go +49 -0
- package/linthost/format_semi_prefer_never_normalizes_a_comma_it_must_keep_test.go +37 -0
- package/linthost/format_semi_prefer_never_strips_a_comma_member_separator_test.go +32 -0
- package/linthost/format_semi_prefer_never_strips_a_flat_object_types_trailing_separator_test.go +33 -0
- package/linthost/format_semi_prefer_never_strips_a_mapped_type_terminator_test.go +35 -0
- package/linthost/format_semi_prefer_never_strips_across_crlf_test.go +33 -0
- package/linthost/format_semi_prefer_never_strips_across_multiline_comment_gap_test.go +32 -0
- package/linthost/format_semi_prefer_never_strips_before_same_line_close_brace_test.go +31 -0
- package/linthost/format_semi_prefer_never_strips_member_with_space_test.go +52 -0
- package/linthost/format_semi_reads_a_mapped_types_wrap_at_its_opening_brace_test.go +34 -0
- package/linthost/format_semi_skips_already_terminated_statements_test.go +31 -0
- package/linthost/format_semi_strips_class_field_semicolons_test.go +29 -0
- package/linthost/format_semi_strips_interface_member_semicolons_test.go +29 -0
- package/linthost/format_semi_strips_type_alias_semicolon_test.go +29 -0
- package/linthost/format_semi_terminates_a_broken_mapped_type_test.go +40 -0
- package/linthost/format_semi_terminates_a_mapped_type_across_crlf_test.go +32 -0
- package/linthost/format_semi_terminates_a_mapped_type_around_its_trailing_comment_test.go +37 -0
- package/linthost/format_semi_terminates_a_mapped_type_without_a_type_annotation_test.go +37 -0
- package/linthost/format_semi_terminates_a_member_across_crlf_test.go +31 -0
- package/linthost/format_semi_terminates_a_member_whose_type_ends_in_a_brace_test.go +31 -0
- package/linthost/format_semi_terminates_broken_interface_members_test.go +45 -0
- package/linthost/format_semi_terminates_broken_type_literal_member_test.go +31 -0
- package/linthost/format_semi_terminates_class_index_signature_and_ambient_accessor_test.go +29 -0
- package/linthost/format_sort_imports_alphabetizes_named_specifiers_test.go +31 -0
- package/linthost/format_sort_imports_combine_requires_unsafe_runtime_opt_in_test.go +30 -0
- package/linthost/format_sort_imports_combines_type_and_value_test.go +27 -0
- package/linthost/format_sort_imports_dedupes_repeated_specifier_test.go +28 -0
- package/linthost/format_sort_imports_group_separator_honors_crlf_end_of_line_test.go +40 -0
- package/linthost/format_sort_imports_groups_builtins_first_test.go +29 -0
- package/linthost/format_sort_imports_groups_external_before_relative_test.go +35 -0
- package/linthost/format_sort_imports_groups_type_only_imports_test.go +27 -0
- package/linthost/format_sort_imports_honors_crlf_end_of_line_test.go +40 -0
- package/linthost/format_sort_imports_honors_custom_import_order_test.go +88 -0
- package/linthost/format_sort_imports_keeps_attribute_bearing_imports_unmerged_test.go +24 -0
- package/linthost/format_sort_imports_keeps_commented_list_unmerged_test.go +26 -0
- package/linthost/format_sort_imports_keeps_conflicting_defaults_separate_test.go +34 -0
- package/linthost/format_sort_imports_keeps_default_gap_comment_unmerged_test.go +24 -0
- package/linthost/format_sort_imports_keeps_default_only_gap_comment_unmerged_test.go +24 -0
- package/linthost/format_sort_imports_keeps_empty_named_imports_test.go +31 -0
- package/linthost/format_sort_imports_keeps_identical_commented_imports_unmerged_test.go +35 -0
- package/linthost/format_sort_imports_keeps_identical_namespace_imports_unmerged_test.go +35 -0
- package/linthost/format_sort_imports_keeps_namespace_imports_separate_test.go +34 -0
- package/linthost/format_sort_imports_keeps_trailing_specifier_comment_unmerged_test.go +24 -0
- package/linthost/format_sort_imports_keeps_type_and_value_separate_test.go +31 -0
- package/linthost/format_sort_imports_keeps_type_default_and_type_named_separate_test.go +34 -0
- package/linthost/format_sort_imports_keeps_type_default_and_type_named_separate_when_combining_test.go +34 -0
- package/linthost/format_sort_imports_keeps_type_default_separate_when_combining_test.go +31 -0
- package/linthost/format_sort_imports_merges_default_and_named_test.go +27 -0
- package/linthost/format_sort_imports_merges_duplicate_modules_test.go +28 -0
- package/linthost/format_sort_imports_merges_duplicate_type_only_imports_test.go +24 -0
- package/linthost/format_sort_imports_merges_type_default_with_empty_named_test.go +28 -0
- package/linthost/format_sort_imports_merges_type_named_binding_test.go +33 -0
- package/linthost/format_sort_imports_orders_case_insensitively_by_default_test.go +29 -0
- package/linthost/format_sort_imports_orders_case_sensitively_when_enabled_test.go +29 -0
- package/linthost/format_sort_imports_preserves_comments_between_imports_test.go +43 -0
- package/linthost/format_sort_imports_preserves_comments_between_specifiers_test.go +38 -0
- package/linthost/format_sort_imports_preserves_side_effect_imports_test.go +55 -0
- package/linthost/format_sort_imports_recognizes_exact_builtin_specifiers_test.go +56 -0
- package/linthost/format_sort_imports_scopes_type_group_by_regex_test.go +32 -0
- package/linthost/format_sort_imports_separator_spans_empty_group_test.go +31 -0
- package/linthost/format_sort_imports_skips_already_sorted_files_test.go +40 -0
- package/linthost/format_sort_imports_skips_invalid_regex_group_test.go +30 -0
- package/linthost/format_sort_imports_skips_invalid_types_regex_group_test.go +28 -0
- package/linthost/format_sort_imports_skips_single_import_files_test.go +38 -0
- package/linthost/format_sort_imports_sorts_erased_type_only_block_test.go +26 -0
- package/linthost/format_sort_imports_sorts_named_specifiers_without_reordering_runtime_imports_test.go +28 -0
- package/linthost/format_sort_imports_treats_inline_type_bindings_as_runtime_import_test.go +24 -0
- package/linthost/format_sort_imports_unsafe_option_reorders_runtime_imports_test.go +34 -0
- package/linthost/format_statement_split_abstains_on_empty_statements_test.go +26 -0
- package/linthost/format_statement_split_abstains_when_block_comment_in_gap_test.go +28 -0
- package/linthost/format_statement_split_breaks_statements_sharing_a_line_test.go +28 -0
- package/linthost/format_statement_split_breaks_three_statements_on_one_line_test.go +27 -0
- package/linthost/format_statement_split_honors_crlf_end_of_line_test.go +29 -0
- package/linthost/format_statement_split_indents_split_statement_inside_block_test.go +30 -0
- package/linthost/format_statement_split_keeps_block_on_case_label_line_test.go +28 -0
- package/linthost/format_statement_split_keeps_leading_semi_guard_test.go +31 -0
- package/linthost/format_statement_split_skips_already_one_per_line_test.go +26 -0
- package/linthost/format_ternary_nullish_parens_leaves_logical_and_parenthesized_test.go +30 -0
- package/linthost/format_ternary_nullish_parens_wraps_all_positions_test.go +29 -0
- package/linthost/format_trailing_comma_honors_mode_es5_for_enum_members_test.go +26 -0
- package/linthost/format_trailing_comma_honors_mode_es5_includes_type_level_lists_test.go +26 -0
- package/linthost/format_trailing_comma_honors_mode_es5_option_test.go +28 -0
- package/linthost/format_trailing_comma_honors_mode_es5_skips_arrow_parameter_test.go +29 -0
- package/linthost/format_trailing_comma_honors_mode_es5_skips_call_argument_test.go +28 -0
- package/linthost/format_trailing_comma_honors_mode_es5_skips_constructor_parameter_test.go +29 -0
- package/linthost/format_trailing_comma_honors_mode_es5_skips_function_expression_parameter_test.go +29 -0
- package/linthost/format_trailing_comma_honors_mode_es5_skips_method_parameter_test.go +29 -0
- package/linthost/format_trailing_comma_honors_mode_es5_skips_new_argument_test.go +28 -0
- package/linthost/format_trailing_comma_honors_mode_es5_skips_set_accessor_parameter_test.go +29 -0
- package/linthost/format_trailing_comma_inserts_after_array_spread_in_value_literal_test.go +26 -0
- package/linthost/format_trailing_comma_inserts_after_decorated_parameter_test.go +27 -0
- package/linthost/format_trailing_comma_inserts_after_last_array_element_test.go +25 -0
- package/linthost/format_trailing_comma_inserts_after_last_arrow_parameter_test.go +25 -0
- package/linthost/format_trailing_comma_inserts_after_last_call_argument_test.go +25 -0
- package/linthost/format_trailing_comma_inserts_after_last_call_signature_parameter_test.go +28 -0
- package/linthost/format_trailing_comma_inserts_after_last_construct_signature_parameter_test.go +28 -0
- package/linthost/format_trailing_comma_inserts_after_last_constructor_parameter_test.go +26 -0
- package/linthost/format_trailing_comma_inserts_after_last_constructor_type_parameter_test.go +28 -0
- package/linthost/format_trailing_comma_inserts_after_last_element_in_multiple_lists_test.go +27 -0
- package/linthost/format_trailing_comma_inserts_after_last_function_expression_parameter_test.go +25 -0
- package/linthost/format_trailing_comma_inserts_after_last_function_parameter_test.go +25 -0
- package/linthost/format_trailing_comma_inserts_after_last_function_type_parameter_test.go +28 -0
- package/linthost/format_trailing_comma_inserts_after_last_method_parameter_test.go +26 -0
- package/linthost/format_trailing_comma_inserts_after_last_method_signature_parameter_test.go +28 -0
- package/linthost/format_trailing_comma_inserts_after_last_named_export_test.go +25 -0
- package/linthost/format_trailing_comma_inserts_after_last_named_import_test.go +25 -0
- package/linthost/format_trailing_comma_inserts_after_last_new_argument_test.go +27 -0
- package/linthost/format_trailing_comma_inserts_after_last_object_property_test.go +25 -0
- package/linthost/format_trailing_comma_inserts_after_last_set_accessor_parameter_test.go +26 -0
- package/linthost/format_trailing_comma_inserts_after_last_tuple_element_test.go +25 -0
- package/linthost/format_trailing_comma_inserts_after_last_type_parameter_test.go +28 -0
- package/linthost/format_trailing_comma_inserts_after_non_rest_array_assignment_target_test.go +27 -0
- package/linthost/format_trailing_comma_inserts_after_non_rest_object_assignment_target_test.go +27 -0
- package/linthost/format_trailing_comma_inserts_after_object_spread_in_value_literal_test.go +26 -0
- package/linthost/format_trailing_comma_inserts_after_parameter_property_in_constructor_test.go +28 -0
- package/linthost/format_trailing_comma_mode_none_removes_trailing_comma_test.go +28 -0
- package/linthost/format_trailing_comma_places_comma_before_trailing_line_comment_test.go +31 -0
- package/linthost/format_trailing_comma_removes_call_comma_under_es5_test.go +27 -0
- package/linthost/format_trailing_comma_skips_already_terminated_lists_test.go +31 -0
- package/linthost/format_trailing_comma_skips_array_rest_assignment_target_test.go +28 -0
- package/linthost/format_trailing_comma_skips_call_when_close_paren_shares_line_with_last_argument_test.go +30 -0
- package/linthost/format_trailing_comma_skips_dynamic_import_argument_test.go +28 -0
- package/linthost/format_trailing_comma_skips_empty_lists_test.go +32 -0
- package/linthost/format_trailing_comma_skips_inline_block_comment_before_close_bracket_test.go +31 -0
- package/linthost/format_trailing_comma_skips_object_rest_assignment_target_test.go +28 -0
- package/linthost/format_trailing_comma_skips_rest_parameter_test.go +39 -0
- package/linthost/format_trailing_comma_skips_single_line_lists_test.go +34 -0
- package/linthost/format_trailing_comma_skips_unparenthesized_arrow_with_multiline_body_test.go +28 -0
- package/linthost/format_whitespace_collapses_all_blank_file_to_single_eol_test.go +30 -0
- package/linthost/format_whitespace_collapses_consecutive_blank_lines_test.go +27 -0
- package/linthost/format_whitespace_fixes_missing_final_newline_with_trailing_space_test.go +29 -0
- package/linthost/format_whitespace_inserts_missing_final_newline_test.go +28 -0
- package/linthost/format_whitespace_keeps_blank_line_inside_template_test.go +27 -0
- package/linthost/format_whitespace_normalizes_crlf_to_lf_by_default_test.go +28 -0
- package/linthost/format_whitespace_preserves_crlf_under_crlf_end_of_line_test.go +28 -0
- package/linthost/format_whitespace_preserves_nested_template_content_test.go +28 -0
- package/linthost/format_whitespace_preserves_trailing_space_across_template_substitution_test.go +29 -0
- package/linthost/format_whitespace_preserves_trailing_spaces_inside_template_literal_test.go +35 -0
- package/linthost/format_whitespace_skips_empty_file_test.go +26 -0
- package/linthost/format_whitespace_skips_single_blank_line_test.go +26 -0
- package/linthost/format_whitespace_strips_leading_blank_lines_test.go +27 -0
- package/linthost/format_whitespace_strips_trailing_blank_lines_test.go +27 -0
- package/linthost/format_whitespace_trims_trailing_spaces_test.go +28 -0
- package/linthost/functional_helpers_test.go +88 -0
- package/linthost/functional_immutable_data_ignores_code_pattern_test.go +28 -0
- package/linthost/functional_immutable_data_rejects_property_assignment_test.go +25 -0
- package/linthost/functional_no_class_inheritance_rejects_extends_test.go +24 -0
- package/linthost/functional_no_classes_rejects_class_declaration_test.go +24 -0
- package/linthost/functional_no_conditional_statements_rejects_if_test.go +23 -0
- package/linthost/functional_no_expression_statements_rejects_call_test.go +23 -0
- package/linthost/functional_no_let_ignores_identifier_pattern_test.go +28 -0
- package/linthost/functional_no_let_rejects_let_declaration_test.go +24 -0
- package/linthost/functional_no_loop_statements_rejects_for_test.go +23 -0
- package/linthost/functional_no_mixed_types_check_interfaces_false_skips_interface_test.go +28 -0
- package/linthost/functional_no_mixed_types_check_interfaces_false_still_checks_type_literal_test.go +28 -0
- package/linthost/functional_no_mixed_types_check_type_literals_false_skips_type_literal_test.go +28 -0
- package/linthost/functional_no_mixed_types_check_type_literals_false_still_checks_interface_test.go +28 -0
- package/linthost/functional_no_mixed_types_rejects_method_and_property_test.go +23 -0
- package/linthost/functional_no_promise_reject_rejects_static_call_test.go +23 -0
- package/linthost/functional_no_return_void_allow_null_false_rejects_null_return_type_test.go +27 -0
- package/linthost/functional_no_return_void_allow_undefined_false_rejects_undefined_return_type_test.go +28 -0
- package/linthost/functional_no_return_void_allows_null_return_type_by_default_test.go +23 -0
- package/linthost/functional_no_return_void_allows_undefined_return_type_by_default_test.go +23 -0
- package/linthost/functional_no_return_void_ignore_inferred_types_keeps_annotated_bare_return_test.go +28 -0
- package/linthost/functional_no_return_void_ignore_inferred_types_reads_a_get_accessor_annotation_test.go +30 -0
- package/linthost/functional_no_return_void_ignore_inferred_types_skips_unannotated_bare_return_test.go +28 -0
- package/linthost/functional_no_return_void_ignore_inferred_types_stops_at_the_nearest_function_test.go +29 -0
- package/linthost/functional_no_return_void_rejects_void_annotation_test.go +23 -0
- package/linthost/functional_no_this_expressions_rejects_this_test.go +23 -0
- package/linthost/functional_no_throw_statements_rejects_throw_test.go +23 -0
- package/linthost/functional_no_try_statements_rejects_try_test.go +23 -0
- package/linthost/functional_parameters_ignores_identifier_pattern_test.go +27 -0
- package/linthost/functional_parameters_rejects_rest_parameter_test.go +25 -0
- package/linthost/functional_prefer_immutable_types_ignores_identifier_pattern_test.go +28 -0
- package/linthost/functional_prefer_immutable_types_rejects_array_type_test.go +23 -0
- package/linthost/functional_prefer_immutable_types_rejects_mutable_parameter_array_test.go +24 -0
- package/linthost/functional_prefer_property_signatures_rejects_method_signature_test.go +23 -0
- package/linthost/functional_prefer_readonly_type_allow_mutable_return_type_covers_call_signature_test.go +29 -0
- package/linthost/functional_prefer_readonly_type_allow_mutable_return_type_keeps_parameter_annotation_test.go +28 -0
- package/linthost/functional_prefer_readonly_type_allow_mutable_return_type_skips_return_annotation_test.go +28 -0
- package/linthost/functional_prefer_readonly_type_ignore_class_fields_only_keeps_method_parameter_test.go +34 -0
- package/linthost/functional_prefer_readonly_type_ignore_class_keeps_module_scope_checked_test.go +29 -0
- package/linthost/functional_prefer_readonly_type_ignore_class_skips_class_body_test.go +29 -0
- package/linthost/functional_prefer_readonly_type_ignore_collections_keeps_property_signature_test.go +28 -0
- package/linthost/functional_prefer_readonly_type_ignore_collections_skips_array_type_test.go +28 -0
- package/linthost/functional_prefer_readonly_type_ignore_interface_keeps_type_alias_member_test.go +28 -0
- package/linthost/functional_prefer_readonly_type_ignore_interface_skips_interface_member_test.go +28 -0
- package/linthost/functional_prefer_readonly_type_ignores_code_pattern_test.go +27 -0
- package/linthost/functional_prefer_readonly_type_rejects_array_type_test.go +23 -0
- package/linthost/functional_prefer_tacit_check_member_expressions_false_keeps_identifier_callee_test.go +27 -0
- package/linthost/functional_prefer_tacit_check_member_expressions_false_skips_member_callee_test.go +28 -0
- package/linthost/functional_prefer_tacit_rejects_single_argument_wrapper_test.go +24 -0
- package/linthost/functional_readonly_type_rejects_readonly_array_generic_test.go +23 -0
- package/linthost/functional_type_declaration_immutability_ignores_identifier_pattern_test.go +27 -0
- package/linthost/functional_type_declaration_immutability_rejects_mutable_interface_test.go +23 -0
- package/linthost/getter_return_follows_every_path_through_switch_try_and_loops_test.go +64 -0
- package/linthost/global_ignores_remove_an_imported_source_from_the_read_scope_test.go +60 -0
- package/linthost/graph_nodes.go +12 -2
- package/linthost/graph_nodes_drops_what_a_consumer_cannot_index_test.go +98 -0
- package/linthost/graph_nodes_publishes_nothing_without_a_publisher_test.go +51 -0
- package/linthost/grapheme_break_unicode_16_conformance_test.go +99 -0
- package/linthost/grouped_accessor_pairs_object_literal_message_test.go +75 -0
- package/linthost/guard_for_in_structural_matrix_test.go +74 -0
- package/linthost/has_nil_entry_distinguishes_malformed_and_valid_lists_test.go +35 -0
- package/linthost/has_nil_entry_returns_false_for_nil_list_test.go +26 -0
- package/linthost/helpers_test.go +910 -0
- package/linthost/hints.go +11 -1
- package/linthost/host.go +126 -43
- package/linthost/imported_tsx_source_joins_the_read_scope_test.go +67 -0
- package/linthost/indent_unit_uses_tab_width_when_positive_test.go +49 -0
- package/linthost/inline_resolver_carries_options_in_resolved_config_test.go +36 -0
- package/linthost/input_observation.go +571 -0
- package/linthost/invalid_contributor_range_cannot_panic_inline_directive_filtering_test.go +46 -0
- package/linthost/is_format_rule_detects_marker_interface_test.go +62 -0
- package/linthost/jsdoc_helpers_test.go +30 -0
- package/linthost/jsx_a11y_alt_text_allows_img_spread_props_test.go +21 -0
- package/linthost/jsx_a11y_alt_text_requires_img_alt_test.go +22 -0
- package/linthost/jsx_a11y_anchor_ambiguous_text_test.go +24 -0
- package/linthost/jsx_a11y_anchor_has_content_rejects_empty_anchor_test.go +25 -0
- package/linthost/jsx_a11y_anchor_is_valid_allows_spread_props_test.go +21 -0
- package/linthost/jsx_a11y_anchor_is_valid_rejects_hash_href_despite_spread_test.go +22 -0
- package/linthost/jsx_a11y_anchor_is_valid_rejects_hash_href_test.go +22 -0
- package/linthost/jsx_a11y_aria_activedescendant_has_tabindex_requires_focus_target_test.go +23 -0
- package/linthost/jsx_a11y_aria_props_rejects_unknown_prop_test.go +22 -0
- package/linthost/jsx_a11y_aria_proptypes_rejects_bad_boolean_test.go +23 -0
- package/linthost/jsx_a11y_aria_role_rejects_unknown_role_test.go +22 -0
- package/linthost/jsx_a11y_aria_unsupported_elements_rejects_meta_aria_test.go +23 -0
- package/linthost/jsx_a11y_aria_unsupported_elements_rejects_role_despite_spread_test.go +24 -0
- package/linthost/jsx_a11y_autocomplete_valid_allows_appropriate_input_type_test.go +29 -0
- package/linthost/jsx_a11y_autocomplete_valid_rejects_inappropriate_input_type_test.go +21 -0
- package/linthost/jsx_a11y_autocomplete_valid_rejects_invalid_token_sequence_test.go +26 -0
- package/linthost/jsx_a11y_autocomplete_valid_rejects_unknown_token_test.go +22 -0
- package/linthost/jsx_a11y_click_events_have_key_events_requires_keyboard_handler_test.go +21 -0
- package/linthost/jsx_a11y_control_has_associated_label_requires_button_label_test.go +21 -0
- package/linthost/jsx_a11y_heading_has_content_rejects_empty_heading_test.go +22 -0
- package/linthost/jsx_a11y_helpers_test.go +33 -0
- package/linthost/jsx_a11y_html_has_lang_allows_non_empty_lang_test.go +21 -0
- package/linthost/jsx_a11y_html_has_lang_allows_spread_props_test.go +24 -0
- package/linthost/jsx_a11y_html_has_lang_rejects_empty_lang_test.go +27 -0
- package/linthost/jsx_a11y_html_has_lang_requires_lang_test.go +21 -0
- package/linthost/jsx_a11y_iframe_has_title_allows_spread_props_test.go +23 -0
- package/linthost/jsx_a11y_iframe_has_title_requires_title_test.go +21 -0
- package/linthost/jsx_a11y_img_redundant_alt_rejects_image_word_despite_spread_test.go +25 -0
- package/linthost/jsx_a11y_img_redundant_alt_rejects_image_word_test.go +21 -0
- package/linthost/jsx_a11y_interactive_supports_focus_requires_tabindex_test.go +21 -0
- package/linthost/jsx_a11y_label_has_associated_control_requires_for_or_child_test.go +21 -0
- package/linthost/jsx_a11y_label_has_for_alias_matches_associated_control_test.go +21 -0
- package/linthost/jsx_a11y_lang_allows_valid_bcp47_tag_test.go +22 -0
- package/linthost/jsx_a11y_lang_rejects_empty_lang_test.go +20 -0
- package/linthost/jsx_a11y_lang_rejects_invalid_bcp47_tag_test.go +25 -0
- package/linthost/jsx_a11y_media_has_caption_requires_track_test.go +22 -0
- package/linthost/jsx_a11y_mouse_events_have_key_events_requires_focus_test.go +21 -0
- package/linthost/jsx_a11y_no_access_key_rejects_access_key_test.go +21 -0
- package/linthost/jsx_a11y_no_aria_hidden_on_focusable_rejects_hidden_button_test.go +21 -0
- package/linthost/jsx_a11y_no_autofocus_rejects_autofocus_test.go +21 -0
- package/linthost/jsx_a11y_no_distracting_elements_rejects_marquee_test.go +21 -0
- package/linthost/jsx_a11y_no_interactive_element_to_noninteractive_role_rejects_button_presentation_test.go +21 -0
- package/linthost/jsx_a11y_no_noninteractive_element_interactions_rejects_li_click_test.go +21 -0
- package/linthost/jsx_a11y_no_noninteractive_element_to_interactive_role_rejects_ul_button_test.go +21 -0
- package/linthost/jsx_a11y_no_noninteractive_tabindex_rejects_section_tabindex_test.go +21 -0
- package/linthost/jsx_a11y_no_redundant_roles_rejects_button_role_button_test.go +21 -0
- package/linthost/jsx_a11y_no_static_element_interactions_requires_role_test.go +21 -0
- package/linthost/jsx_a11y_prefer_tag_over_role_rejects_div_button_test.go +21 -0
- package/linthost/jsx_a11y_role_has_required_aria_props_allows_native_checkbox_test.go +21 -0
- package/linthost/jsx_a11y_role_has_required_aria_props_allows_spread_props_test.go +23 -0
- package/linthost/jsx_a11y_role_has_required_aria_props_requires_checkbox_checked_test.go +21 -0
- package/linthost/jsx_a11y_role_supports_aria_props_allows_explicit_button_pressed_test.go +21 -0
- package/linthost/jsx_a11y_role_supports_aria_props_allows_native_button_pressed_test.go +21 -0
- package/linthost/jsx_a11y_role_supports_aria_props_rejects_button_checked_test.go +21 -0
- package/linthost/jsx_a11y_rules_survive_spread_attributes_test.go +60 -0
- package/linthost/jsx_a11y_scope_rejects_scope_on_td_test.go +21 -0
- package/linthost/jsx_a11y_tabindex_no_positive_rejects_positive_tabindex_test.go +21 -0
- package/linthost/known_symbol_property_name_finds_iteration_and_disposal_protocol_members_test.go +112 -0
- package/linthost/legacy_custom_resolver_keeps_rule_options_fallback_test.go +45 -0
- package/linthost/lint_corpus_companions_belong_to_their_own_case_test.go +53 -0
- package/linthost/lint_corpus_diagnostics_are_attributed_to_the_main_source_test.go +51 -0
- package/linthost/lint_corpus_directives_reject_malformed_or_duplicate_markers_test.go +89 -0
- package/linthost/lint_corpus_discovery_classifies_every_typescript_suffix_test.go +56 -0
- package/linthost/lint_corpus_discovery_rejects_invalid_companion_contracts_test.go +50 -0
- package/linthost/lint_corpus_discovery_rejects_unclassified_sources_test.go +39 -0
- package/linthost/lint_corpus_expectation_parser_rejects_malformed_or_targetless_markers_test.go +46 -0
- package/linthost/lint_corpus_expectation_parser_resolves_line_and_jsx_block_markers_test.go +53 -0
- package/linthost/lint_corpus_filename_separators_share_materialized_source_identity_test.go +85 -0
- package/linthost/lint_corpus_loader_helpers_test.go +704 -0
- package/linthost/lint_corpus_project_selects_jsx_mode_for_included_tsx_sources_test.go +118 -0
- package/linthost/lint_corpus_skips_name_one_rule_and_one_harness_test.go +63 -0
- package/linthost/lint_fixture_corpus_test.go +166 -0
- package/linthost/lint_trace.go +202 -0
- package/linthost/lint_trace_preserves_raw_invocation_and_integrity_test.go +139 -0
- package/linthost/load_config_file_rejects_unsupported_extension_test.go +38 -0
- package/linthost/load_config_resolver_compact_globs_preserve_entry_policy_test.go +97 -0
- package/linthost/load_config_resolver_scopes_extends_options_in_engine_test.go +65 -0
- package/linthost/load_json_config_file_rejects_invalid_json_test.go +38 -0
- package/linthost/load_program_keeps_checker_pool_for_type_aware_rules_test.go +184 -0
- package/linthost/load_program_skips_checker_for_ast_only_rules_test.go +59 -0
- package/linthost/load_rule_config_configfile_overrides_discovery_test.go +51 -0
- package/linthost/load_rule_config_discovers_cwd_config_for_out_of_tree_tsconfig_test.go +46 -0
- package/linthost/load_rule_config_discovers_plain_lint_config_test.go +39 -0
- package/linthost/load_rule_config_extends_with_ignores_and_rules_ignores_globally_test.go +141 -0
- package/linthost/load_rule_config_honors_plugin_config_dir_env_test.go +53 -0
- package/linthost/load_rule_config_loads_json_config_file_test.go +55 -0
- package/linthost/load_rule_config_missing_config_error_names_search_origins_test.go +44 -0
- package/linthost/load_rule_config_preserves_json_pattern_precedence_test.go +80 -0
- package/linthost/load_rule_config_rejects_array_rules_test.go +34 -0
- package/linthost/load_rule_config_rejects_empty_extends_test.go +34 -0
- package/linthost/load_rule_config_rejects_extends_cycle_between_two_configs_test.go +71 -0
- package/linthost/load_rule_config_rejects_missing_discovered_config_test.go +37 -0
- package/linthost/load_rule_config_rejects_overly_deep_extends_chain_test.go +53 -0
- package/linthost/load_rule_config_rejects_self_referential_extends_test.go +49 -0
- package/linthost/load_rule_config_resolves_configfile_relative_to_plugin_config_dir_env_test.go +46 -0
- package/linthost/load_rule_config_resolves_linear_extends_chain_test.go +81 -0
- package/linthost/load_rules_ignores_non_lint_plugin_payload_test.go +33 -0
- package/linthost/loader_module_option_follows_the_config_package_type_test.go +103 -0
- package/linthost/loader_rootdir_contains_loader_and_config_test.go +59 -0
- package/linthost/loader_temp_base_stays_on_config_volume_test.go +35 -0
- package/linthost/logic_rules_cover_boolean_call_arguments_undefined_typeof_negative_zero_and_number_nan_test.go +43 -0
- package/linthost/lookup_rule_returns_registered_implementation_or_nil_test.go +49 -0
- package/linthost/lsp.go +185 -34
- package/linthost/lsp_apply_suggestion_rejects_stale_source_test.go +49 -0
- package/linthost/lsp_apply_suggestion_resolves_junction_project_link_test.go +33 -0
- package/linthost/lsp_apply_suggestion_resolves_logical_project_link_test.go +35 -0
- package/linthost/lsp_await_thenable_suggestion_executes_exact_token_test.go +52 -0
- package/linthost/lsp_ban_ts_comment_suggestion_preserves_crlf_block_test.go +52 -0
- package/linthost/lsp_code_action_helpers_test.go +55 -0
- package/linthost/lsp_code_actions_fail_closed_for_invalid_quickfix_range_test.go +88 -0
- package/linthost/lsp_code_actions_reject_more_specific_context_only_test.go +37 -0
- package/linthost/lsp_code_actions_returns_empty_for_node_modules_target_test.go +44 -0
- package/linthost/lsp_code_actions_returns_empty_for_outside_cwd_target_test.go +45 -0
- package/linthost/lsp_code_actions_short_circuits_unowned_context_only_test.go +46 -0
- package/linthost/lsp_code_actions_split_lint_and_format_commands_test.go +41 -0
- package/linthost/lsp_command_discovery_reports_owned_commands_and_kinds_test.go +67 -0
- package/linthost/lsp_command_helpers_test.go +113 -0
- package/linthost/lsp_command_workspace_preserves_nested_dependency_scopes_test.go +77 -0
- package/linthost/lsp_commands_accept_windows_short_cwd_test.go +62 -0
- package/linthost/lsp_diagnostic_omits_code_description_for_contributor_rule_test.go +81 -0
- package/linthost/lsp_diagnostic_tags_drop_unknown_values_test.go +41 -0
- package/linthost/lsp_diagnostic_wire_drops_code_description_key_when_unmapped_test.go +65 -0
- package/linthost/lsp_diagnostics_link_rule_codes_to_documentation_test.go +84 -0
- package/linthost/lsp_document_write_scope_preserves_project_and_sibling_boundaries_test.go +68 -0
- package/linthost/lsp_execute_command_applies_utf16_edit_after_non_bmp_prefix_test.go +48 -0
- package/linthost/lsp_execute_command_cascades_format_fixes_without_mutating_disk_test.go +50 -0
- package/linthost/lsp_execute_command_cascades_lint_fixes_without_mutating_disk_test.go +48 -0
- package/linthost/lsp_execute_command_copies_read_only_file_as_writable_test.go +46 -0
- package/linthost/lsp_execute_command_maps_absolute_config_file_into_temp_workspace_test.go +40 -0
- package/linthost/lsp_execute_command_materializes_duplicate_symlinked_directories_test.go +57 -0
- package/linthost/lsp_execute_command_materializes_junctioned_directory_without_mutating_original_test.go +61 -0
- package/linthost/lsp_execute_command_materializes_symlink_target_without_mutating_original_test.go +55 -0
- package/linthost/lsp_execute_command_materializes_symlinked_directory_without_mutating_original_test.go +56 -0
- package/linthost/lsp_execute_command_rejects_target_outside_cwd_before_read_test.go +61 -0
- package/linthost/lsp_execute_command_returns_null_for_node_modules_target_test.go +59 -0
- package/linthost/lsp_execute_command_returns_null_when_no_edits_test.go +51 -0
- package/linthost/lsp_execute_command_splits_lint_and_format_edits_test.go +43 -0
- package/linthost/lsp_fix_all_leaves_suggestion_only_rewrites_unchanged_test.go +37 -0
- package/linthost/lsp_format_buffer_formats_missing_disk_file_test.go +42 -0
- package/linthost/lsp_format_buffer_helpers_test.go +68 -0
- package/linthost/lsp_format_buffer_ignores_disk_content_test.go +52 -0
- package/linthost/lsp_format_buffer_in_memory_test.go +47 -0
- package/linthost/lsp_format_buffer_type_aware_contributor_test.go +142 -0
- package/linthost/lsp_format_paths_honor_entry_ignores_test.go +45 -0
- package/linthost/lsp_format_paths_use_canonical_defaults_test.go +72 -0
- package/linthost/lsp_format_paths_use_defaults_without_format_block_test.go +28 -0
- package/linthost/lsp_format_paths_use_editor_language_overrides_test.go +34 -0
- package/linthost/lsp_hints_publishes_jsdoc_check_tag_names_corpus_test.go +56 -0
- package/linthost/lsp_hints_skips_the_program_when_nothing_publishes_test.go +46 -0
- package/linthost/lsp_hints_still_loads_the_program_for_a_declared_publisher_test.go +42 -0
- package/linthost/lsp_logical_project_link_helpers_test.go +127 -0
- package/linthost/lsp_position_columns_count_utf16_across_planes_test.go +107 -0
- package/linthost/lsp_position_counts_non_bmp_as_two_utf16_units_test.go +26 -0
- package/linthost/lsp_prefer_as_const_suggestion_executes_selected_range_test.go +51 -0
- package/linthost/lsp_project_diagnostics_recomputes_external_state_without_document_test.go +187 -0
- package/linthost/lsp_serve_answers_hints_from_the_resident_daemon_test.go +73 -0
- package/linthost/lsp_switch_exhaustiveness_suggestions_preserve_default_anchors_test.go +206 -0
- package/linthost/match_any_pattern_accepts_native_and_slash_separators_test.go +47 -0
- package/linthost/match_any_pattern_handles_brace_expansion_test.go +43 -0
- package/linthost/match_any_pattern_matches_dot_directory_globs_test.go +44 -0
- package/linthost/max_nested_callbacks_counts_only_functions_passed_to_calls_test.go +46 -0
- package/linthost/migrated_no_misused_promises_helpers_test.go +30 -0
- package/linthost/migrated_no_unused_expressions_helpers_test.go +50 -0
- package/linthost/migrated_typed_rule_helpers_test.go +46 -0
- package/linthost/misc_testing_library_rules_test.go +63 -0
- package/linthost/mixed_diagnostics_render_empty_is_silent_test.go +29 -0
- package/linthost/mixed_diagnostics_render_interleaves_parser_and_lint_test.go +51 -0
- package/linthost/mixed_diagnostics_render_orders_files_and_ties_test.go +58 -0
- package/linthost/new_print_context_zero_print_width_applies_defaults_test.go +36 -0
- package/linthost/no_array_delete_asks_the_type_not_the_subscript_test.go +70 -0
- package/linthost/no_await_in_loop_complete_semantics_test.go +205 -0
- package/linthost/no_base_to_string_test.go +48 -0
- package/linthost/no_class_assign_test.go +217 -0
- package/linthost/no_container_ignores_unrelated_container_binding_test.go +33 -0
- package/linthost/no_deprecated_test.go +45 -0
- package/linthost/no_dupe_class_members_allows_typescript_overload_signatures_test.go +41 -0
- package/linthost/no_dupe_class_members_rejects_accessor_data_collisions_test.go +28 -0
- package/linthost/no_dupe_else_if_logical_coverage_test.go +152 -0
- package/linthost/no_dupe_keys_computed_key_static_resolution_test.go +72 -0
- package/linthost/no_duplicate_imports_allow_separate_type_imports_allows_value_plus_type_import_test.go +30 -0
- package/linthost/no_duplicate_imports_allow_separate_type_imports_still_reports_type_pairs_test.go +30 -0
- package/linthost/no_duplicate_imports_allow_separate_type_imports_still_reports_value_pairs_test.go +29 -0
- package/linthost/no_duplicate_imports_allows_inline_type_specifier_beside_type_import_test.go +29 -0
- package/linthost/no_duplicate_imports_allows_named_and_namespace_value_imports_test.go +31 -0
- package/linthost/no_duplicate_imports_allows_type_default_and_type_named_imports_test.go +31 -0
- package/linthost/no_duplicate_imports_allows_type_namespace_and_type_named_imports_test.go +28 -0
- package/linthost/no_duplicate_imports_classifies_inline_type_specifier_as_value_test.go +31 -0
- package/linthost/no_duplicate_imports_helpers_test.go +78 -0
- package/linthost/no_duplicate_imports_ignores_misspelled_option_keys_test.go +30 -0
- package/linthost/no_duplicate_imports_ignores_reexports_by_default_test.go +32 -0
- package/linthost/no_duplicate_imports_include_exports_allows_export_star_beside_named_import_test.go +31 -0
- package/linthost/no_duplicate_imports_include_exports_allows_export_star_beside_namespace_reexport_test.go +29 -0
- package/linthost/no_duplicate_imports_include_exports_allows_namespace_reexport_beside_named_import_test.go +29 -0
- package/linthost/no_duplicate_imports_include_exports_reports_both_pairings_on_one_declaration_test.go +34 -0
- package/linthost/no_duplicate_imports_include_exports_reports_export_star_beside_side_effect_import_test.go +35 -0
- package/linthost/no_duplicate_imports_include_exports_reports_import_after_reexport_test.go +30 -0
- package/linthost/no_duplicate_imports_include_exports_reports_reexport_after_import_test.go +30 -0
- package/linthost/no_duplicate_imports_include_exports_reports_repeated_export_star_test.go +30 -0
- package/linthost/no_duplicate_imports_include_exports_reports_second_reexport_test.go +29 -0
- package/linthost/no_duplicate_imports_include_exports_reports_type_reexport_after_value_import_test.go +30 -0
- package/linthost/no_duplicate_imports_include_exports_skips_local_export_without_module_test.go +31 -0
- package/linthost/no_duplicate_imports_include_exports_treats_empty_reexport_clause_as_side_effect_test.go +31 -0
- package/linthost/no_duplicate_imports_include_exports_with_allow_separate_allows_type_reexport_test.go +30 -0
- package/linthost/no_duplicate_imports_preserves_migrated_json_tuple_options_test.go +47 -0
- package/linthost/no_duplicate_imports_reports_default_then_named_value_imports_test.go +31 -0
- package/linthost/no_duplicate_imports_reports_default_then_namespace_value_imports_test.go +30 -0
- package/linthost/no_duplicate_imports_reports_each_later_duplicate_import_test.go +31 -0
- package/linthost/no_duplicate_imports_reports_nonadjacent_duplicate_value_imports_test.go +30 -0
- package/linthost/no_duplicate_imports_reports_repeated_side_effect_imports_test.go +29 -0
- package/linthost/no_duplicate_imports_reports_side_effect_import_after_named_import_test.go +30 -0
- package/linthost/no_duplicate_imports_reports_two_namespace_value_imports_test.go +29 -0
- package/linthost/no_duplicate_imports_reports_two_type_default_imports_test.go +29 -0
- package/linthost/no_duplicate_imports_reports_value_default_then_type_named_import_test.go +33 -0
- package/linthost/no_duplicate_imports_reports_value_then_type_named_import_by_default_test.go +30 -0
- package/linthost/no_duplicate_imports_skips_empty_module_specifiers_test.go +30 -0
- package/linthost/no_duplicate_imports_treats_default_with_empty_named_clause_as_default_test.go +30 -0
- package/linthost/no_duplicate_imports_treats_empty_named_import_clause_as_side_effect_test.go +32 -0
- package/linthost/no_duplicate_imports_trims_module_specifier_whitespace_test.go +29 -0
- package/linthost/no_else_return_allow_else_if_false_reports_else_if_test.go +60 -0
- package/linthost/no_else_return_allows_break_before_else_test.go +34 -0
- package/linthost/no_else_return_allows_continue_before_else_test.go +34 -0
- package/linthost/no_else_return_allows_else_if_return_chain_test.go +34 -0
- package/linthost/no_else_return_allows_throw_before_else_test.go +32 -0
- package/linthost/no_else_return_reports_once_on_terminal_else_test.go +31 -0
- package/linthost/no_else_return_reports_plain_else_after_return_test.go +27 -0
- package/linthost/no_empty_character_class_semantics_test.go +62 -0
- package/linthost/no_empty_complete_semantics_test.go +89 -0
- package/linthost/no_empty_function_comments_preserve_every_kind_test.go +35 -0
- package/linthost/no_empty_function_options_test.go +60 -0
- package/linthost/no_empty_function_typescript_exceptions_and_category_boundaries_test.go +248 -0
- package/linthost/no_empty_static_block_comment_boundaries_test.go +37 -0
- package/linthost/no_extend_native_covers_assignment_and_static_callee_forms_test.go +52 -0
- package/linthost/no_extend_native_covers_every_native_constructor_with_a_prototype_test.go +45 -0
- package/linthost/no_extend_native_define_property_and_computed_test.go +71 -0
- package/linthost/no_extend_native_respects_constructor_bindings_test.go +48 -0
- package/linthost/no_extra_bind_function_body_test.go +72 -0
- package/linthost/no_extra_bind_offers_withheld_removal_as_suggestion_test.go +43 -0
- package/linthost/no_extra_bind_preserves_throwing_receiver_reads_test.go +32 -0
- package/linthost/no_extra_boolean_cast_declines_fix_for_comment_between_bangs_test.go +28 -0
- package/linthost/no_extra_boolean_cast_declines_fix_for_leading_comment_in_call_test.go +29 -0
- package/linthost/no_extra_boolean_cast_declines_fix_for_trailing_comment_in_call_test.go +28 -0
- package/linthost/no_extra_boolean_cast_fix_boolean_call_in_boolean_context_test.go +43 -0
- package/linthost/no_extra_boolean_cast_fix_collapses_nested_boolean_call_test.go +30 -0
- package/linthost/no_extra_boolean_cast_fix_double_bang_in_boolean_context_test.go +28 -0
- package/linthost/no_extra_boolean_cast_fix_keeps_bare_identifier_under_bang_test.go +28 -0
- package/linthost/no_extra_boolean_cast_fix_keeps_parenthesized_argument_without_double_wrap_test.go +28 -0
- package/linthost/no_extra_boolean_cast_fix_parenthesizes_arrow_argument_in_ternary_condition_test.go +30 -0
- package/linthost/no_extra_boolean_cast_fix_parenthesizes_assignment_in_ternary_condition_test.go +28 -0
- package/linthost/no_extra_boolean_cast_fix_parenthesizes_await_argument_under_bang_test.go +28 -0
- package/linthost/no_extra_boolean_cast_fix_parenthesizes_logical_operand_under_bang_test.go +28 -0
- package/linthost/no_extra_boolean_cast_fix_parenthesizes_nested_ternary_condition_test.go +30 -0
- package/linthost/no_extra_boolean_cast_fix_parenthesizes_yield_argument_under_bang_test.go +28 -0
- package/linthost/no_extra_boolean_cast_fix_preserves_comment_inside_argument_test.go +29 -0
- package/linthost/no_extra_boolean_cast_fix_skips_wrap_for_logical_ternary_condition_test.go +29 -0
- package/linthost/no_extra_boolean_cast_fix_skips_wrap_inside_explicit_parens_under_bang_test.go +29 -0
- package/linthost/no_extra_boolean_cast_keeps_meaningful_double_bang_outside_boolean_context_test.go +28 -0
- package/linthost/no_extra_boolean_cast_offers_withheld_splice_as_suggestion_test.go +37 -0
- package/linthost/no_extra_boolean_cast_preserves_shadowed_converters_test.go +76 -0
- package/linthost/no_fallthrough_accepts_adjacent_empty_case_labels_test.go +28 -0
- package/linthost/no_fallthrough_accepts_block_marker_with_trailing_unrelated_comment_test.go +32 -0
- package/linthost/no_fallthrough_accepts_break_in_try_with_normal_finally_test.go +33 -0
- package/linthost/no_fallthrough_accepts_breaking_catch_after_throwing_try_test.go +34 -0
- package/linthost/no_fallthrough_accepts_continue_terminating_case_test.go +33 -0
- package/linthost/no_fallthrough_accepts_do_while_with_always_throwing_body_test.go +33 -0
- package/linthost/no_fallthrough_accepts_empty_case_with_same_line_comment_test.go +29 -0
- package/linthost/no_fallthrough_accepts_if_else_terminating_every_path_test.go +38 -0
- package/linthost/no_fallthrough_accepts_infinite_for_without_break_test.go +31 -0
- package/linthost/no_fallthrough_accepts_infinite_loop_with_labeled_break_to_outer_test.go +35 -0
- package/linthost/no_fallthrough_accepts_infinite_while_without_break_test.go +31 -0
- package/linthost/no_fallthrough_accepts_labeled_break_to_outer_loop_test.go +34 -0
- package/linthost/no_fallthrough_accepts_marked_empty_case_with_blank_gap_test.go +30 -0
- package/linthost/no_fallthrough_accepts_marked_fallthrough_variants_test.go +43 -0
- package/linthost/no_fallthrough_accepts_marker_in_sole_empty_block_test.go +30 -0
- package/linthost/no_fallthrough_accepts_marker_inside_sole_block_statement_test.go +32 -0
- package/linthost/no_fallthrough_accepts_nested_switch_terminating_on_every_path_test.go +38 -0
- package/linthost/no_fallthrough_accepts_terminating_finally_test.go +34 -0
- package/linthost/no_fallthrough_accepts_terminating_try_and_catch_with_normal_finally_test.go +41 -0
- package/linthost/no_fallthrough_accepts_unreachable_labeled_break_in_while_false_test.go +39 -0
- package/linthost/no_fallthrough_accepts_unreachable_labeled_break_in_while_zero_test.go +37 -0
- package/linthost/no_fallthrough_accepts_while_bigint_one_literal_test.go +31 -0
- package/linthost/no_fallthrough_accepts_while_nonempty_string_literal_test.go +31 -0
- package/linthost/no_fallthrough_accepts_while_numeric_one_literal_test.go +31 -0
- package/linthost/no_fallthrough_accepts_while_regex_literal_test.go +31 -0
- package/linthost/no_fallthrough_accepts_with_statement_body_break_test.go +33 -0
- package/linthost/no_fallthrough_allow_empty_case_permits_blank_line_gap_test.go +29 -0
- package/linthost/no_fallthrough_command_composes_nested_try_finally_test.go +124 -0
- package/linthost/no_fallthrough_command_composes_statement_and_loop_throw_edges_test.go +108 -0
- package/linthost/no_fallthrough_command_helpers_test.go +68 -0
- package/linthost/no_fallthrough_command_preserves_bigint_literal_truthiness_test.go +82 -0
- package/linthost/no_fallthrough_command_preserves_catch_break_continue_test.go +66 -0
- package/linthost/no_fallthrough_command_preserves_code_path_boundaries_test.go +136 -0
- package/linthost/no_fallthrough_command_preserves_jsx_code_path_boundaries_test.go +68 -0
- package/linthost/no_fallthrough_command_preserves_markers_across_catch_reachability_test.go +40 -0
- package/linthost/no_fallthrough_command_tracks_binding_reference_edges_test.go +70 -0
- package/linthost/no_fallthrough_command_tracks_return_exception_edges_test.go +79 -0
- package/linthost/no_fallthrough_custom_pattern_replaces_default_marker_test.go +32 -0
- package/linthost/no_fallthrough_directive_suppression_still_wins_test.go +32 -0
- package/linthost/no_fallthrough_helpers_test.go +55 -0
- package/linthost/no_fallthrough_honors_custom_comment_pattern_test.go +30 -0
- package/linthost/no_fallthrough_ignores_switch_without_clauses_test.go +24 -0
- package/linthost/no_fallthrough_ignores_trailing_unreachable_statements_test.go +33 -0
- package/linthost/no_fallthrough_ignores_unreachable_break_in_infinite_loop_test.go +35 -0
- package/linthost/no_fallthrough_invalid_comment_pattern_falls_back_to_default_test.go +31 -0
- package/linthost/no_fallthrough_never_reports_last_open_case_test.go +27 -0
- package/linthost/no_fallthrough_rejects_breakable_conditional_while_test.go +33 -0
- package/linthost/no_fallthrough_rejects_directive_comment_as_marker_test.go +31 -0
- package/linthost/no_fallthrough_rejects_do_while_exited_by_labeled_continue_test.go +34 -0
- package/linthost/no_fallthrough_rejects_do_while_exited_by_unlabeled_continue_test.go +33 -0
- package/linthost/no_fallthrough_rejects_do_while_with_break_test.go +32 -0
- package/linthost/no_fallthrough_rejects_empty_case_followed_by_blank_line_test.go +30 -0
- package/linthost/no_fallthrough_rejects_empty_case_with_comment_line_gap_test.go +31 -0
- package/linthost/no_fallthrough_rejects_empty_statement_case_despite_allow_empty_case_test.go +29 -0
- package/linthost/no_fallthrough_rejects_for_of_with_always_throwing_body_test.go +33 -0
- package/linthost/no_fallthrough_rejects_if_else_with_one_open_branch_test.go +36 -0
- package/linthost/no_fallthrough_rejects_if_without_else_test.go +33 -0
- package/linthost/no_fallthrough_rejects_infinite_loop_broken_by_own_label_test.go +32 -0
- package/linthost/no_fallthrough_rejects_infinite_while_containing_break_test.go +32 -0
- package/linthost/no_fallthrough_rejects_labeled_block_broken_by_own_label_test.go +33 -0
- package/linthost/no_fallthrough_rejects_lint_directive_comment_as_marker_test.go +31 -0
- package/linthost/no_fallthrough_rejects_marker_before_last_statement_test.go +32 -0
- package/linthost/no_fallthrough_rejects_marker_in_block_that_is_not_sole_statement_test.go +31 -0
- package/linthost/no_fallthrough_rejects_marker_inside_nested_inner_block_test.go +31 -0
- package/linthost/no_fallthrough_rejects_nested_switch_exited_by_inner_break_test.go +34 -0
- package/linthost/no_fallthrough_rejects_nested_switch_without_default_test.go +36 -0
- package/linthost/no_fallthrough_rejects_non_literal_constant_condition_test.go +33 -0
- package/linthost/no_fallthrough_rejects_normally_completing_catch_test.go +34 -0
- package/linthost/no_fallthrough_rejects_open_try_with_normal_finally_test.go +34 -0
- package/linthost/no_fallthrough_rejects_return_inside_arrow_test.go +32 -0
- package/linthost/no_fallthrough_rejects_return_inside_function_declaration_test.go +33 -0
- package/linthost/no_fallthrough_rejects_return_inside_function_expression_test.go +33 -0
- package/linthost/no_fallthrough_rejects_unrelated_comment_in_sole_empty_block_test.go +29 -0
- package/linthost/no_fallthrough_rejects_unrelated_trailing_comment_test.go +30 -0
- package/linthost/no_fallthrough_reports_case_message_after_leading_default_test.go +37 -0
- package/linthost/no_fallthrough_reports_default_message_for_default_clause_test.go +35 -0
- package/linthost/no_fallthrough_reports_each_unmarked_transition_once_test.go +32 -0
- package/linthost/no_fallthrough_reports_inner_and_outer_switch_transitions_test.go +37 -0
- package/linthost/no_fallthrough_reports_unused_comment_after_terminating_if_else_test.go +46 -0
- package/linthost/no_fallthrough_reports_unused_comment_inside_sole_block_test.go +36 -0
- package/linthost/no_fallthrough_reports_unused_fallthrough_comment_test.go +38 -0
- package/linthost/no_fallthrough_reports_unused_marker_after_unreachable_catch_test.go +37 -0
- package/linthost/no_fallthrough_requires_marker_to_be_last_comment_test.go +32 -0
- package/linthost/no_fallthrough_unused_check_accepts_real_fallthrough_marker_test.go +30 -0
- package/linthost/no_fallthrough_unused_check_ignores_non_marker_comment_test.go +31 -0
- package/linthost/no_fallthrough_unused_check_skips_last_case_marker_test.go +28 -0
- package/linthost/no_fallthrough_unused_check_skips_reachable_empty_case_test.go +30 -0
- package/linthost/no_fallthrough_unused_comment_ignored_by_default_test.go +31 -0
- package/linthost/no_floating_promises_credits_a_handler_through_an_optional_chain_test.go +55 -0
- package/linthost/no_floating_promises_default_semantics_test.go +48 -0
- package/linthost/no_floating_promises_detects_index_value_type_parameters_test.go +145 -0
- package/linthost/no_floating_promises_handler_chains_test.go +53 -0
- package/linthost/no_floating_promises_helpers_test.go +43 -0
- package/linthost/no_floating_promises_iife_test.go +32 -0
- package/linthost/no_floating_promises_javascript_generic_defaults_test.go +177 -0
- package/linthost/no_floating_promises_mixed_receiver_results_test.go +222 -0
- package/linthost/no_floating_promises_options_test.go +56 -0
- package/linthost/no_floating_promises_preserves_call_resolution_test.go +291 -0
- package/linthost/no_floating_promises_preserves_candidate_context_literals_test.go +289 -0
- package/linthost/no_floating_promises_preserves_contextual_callback_returns_test.go +208 -0
- package/linthost/no_floating_promises_preserves_migrated_default_contexts_test.go +20 -0
- package/linthost/no_floating_promises_preserves_optional_callback_overloads_test.go +42 -0
- package/linthost/no_floating_promises_preserves_subtype_overload_priority_test.go +40 -0
- package/linthost/no_floating_promises_rejects_inapplicable_generic_receiver_branches_test.go +254 -0
- package/linthost/no_floating_promises_rejects_opaque_mapped_type_parameters_test.go +159 -0
- package/linthost/no_floating_promises_safe_calls_in_composites_specifiers_test.go +43 -0
- package/linthost/no_floating_promises_safe_calls_in_composites_test.go +88 -0
- package/linthost/no_floating_promises_specifiers_test.go +108 -0
- package/linthost/no_floating_promises_test.go +46 -0
- package/linthost/no_floating_promises_thenable_scope_follows_check_thenables_test.go +87 -0
- package/linthost/no_floating_promises_type_shapes_test.go +100 -0
- package/linthost/no_for_in_array_test.go +49 -0
- package/linthost/no_func_assign_test.go +195 -0
- package/linthost/no_import_assign_binding_identity_and_complete_writes_test.go +140 -0
- package/linthost/no_import_assign_binding_identity_helpers_test.go +114 -0
- package/linthost/no_import_assign_ignores_resolved_shadows_and_deeper_values_test.go +118 -0
- package/linthost/no_import_assign_recognizes_every_assignment_operator_test.go +36 -0
- package/linthost/no_import_assign_test.go +48 -0
- package/linthost/no_inner_declarations_both_mode_test.go +73 -0
- package/linthost/no_inner_declarations_default_allows_strict_script_block_functions_test.go +33 -0
- package/linthost/no_inner_declarations_default_module_test.go +35 -0
- package/linthost/no_inner_declarations_default_strict_context_test.go +93 -0
- package/linthost/no_inner_declarations_disallow_block_functions_test.go +57 -0
- package/linthost/no_inner_declarations_helpers_test.go +32 -0
- package/linthost/no_invalid_this_accepts_class_field_initializers_test.go +32 -0
- package/linthost/no_irregular_whitespace_allows_string_literals_and_reports_code_test.go +44 -0
- package/linthost/no_loop_func_allows_safe_bindings_and_excluded_headers_test.go +67 -0
- package/linthost/no_loop_func_allows_using_bindings_test.go +52 -0
- package/linthost/no_loop_func_checks_all_runtime_function_forms_test.go +52 -0
- package/linthost/no_loop_func_helpers_test.go +55 -0
- package/linthost/no_loop_func_iife_boundaries_test.go +41 -0
- package/linthost/no_loop_func_reports_only_unsafe_references_test.go +83 -0
- package/linthost/no_loop_func_test.go +68 -0
- package/linthost/no_loop_func_tracks_write_forms_and_symbol_identity_test.go +49 -0
- package/linthost/no_loop_func_treats_class_field_initializers_as_variable_scopes_test.go +46 -0
- package/linthost/no_loss_of_precision_accepts_exact_unsafe_integer_test.go +36 -0
- package/linthost/no_loss_of_precision_handles_every_number_syntax_test.go +93 -0
- package/linthost/no_loss_of_precision_rejects_huge_decimal_integer_test.go +28 -0
- package/linthost/no_meaningless_void_operator_test.go +48 -0
- package/linthost/no_misused_promises_arguments_test.go +82 -0
- package/linthost/no_misused_promises_defaults_test.go +89 -0
- package/linthost/no_misused_promises_helpers_test.go +135 -0
- package/linthost/no_misused_promises_native_array_predicates_test.go +91 -0
- package/linthost/no_misused_promises_options_test.go +103 -0
- package/linthost/no_misused_promises_preserves_migrated_default_contexts_test.go +23 -0
- package/linthost/no_misused_promises_test.go +53 -0
- package/linthost/no_mixed_operators_allow_same_precedence_false_flags_additive_test.go +42 -0
- package/linthost/no_mixed_operators_allows_bitwise_beside_comparison_test.go +26 -0
- package/linthost/no_mixed_operators_allows_bitwise_beside_logical_test.go +25 -0
- package/linthost/no_mixed_operators_allows_parenthesized_inner_test.go +27 -0
- package/linthost/no_mixed_operators_allows_relational_same_precedence_test.go +27 -0
- package/linthost/no_mixed_operators_allows_same_operator_chain_test.go +26 -0
- package/linthost/no_mixed_operators_allows_same_precedence_multiplicative_test.go +26 -0
- package/linthost/no_mixed_operators_allows_ternary_beside_logical_by_default_test.go +27 -0
- package/linthost/no_mixed_operators_custom_groups_omitting_arithmetic_allow_test.go +28 -0
- package/linthost/no_mixed_operators_custom_groups_ternary_flags_logical_test.go +43 -0
- package/linthost/no_mixed_operators_flags_logical_and_left_of_or_test.go +27 -0
- package/linthost/no_mixed_operators_flags_logical_and_right_of_or_test.go +27 -0
- package/linthost/no_mixed_operators_flags_multiplicative_within_additive_test.go +26 -0
- package/linthost/no_mixed_operators_flags_relational_within_equality_test.go +28 -0
- package/linthost/no_mixed_operators_flags_shift_within_bitwise_test.go +28 -0
- package/linthost/no_mixed_operators_reports_both_operator_tokens_test.go +60 -0
- package/linthost/no_namespace_exempts_global_augmentation_test.go +52 -0
- package/linthost/no_param_reassign_complete_semantics_test.go +75 -0
- package/linthost/no_param_reassign_default_props_leaves_property_writes_alone_test.go +38 -0
- package/linthost/no_param_reassign_helpers_test.go +63 -0
- package/linthost/no_param_reassign_options_validation_helpers_test.go +12 -0
- package/linthost/no_param_reassign_options_validation_test.go +58 -0
- package/linthost/no_param_reassign_options_validator_rejects_every_invalid_schema_boundary_test.go +109 -0
- package/linthost/no_param_reassign_props_follows_official_mutation_boundaries_and_ignores_test.go +89 -0
- package/linthost/no_param_reassign_test.go +52 -0
- package/linthost/no_param_reassign_uses_checker_identity_across_nested_scopes_test.go +73 -0
- package/linthost/no_promise_executor_return_allow_void_test.go +80 -0
- package/linthost/no_promise_executor_return_complete_semantics_test.go +145 -0
- package/linthost/no_promise_executor_return_test.go +35 -0
- package/linthost/no_promise_in_fire_event_test.go +36 -0
- package/linthost/no_redeclare_relates_first_definition_test.go +55 -0
- package/linthost/no_render_in_lifecycle_test.go +35 -0
- package/linthost/no_restricted_imports_allow_type_imports_handles_whole_and_inline_type_syntax_test.go +57 -0
- package/linthost/no_restricted_imports_allowed_name_pattern_covers_imports_and_reexports_test.go +32 -0
- package/linthost/no_restricted_imports_allowed_names_reject_only_the_complement_test.go +43 -0
- package/linthost/no_restricted_imports_exact_paths_cover_every_static_module_form_test.go +77 -0
- package/linthost/no_restricted_imports_exact_paths_preserve_module_specifier_whitespace_test.go +31 -0
- package/linthost/no_restricted_imports_groups_keep_gitignore_anchors_globstars_and_unicode_test.go +78 -0
- package/linthost/no_restricted_imports_matches_source_names_and_reports_exact_specifier_ranges_test.go +71 -0
- package/linthost/no_restricted_imports_missing_and_empty_restrictions_are_no_op_test.go +42 -0
- package/linthost/no_restricted_imports_options_helpers_test.go +76 -0
- package/linthost/no_restricted_imports_patterns_honor_negation_case_regex_and_name_patterns_test.go +46 -0
- package/linthost/no_restricted_imports_positional_paths_do_not_reach_dynamic_imports_test.go +32 -0
- package/linthost/no_restricted_imports_string_patterns_keep_gitignore_parent_negation_semantics_test.go +30 -0
- package/linthost/no_restricted_imports_test.go +14 -0
- package/linthost/no_restricted_imports_validator_accepts_every_official_option_branch_test.go +48 -0
- package/linthost/no_restricted_imports_validator_rejects_malformed_configuration_at_the_boundary_test.go +64 -0
- package/linthost/no_restricted_syntax_applies_every_configured_entry_and_custom_message_test.go +45 -0
- package/linthost/no_restricted_syntax_checks_structured_option_uniqueness_by_fields_test.go +40 -0
- package/linthost/no_restricted_syntax_coerces_empty_node_lists_for_numeric_comparisons_test.go +34 -0
- package/linthost/no_restricted_syntax_compares_strings_as_utf16_test.go +37 -0
- package/linthost/no_restricted_syntax_distinguishes_assignment_patterns_from_literals_test.go +81 -0
- package/linthost/no_restricted_syntax_distinguishes_object_binding_properties_from_rest_test.go +44 -0
- package/linthost/no_restricted_syntax_distinguishes_rest_and_spread_aliases_test.go +54 -0
- package/linthost/no_restricted_syntax_exposes_computed_keys_and_property_value_paths_test.go +34 -0
- package/linthost/no_restricted_syntax_exposes_scalar_statement_bodies_test.go +43 -0
- package/linthost/no_restricted_syntax_exposes_switch_case_test_and_consequent_test.go +36 -0
- package/linthost/no_restricted_syntax_helpers_test.go +56 -0
- package/linthost/no_restricted_syntax_inherits_declare_from_variable_statements_test.go +42 -0
- package/linthost/no_restricted_syntax_keeps_template_and_literal_aliases_distinct_test.go +32 -0
- package/linthost/no_restricted_syntax_limits_boolean_properties_and_es_tree_aliases_test.go +51 -0
- package/linthost/no_restricted_syntax_matches_attributes_nested_paths_regex_types_and_lengths_test.go +47 -0
- package/linthost/no_restricted_syntax_matches_classes_alternatives_and_type_script_nodes_test.go +61 -0
- package/linthost/no_restricted_syntax_matches_combinators_fields_pseudos_and_subjects_test.go +111 -0
- package/linthost/no_restricted_syntax_matches_indexed_paths_literal_types_and_prefix_test.go +169 -0
- package/linthost/no_restricted_syntax_preserves_null_across_nested_paths_test.go +35 -0
- package/linthost/no_restricted_syntax_rejects_invalid_configuration_before_dispatch_test.go +58 -0
- package/linthost/no_restricted_syntax_reports_matches_in_source_order_test.go +36 -0
- package/linthost/no_restricted_syntax_stringifies_regular_expression_values_test.go +38 -0
- package/linthost/no_restricted_syntax_test.go +29 -0
- package/linthost/no_restricted_syntax_uses_the_last_message_for_a_repeated_selector_test.go +37 -0
- package/linthost/no_restricted_types_external_config_validates_at_engine_binding_test.go +39 -0
- package/linthost/no_restricted_types_fixes_whole_qualified_generic_and_empty_type_surfaces_test.go +56 -0
- package/linthost/no_restricted_types_has_no_implicit_defaults_test.go +51 -0
- package/linthost/no_restricted_types_helpers_test.go +63 -0
- package/linthost/no_restricted_types_later_whitespace_equivalent_key_wins_test.go +40 -0
- package/linthost/no_restricted_types_matches_every_official_type_surface_exactly_test.go +144 -0
- package/linthost/no_restricted_types_options_accept_complete_runtime_schema_test.go +54 -0
- package/linthost/no_restricted_types_options_reject_malformed_schema_boundaries_test.go +60 -0
- package/linthost/no_restricted_types_rejects_only_exact_type_syntax_test.go +56 -0
- package/linthost/no_restricted_types_runs_on_declaration_files_test.go +36 -0
- package/linthost/no_restricted_types_structured_policy_provides_fix_and_every_suggestion_test.go +172 -0
- package/linthost/no_restricted_types_uses_configured_surface_spelling_across_symbols_test.go +74 -0
- package/linthost/no_restricted_types_validation_helpers_test.go +12 -0
- package/linthost/no_return_assign_allows_parenthesized_assignment_test.go +91 -0
- package/linthost/no_types_test.go +29 -0
- package/linthost/no_undef_init_ignores_const_declarations_test.go +33 -0
- package/linthost/no_uninstalled_addons_test.go +45 -0
- package/linthost/no_unnecessary_act_test.go +38 -0
- package/linthost/no_unnecessary_boolean_literal_compare_test.go +50 -0
- package/linthost/no_unnecessary_condition_test.go +50 -0
- package/linthost/no_unnecessary_qualifier_test.go +121 -0
- package/linthost/no_unnecessary_template_expression_test.go +48 -0
- package/linthost/no_unnecessary_type_arguments_leaves_unresolved_aliases_alone_test.go +42 -0
- package/linthost/no_unnecessary_type_arguments_preserves_callable_semantics_test.go +98 -0
- package/linthost/no_unnecessary_type_arguments_preserves_heritage_defaults_test.go +38 -0
- package/linthost/no_unnecessary_type_arguments_resolves_imported_aliases_test.go +58 -0
- package/linthost/no_unnecessary_type_arguments_test.go +49 -0
- package/linthost/no_unnecessary_type_assertion_test.go +48 -0
- package/linthost/no_unneeded_ternary_fix_false_true_branches_test.go +34 -0
- package/linthost/no_unneeded_ternary_fix_false_true_with_low_precedence_cond_test.go +29 -0
- package/linthost/no_unneeded_ternary_fix_true_false_branches_test.go +28 -0
- package/linthost/no_unneeded_ternary_uses_intrinsic_boolean_coercion_test.go +28 -0
- package/linthost/no_unreachable_reports_one_region_and_exempts_hoisted_declarations_test.go +50 -0
- package/linthost/no_unsafe_argument_test.go +50 -0
- package/linthost/no_unsafe_assignment_aliases_test.go +28 -0
- package/linthost/no_unsafe_assignment_array_destructuring_test.go +33 -0
- package/linthost/no_unsafe_assignment_array_spreads_test.go +29 -0
- package/linthost/no_unsafe_assignment_binding_defaults_test.go +39 -0
- package/linthost/no_unsafe_assignment_class_initializers_test.go +30 -0
- package/linthost/no_unsafe_assignment_destructuring_reassignment_test.go +33 -0
- package/linthost/no_unsafe_assignment_direct_declarations_test.go +28 -0
- package/linthost/no_unsafe_assignment_empty_map_test.go +26 -0
- package/linthost/no_unsafe_assignment_generic_constraints_test.go +33 -0
- package/linthost/no_unsafe_assignment_helpers_test.go +114 -0
- package/linthost/no_unsafe_assignment_jsx_attributes_test.go +31 -0
- package/linthost/no_unsafe_assignment_mapped_types_test.go +29 -0
- package/linthost/no_unsafe_assignment_object_destructuring_test.go +43 -0
- package/linthost/no_unsafe_assignment_object_literals_test.go +31 -0
- package/linthost/no_unsafe_assignment_parameter_defaults_test.go +37 -0
- package/linthost/no_unsafe_assignment_preserves_migrated_assignment_sites_test.go +42 -0
- package/linthost/no_unsafe_assignment_readonly_arrays_test.go +27 -0
- package/linthost/no_unsafe_assignment_reassignment_test.go +29 -0
- package/linthost/no_unsafe_assignment_recursive_generics_test.go +26 -0
- package/linthost/no_unsafe_assignment_recursive_types_test.go +30 -0
- package/linthost/no_unsafe_assignment_tuples_test.go +26 -0
- package/linthost/no_unsafe_assignment_unions_intersections_test.go +40 -0
- package/linthost/no_unsafe_call_test.go +49 -0
- package/linthost/no_unsafe_enum_comparison_test.go +51 -0
- package/linthost/no_unsafe_finally_resolves_jump_targets_inside_and_outside_the_finally_test.go +40 -0
- package/linthost/no_unsafe_member_access_test.go +50 -0
- package/linthost/no_unsafe_optional_chaining_preserves_contiguous_chain_test.go +28 -0
- package/linthost/no_unsafe_return_test.go +52 -0
- package/linthost/no_unsafe_unary_minus_test.go +47 -0
- package/linthost/no_unused_expressions_allows_jsx_by_default_test.go +38 -0
- package/linthost/no_unused_expressions_allows_productive_kinds_test.go +61 -0
- package/linthost/no_unused_expressions_composes_short_circuit_and_ternary_test.go +60 -0
- package/linthost/no_unused_expressions_directive_prologue_positions_test.go +63 -0
- package/linthost/no_unused_expressions_honors_allow_short_circuit_test.go +59 -0
- package/linthost/no_unused_expressions_honors_allow_tagged_templates_test.go +52 -0
- package/linthost/no_unused_expressions_honors_allow_ternary_test.go +58 -0
- package/linthost/no_unused_expressions_honors_enforce_for_jsx_test.go +56 -0
- package/linthost/no_unused_expressions_honors_ignore_directives_test.go +62 -0
- package/linthost/no_unused_expressions_preserves_migrated_default_controls_test.go +29 -0
- package/linthost/no_unused_expressions_ts_wrappers_inherit_classification_test.go +61 -0
- package/linthost/no_useless_catch_reports_a_rethrowing_catch_with_and_without_finally_test.go +42 -0
- package/linthost/no_useless_constructor_preserves_argument_filtering_test.go +44 -0
- package/linthost/no_useless_empty_export_allows_module_marker_test.go +36 -0
- package/linthost/no_useless_escape_flags_regex_character_class_test.go +53 -0
- package/linthost/no_useless_escape_invalid_utf8_names_replacement_character_test.go +63 -0
- package/linthost/no_useless_escape_judges_quotes_and_template_escapes_by_enclosing_delimiter_test.go +58 -0
- package/linthost/no_useless_escape_message_names_decoded_rune_test.go +74 -0
- package/linthost/no_useless_escape_multibyte_range_covers_backslash_only_test.go +71 -0
- package/linthost/no_useless_escape_nested_untagged_template_in_tagged_substitution_test.go +67 -0
- package/linthost/no_useless_escape_v_flag_class_preserves_syntax_char_escapes_test.go +60 -0
- package/linthost/no_useless_rename_declines_fix_when_comment_between_names_test.go +38 -0
- package/linthost/no_useless_rename_offers_withheld_tail_deletion_as_suggestion_test.go +37 -0
- package/linthost/no_var_preserves_loop_body_retained_values_test.go +33 -0
- package/linthost/no_var_skips_ambient_declare_var_test.go +55 -0
- package/linthost/no_var_skips_declaration_file_vars_test.go +41 -0
- package/linthost/no_var_skips_using_declarations_test.go +44 -0
- package/linthost/node_config_loader_env_prepends_nearest_node_modules_test.go +51 -0
- package/linthost/node_package_manifest_from_resolves_a_relative_anchor_test.go +56 -0
- package/linthost/node_package_manifest_from_skips_a_node_modules_directory_test.go +51 -0
- package/linthost/node_platform_pair_matches_the_npm_platform_vocabulary_test.go +62 -0
- package/linthost/node_report_bounds_before_skipping_trivia_test.go +44 -0
- package/linthost/node_spans_multiple_lines_returns_false_for_nil_node_test.go +41 -0
- package/linthost/node_suggestions_preserve_owned_edit_channels_test.go +86 -0
- package/linthost/non_nullable_type_assertion_style_test.go +49 -0
- package/linthost/object_shorthand_declines_fix_when_comment_in_value_span_test.go +38 -0
- package/linthost/object_shorthand_offers_withheld_collapse_as_suggestion_test.go +37 -0
- package/linthost/only_throw_error_test.go +44 -0
- package/linthost/override_glob_matches_a_file_named_through_a_miscased_import_test.go +49 -0
- package/linthost/override_glob_stored_case_preserves_character_class_test.go +41 -0
- package/linthost/parse_config_store_accepts_severity_tuples_test.go +49 -0
- package/linthost/parse_config_store_keeps_ignores_entry_scoped_when_files_present_test.go +56 -0
- package/linthost/parse_config_store_promotes_global_ignores_alongside_rules_test.go +56 -0
- package/linthost/parse_config_store_promotes_global_ignores_with_format_block_test.go +53 -0
- package/linthost/parse_config_store_resolves_files_and_ignores_test.go +70 -0
- package/linthost/parse_external_rule_entry_preserves_three_slot_tuple_test.go +54 -0
- package/linthost/parse_external_rule_entry_treats_null_second_slot_as_no_options_test.go +35 -0
- package/linthost/parse_plugins_blank_payload_returns_nil_test.go +29 -0
- package/linthost/parse_plugins_rejects_bad_json_test.go +31 -0
- package/linthost/parse_plugins_round_trip_test.go +51 -0
- package/linthost/parse_rules_accepts_eslint_tuples_in_standard_inline_config_test.go +64 -0
- package/linthost/parse_rules_accepts_legacy_numeric_severities_test.go +44 -0
- package/linthost/parse_rules_accepts_string_severities_test.go +60 -0
- package/linthost/parse_rules_nil_treated_as_empty_test.go +35 -0
- package/linthost/parse_rules_preserves_positional_options_test.go +75 -0
- package/linthost/parse_subcommand_flags_accepts_common_flag_combinations_test.go +57 -0
- package/linthost/playwright_no_force_option_ignores_non_playwright_options_test.go +35 -0
- package/linthost/playwright_no_networkidle_ignores_non_playwright_wait_until_test.go +35 -0
- package/linthost/prefer_as_const_preserves_migrated_all_family_contexts_test.go +20 -0
- package/linthost/prefer_as_const_property_annotation_offers_exact_suggestion_test.go +41 -0
- package/linthost/prefer_as_const_variable_annotation_offers_exact_suggestion_test.go +41 -0
- package/linthost/prefer_const_allows_reads_in_destructuring_pattern_test.go +43 -0
- package/linthost/prefer_const_counts_non_null_assignment_target_by_symbol_test.go +24 -0
- package/linthost/prefer_const_counts_parenthesized_update_target_by_symbol_test.go +26 -0
- package/linthost/prefer_const_counts_write_forms_by_symbol_test.go +57 -0
- package/linthost/prefer_const_honors_destructuring_option_test.go +77 -0
- package/linthost/prefer_const_honors_ignore_read_before_assign_for_shorthand_read_test.go +30 -0
- package/linthost/prefer_const_honors_ignore_read_before_assign_test.go +58 -0
- package/linthost/prefer_const_preserves_migrated_lexical_fixture_test.go +112 -0
- package/linthost/prefer_const_test.go +57 -0
- package/linthost/prefer_const_tracks_lexical_binding_identity_test.go +60 -0
- package/linthost/prefer_explicit_assert_test.go +36 -0
- package/linthost/prefer_find_test.go +48 -0
- package/linthost/prefer_implicit_assert_test.go +36 -0
- package/linthost/prefer_includes_test.go +49 -0
- package/linthost/prefer_presence_queries_test.go +37 -0
- package/linthost/prefer_promise_reject_errors_test.go +45 -0
- package/linthost/prefer_query_by_disappearance_test.go +35 -0
- package/linthost/prefer_query_matchers_test.go +37 -0
- package/linthost/prefer_readonly_preserves_mutated_private_fields_test.go +57 -0
- package/linthost/prefer_reduce_type_parameter_test.go +56 -0
- package/linthost/prefer_regexp_exec_test.go +48 -0
- package/linthost/prefer_return_this_type_requires_all_completion_paths_test.go +43 -0
- package/linthost/prefer_return_this_type_test.go +55 -0
- package/linthost/prefer_screen_queries_test.go +39 -0
- package/linthost/prefer_string_starts_ends_with_test.go +52 -0
- package/linthost/prefer_template_declines_fix_when_comment_in_concat_span_test.go +50 -0
- package/linthost/prefer_template_fix_embeds_numeric_subchain_as_single_slot_test.go +33 -0
- package/linthost/prefer_template_fix_escapes_backtick_in_literal_test.go +32 -0
- package/linthost/prefer_template_fix_escapes_dollar_brace_seam_test.go +33 -0
- package/linthost/prefer_template_fix_flattens_operands_after_leading_string_test.go +34 -0
- package/linthost/prefer_template_fix_ignores_string_under_other_operator_test.go +32 -0
- package/linthost/prefer_template_fix_keeps_parenthesized_subchain_single_slot_test.go +32 -0
- package/linthost/prefer_template_fix_leading_identifier_chain_test.go +30 -0
- package/linthost/prefer_template_fix_preserves_carriage_return_test.go +33 -0
- package/linthost/prefer_template_fix_preserves_newline_test.go +30 -0
- package/linthost/prefer_template_fix_preserves_template_operand_group_test.go +27 -0
- package/linthost/prefer_template_fix_renders_empty_string_operand_with_default_coercion_test.go +31 -0
- package/linthost/prefer_template_fix_sees_string_through_parens_when_flattening_test.go +34 -0
- package/linthost/prefer_template_fix_three_part_concat_test.go +31 -0
- package/linthost/prefer_template_offers_withheld_template_as_suggestion_test.go +37 -0
- package/linthost/prefer_template_preserves_default_coercion_hint_test.go +30 -0
- package/linthost/prefer_template_skips_all_literal_chain_test.go +27 -0
- package/linthost/prefer_template_skips_numeric_only_chain_test.go +28 -0
- package/linthost/prefer_user_event_setup_ignores_setup_call_test.go +35 -0
- package/linthost/print_arg_list_emits_trailing_comma_when_mode_all_test.go +38 -0
- package/linthost/print_arg_list_omits_trailing_comma_when_mode_es5_test.go +39 -0
- package/linthost/print_arg_list_omits_trailing_comma_when_mode_none_test.go +39 -0
- package/linthost/print_arg_list_returns_parens_for_nil_list_test.go +30 -0
- package/linthost/print_call_expression_falls_back_verbatim_when_args_contain_nil_test.go +43 -0
- package/linthost/print_call_expression_includes_question_dot_token_test.go +36 -0
- package/linthost/print_call_expression_includes_type_arguments_test.go +34 -0
- package/linthost/print_call_expression_returns_empty_for_nil_node_test.go +29 -0
- package/linthost/print_dispatch.go +50 -15
- package/linthost/print_doc.go +206 -41
- package/linthost/print_engine.go +78 -51
- package/linthost/print_new_expression_falls_back_verbatim_when_args_contain_nil_test.go +42 -0
- package/linthost/print_new_expression_includes_type_arguments_test.go +36 -0
- package/linthost/print_new_expression_omits_argument_list_when_absent_test.go +36 -0
- package/linthost/print_new_expression_returns_empty_for_nil_node_test.go +28 -0
- package/linthost/print_node_returns_empty_for_nil_node_test.go +31 -0
- package/linthost/print_nodes_control_flow.go +4 -4
- package/linthost/print_nodes_function.go +9 -11
- package/linthost/print_nodes_imports.go +8 -11
- package/linthost/print_nodes_object.go +3 -6
- package/linthost/printer_test_helpers_test.go +46 -0
- package/linthost/project_companion_preserves_file_scoped_rule_config_test.go +45 -0
- package/linthost/project_contributor_ast_only_marker_keeps_parallel_walk_test.go +54 -0
- package/linthost/project_contributor_generic_accepts_options_method_keeps_legacy_payload_test.go +81 -0
- package/linthost/project_contributor_optionless_marker_rejects_payload_test.go +62 -0
- package/linthost/project_contributor_without_marker_keeps_options_compatibility_test.go +70 -0
- package/linthost/project_contributor_without_marker_keeps_type_checker_test.go +53 -0
- package/linthost/project_engine.go +8 -0
- package/linthost/project_hint_collection_requires_passed_published_state_test.go +105 -0
- package/linthost/project_hint_publication_filters_malformed_and_recovers_panic_test.go +66 -0
- package/linthost/project_identity_mints_distinct_program_lifecycles_test.go +51 -0
- package/linthost/project_input_reader.go +358 -0
- package/linthost/project_input_snapshot_normalizes_windows_case_and_separators_test.go +43 -0
- package/linthost/project_input_snapshot_preserves_missing_files_zero_match_globs_and_config_provenance_test.go +130 -0
- package/linthost/project_input_snapshot_reconciles_options_and_physical_paths_test.go +108 -0
- package/linthost/project_input_snapshot_rejects_remote_urls_test.go +59 -0
- package/linthost/project_inputs.go +31 -4
- package/linthost/project_inputs_command_publishes_configured_snapshot_without_program_test.go +115 -0
- package/linthost/project_rule_config_folds_global_extends_and_options_test.go +68 -0
- package/linthost/project_rule_config_rejects_any_files_selector_test.go +46 -0
- package/linthost/project_rule_live_reports_are_concurrent_and_deterministic_test.go +89 -0
- package/linthost/project_rule_reports_per_finding_severity_test.go +74 -0
- package/linthost/project_rule_results_reach_public_file_context_test.go +172 -0
- package/linthost/project_rule_runs_for_empty_source_set_test.go +52 -0
- package/linthost/project_rule_sources_apply_only_global_ignores_test.go +62 -0
- package/linthost/project_rule_sources_include_imported_sibling_source_test.go +110 -0
- package/linthost/project_rule_state_and_live_failure_reach_file_dispatch_test.go +89 -0
- package/linthost/project_rule_state_and_reporter_are_isolated_between_cycles_test.go +87 -0
- package/linthost/project_source_files_follow_tsconfig_selection_test.go +86 -0
- package/linthost/project_source_selection_preserves_explicit_bundled_roots_test.go +73 -0
- package/linthost/promise_function_async_test.go +49 -0
- package/linthost/public_rule_context_accepts_legacy_reporter_test.go +50 -0
- package/linthost/public_rule_context_legacy_reporter_drops_fix_edits_test.go +57 -0
- package/linthost/public_rule_context_options_are_isolated_test.go +106 -0
- package/linthost/public_rule_context_report_fix_falls_back_when_no_edits_test.go +39 -0
- package/linthost/public_rule_context_report_fix_forwards_to_fixreporter_test.go +102 -0
- package/linthost/public_rule_context_report_fix_off_severity_drops_silently_test.go +41 -0
- package/linthost/public_rule_context_report_fix_skips_nil_node_test.go +34 -0
- package/linthost/public_rule_context_report_range_fix_falls_back_when_no_edits_test.go +38 -0
- package/linthost/public_rule_context_report_range_fix_forwards_to_fixreporter_test.go +49 -0
- package/linthost/public_rule_context_report_related_falls_back_test.go +58 -0
- package/linthost/public_rule_context_report_related_forwards_test.go +108 -0
- package/linthost/public_rule_context_report_suggestion_falls_back_when_unsupported_test.go +41 -0
- package/linthost/public_rule_context_report_suggestion_forwards_to_suggestionreporter_test.go +97 -0
- package/linthost/public_rule_context_report_suggestion_with_no_choices_reports_test.go +33 -0
- package/linthost/radix_accepts_every_integer_radix_from_two_through_thirty_six_test.go +33 -0
- package/linthost/range_suggestion_finding_uses_canonical_bounds_test.go +47 -0
- package/linthost/react_button_has_type_requires_explicit_type_test.go +22 -0
- package/linthost/react_compiler_subset_reports_local_purity_violations_test.go +72 -0
- package/linthost/react_display_name_reports_anonymous_memo_test.go +25 -0
- package/linthost/react_exhaustive_deps_reports_missing_identifiers_test.go +58 -0
- package/linthost/react_helpers_test.go +36 -0
- package/linthost/react_iframe_missing_sandbox_reports_iframe_test.go +21 -0
- package/linthost/react_jsx_key_reports_array_element_test.go +21 -0
- package/linthost/react_jsx_key_reports_conditional_map_element_test.go +23 -0
- package/linthost/react_jsx_key_reports_logical_map_element_test.go +23 -0
- package/linthost/react_jsx_no_duplicate_props_reports_duplicate_test.go +21 -0
- package/linthost/react_jsx_no_script_url_reports_javascript_href_test.go +20 -0
- package/linthost/react_jsx_no_target_blank_reports_missing_rel_test.go +22 -0
- package/linthost/react_jsx_no_undef_declarations_collected_once_per_file_test.go +63 -0
- package/linthost/react_jsx_no_undef_reports_undeclared_component_test.go +25 -0
- package/linthost/react_jsx_no_undef_skips_declared_components_test.go +46 -0
- package/linthost/react_jsx_no_useless_fragment_test.go +29 -0
- package/linthost/react_no_array_index_key_reports_index_key_test.go +21 -0
- package/linthost/react_no_array_index_key_reports_renamed_index_key_test.go +23 -0
- package/linthost/react_no_array_index_key_skips_nested_non_list_element_test.go +22 -0
- package/linthost/react_no_array_index_key_skips_unrelated_index_identifier_test.go +21 -0
- package/linthost/react_no_children_prop_reports_children_prop_test.go +21 -0
- package/linthost/react_no_danger_reports_dangerously_set_inner_html_test.go +21 -0
- package/linthost/react_no_danger_with_children_reports_mixed_content_test.go +22 -0
- package/linthost/react_no_danger_with_children_survives_spread_props_test.go +23 -0
- package/linthost/react_no_direct_mutation_state_reports_state_property_write_test.go +22 -0
- package/linthost/react_no_find_dom_node_reports_call_test.go +20 -0
- package/linthost/react_no_is_mounted_reports_call_test.go +20 -0
- package/linthost/react_no_string_refs_reports_string_ref_test.go +20 -0
- package/linthost/react_no_unescaped_entities_reports_quote_text_test.go +21 -0
- package/linthost/react_only_export_components_honors_allow_options_test.go +41 -0
- package/linthost/react_only_export_components_reports_non_component_export_test.go +41 -0
- package/linthost/react_perf_helpers_test.go +58 -0
- package/linthost/react_perf_jsx_no_jsx_as_prop_test.go +29 -0
- package/linthost/react_perf_jsx_no_new_array_as_prop_test.go +30 -0
- package/linthost/react_perf_jsx_no_new_function_as_prop_test.go +31 -0
- package/linthost/react_perf_jsx_no_new_object_as_prop_test.go +31 -0
- package/linthost/react_perf_native_allow_list_test.go +49 -0
- package/linthost/react_perf_rules_skip_jsx_source_test.go +29 -0
- package/linthost/react_rules_of_hooks_rejects_hook_after_conditional_return_test.go +54 -0
- package/linthost/react_rules_of_hooks_rejects_invalid_call_sites_test.go +65 -0
- package/linthost/react_source_file_rules_handle_tsx_descendants_test.go +77 -0
- package/linthost/react_state_setters_reject_render_and_effect_calls_test.go +62 -0
- package/linthost/react_style_prop_object_reports_string_style_test.go +22 -0
- package/linthost/react_void_dom_elements_no_children_reports_img_child_test.go +22 -0
- package/linthost/regex_optimizer_distinguishes_a_zero_upper_bound_from_an_open_range_test.go +44 -0
- package/linthost/regex_optimizer_preserves_ranges_crossing_meta_sets_test.go +67 -0
- package/linthost/regex_tree_optimizer.go +54 -10
- package/linthost/regexp_alias_rules_test.go +53 -0
- package/linthost/regexp_cache.go +63 -33
- package/linthost/regexp_character_class_and_group_rules_test.go +64 -0
- package/linthost/regexp_duplicate_class_uses_code_points_test.go +41 -0
- package/linthost/regexp_quantifier_and_flag_rules_test.go +52 -0
- package/linthost/regexp_useless_ignore_case_flag_test.go +111 -0
- package/linthost/regexp_useless_multiline_flag_test.go +71 -0
- package/linthost/register_rejects_duplicate_rule_name_test.go +74 -0
- package/linthost/reject_any_type_test.go +50 -0
- package/linthost/reject_function_type_test.go +48 -0
- package/linthost/related_getter_setter_pairs_test.go +56 -0
- package/linthost/render_result_dom_access_and_events_test.go +45 -0
- package/linthost/require_array_sort_compare_test.go +47 -0
- package/linthost/require_await_counts_for_await_and_promise_returns_test.go +76 -0
- package/linthost/require_description_test.go +29 -0
- package/linthost/require_param_description_allows_multiline_continuation_test.go +27 -0
- package/linthost/require_param_description_test.go +29 -0
- package/linthost/require_param_name_test.go +26 -0
- package/linthost/require_property_description_allows_multiline_continuation_test.go +27 -0
- package/linthost/require_property_description_test.go +30 -0
- package/linthost/require_property_name_test.go +26 -0
- package/linthost/require_returns_description_allows_multiline_continuation_test.go +27 -0
- package/linthost/require_returns_description_test.go +29 -0
- package/linthost/required_behavioral_witness_kinds_ignore_non_public_candidates_test.go +51 -0
- package/linthost/resident_apply_change_matches_cold_load_test.go +106 -0
- package/linthost/resident_cache_replaces_a_checker_free_program_when_a_checker_arrives_test.go +57 -0
- package/linthost/resident_cache_retains_program_for_declared_external_change_test.go +61 -0
- package/linthost/resident_cache_serves_a_checker_free_verb_from_the_checker_program_test.go +51 -0
- package/linthost/resident_heritage_update_rebuilds_checker_test.go +70 -0
- package/linthost/resident_regex_cache_retires_reloaded_configurations_test.go +123 -0
- package/linthost/resident_rules_are_reused_only_while_their_config_is_unchanged_test.go +180 -0
- package/linthost/resident_whole_corpus_matches_cold_load_test.go +167 -0
- package/linthost/resolve_config_file_path_uses_tsconfig_directory_test.go +34 -0
- package/linthost/resolve_config_tsgo_falls_back_to_the_project_root_anchor_test.go +36 -0
- package/linthost/resolve_config_tsgo_keeps_an_explicitly_pinned_compiler_test.go +41 -0
- package/linthost/resolve_config_tsgo_prefers_the_config_anchor_over_the_project_root_test.go +41 -0
- package/linthost/resolve_config_tsgo_resolves_the_project_compiler_without_the_environment_test.go +33 -0
- package/linthost/resolve_config_tsgo_resolves_through_a_linked_typescript_install_test.go +48 -0
- package/linthost/resolve_config_tsgo_returns_nothing_without_a_project_typescript_test.go +32 -0
- package/linthost/resolve_config_tsgo_returns_nothing_without_the_platform_package_test.go +40 -0
- package/linthost/resolve_ttsx_launcher_falls_back_to_the_bare_command_test.go +36 -0
- package/linthost/resolve_ttsx_launcher_keeps_an_explicitly_pinned_binary_test.go +40 -0
- package/linthost/resolve_ttsx_launcher_resolves_the_project_launcher_without_the_environment_test.go +33 -0
- package/linthost/restrict_plus_operands_test.go +47 -0
- package/linthost/restrict_template_expressions_test.go +47 -0
- package/linthost/return_await_test.go +54 -0
- package/linthost/rule_codes.go +16 -2
- package/linthost/rule_codes_are_unique_and_banded_across_live_registry_test.go +74 -0
- package/linthost/rule_docs.go +1 -1
- package/linthost/rule_documentation_urls_cover_the_builtin_corpus_test.go +86 -0
- package/linthost/rule_snapshot_engine_requires_a_valid_active_rule_test.go +59 -0
- package/linthost/rules_boundaries.go +19 -7
- package/linthost/rules_consistent_return.go +323 -16
- package/linthost/rules_core_extra.go +41 -82
- package/linthost/rules_default_case.go +1 -1
- package/linthost/rules_escape.go +18 -3
- package/linthost/rules_finally.go +49 -15
- package/linthost/rules_format_arrow_parens.go +8 -10
- package/linthost/rules_format_bracket_spacing.go +14 -19
- package/linthost/rules_format_print_width.go +28 -19
- package/linthost/rules_format_quote_props.go +5 -11
- package/linthost/rules_format_quotes.go +5 -6
- package/linthost/rules_format_sort_imports.go +27 -15
- package/linthost/rules_format_statement_split.go +3 -5
- package/linthost/rules_functional.go +21 -14
- package/linthost/rules_gap.go +9 -12
- package/linthost/rules_jsdoc.go +2 -3
- package/linthost/rules_jsx_a11y.go +2 -0
- package/linthost/rules_logic.go +88 -11
- package/linthost/rules_loops.go +16 -2
- package/linthost/rules_max_nested_callbacks.go +28 -12
- package/linthost/rules_misc.go +38 -8
- package/linthost/rules_no_extend_native.go +52 -13
- package/linthost/rules_no_fallthrough.go +1 -1
- package/linthost/rules_no_invalid_this.go +6 -3
- package/linthost/rules_no_mixed_operators.go +42 -10
- package/linthost/rules_no_param_reassign.go +1 -1
- package/linthost/rules_no_unreachable.go +61 -2
- package/linthost/rules_no_useless_constructor.go +21 -27
- package/linthost/rules_problems.go +26 -2
- package/linthost/rules_regexp.go +76 -28
- package/linthost/rules_security.go +4 -4
- package/linthost/rules_self.go +42 -6
- package/linthost/rules_solid.go +14 -26
- package/linthost/rules_sort_keys.go +12 -14
- package/linthost/rules_storybook.go +16 -26
- package/linthost/rules_strings.go +9 -19
- package/linthost/rules_suggestions.go +79 -45
- package/linthost/rules_testing_library.go +18 -0
- package/linthost/rules_ts_no_restricted_types.go +9 -1
- package/linthost/rules_ts_no_unnecessary_type_arguments.go +44 -47
- package/linthost/rules_ts_prefer_readonly.go +111 -42
- package/linthost/rules_ts_prefer_return_this_type.go +21 -14
- package/linthost/rules_unicorn_no_unnecessary_array_splice_count.go +12 -17
- package/linthost/rules_unicorn_no_unnecessary_await.go +39 -13
- package/linthost/rules_unicorn_no_unnecessary_slice_end.go +7 -10
- package/linthost/rules_unicorn_no_useless_error_capture_stack_trace.go +29 -12
- package/linthost/rules_unicorn_no_useless_fallback_in_spread.go +7 -25
- package/linthost/rules_unicorn_no_useless_length_check.go +19 -19
- package/linthost/rules_unicorn_prefer_array_some.go +1 -2
- package/linthost/rules_unicorn_prefer_bigint_literals.go +21 -18
- package/linthost/rules_unicorn_prefer_date_now.go +7 -17
- package/linthost/rules_unicorn_prefer_default_parameters.go +7 -15
- package/linthost/rules_unicorn_prefer_logical_operator_over_ternary.go +7 -13
- package/linthost/rules_unicorn_prefer_negative_index.go +12 -13
- package/linthost/rules_unicorn_prefer_node_protocol.go +5 -5
- package/linthost/rules_unicorn_prefer_object_from_entries.go +7 -14
- package/linthost/rules_unicorn_prefer_regexp_test_rule.go +17 -19
- package/linthost/rules_unicorn_prefer_single_call.go +12 -6
- package/linthost/rules_unicorn_prefer_spread.go +7 -13
- package/linthost/rules_unicorn_prefer_string_replace_all.go +4 -3
- package/linthost/rules_unicorn_prefer_string_starts_ends_with.go +22 -3
- package/linthost/rules_unicorn_prefer_top_level_await.go +4 -3
- package/linthost/rules_unicorn_relative_url_style.go +33 -14
- package/linthost/rules_var.go +73 -3
- package/linthost/runtime_rule_codes_are_collision_free_and_order_independent_test.go +101 -0
- package/linthost/security_assigned_names_unwrap_assertion_targets_test.go +54 -0
- package/linthost/security_bindings_collected_once_per_file_test.go +63 -0
- package/linthost/security_detect_bidi_characters_test.go +44 -0
- package/linthost/security_name_based_node_api_findings_stay_untagged_test.go +87 -0
- package/linthost/self_compare_and_self_assign_ignore_calls_and_empty_template_curly_is_not_a_placeholder_test.go +50 -0
- package/linthost/semantic_finding_guard_rejects_recovered_execution_failures_test.go +75 -0
- package/linthost/serve.go +42 -25
- package/linthost/set_env_replaces_or_appends_test.go +39 -0
- package/linthost/severity_string_formats_values_test.go +34 -0
- package/linthost/signature_flags_expose_construct_signature_abstractness_test.go +136 -0
- package/linthost/signature_introspection_reaches_runtime_endpoints_test.go +123 -0
- package/linthost/solid_helpers_test.go +92 -0
- package/linthost/solid_import_proxy_and_dependency_rules_test.go +48 -0
- package/linthost/solid_imports_leaves_a_type_only_destination_alone_test.go +42 -0
- package/linthost/solid_imports_relocates_a_misrouted_specifier_test.go +69 -0
- package/linthost/solid_jsx_attribute_guards_test.go +69 -0
- package/linthost/solid_no_react_deps_tags_dependency_array_unnecessary_test.go +106 -0
- package/linthost/solid_reactivity_and_component_returns_test.go +49 -0
- package/linthost/solid_rendering_style_preferences_test.go +59 -0
- package/linthost/solid_self_closing_comp_keeps_text_children_test.go +32 -0
- package/linthost/solid_source_file_rules_handle_jsx_initializers_test.go +47 -0
- package/linthost/solid_style_prop_reports_non_zero_numeric_lengths_test.go +37 -0
- package/linthost/solid_validate_jsx_nesting_test.go +53 -0
- package/linthost/sort_keys_compares_across_a_computed_key_and_resets_at_a_spread_test.go +33 -0
- package/linthost/source_extension_tables_separate_selection_from_widening_test.go +44 -0
- package/linthost/source_has_statement_terminator_detects_semicolon_test.go +28 -0
- package/linthost/source_has_statement_terminator_returns_false_for_empty_string_test.go +27 -0
- package/linthost/source_has_statement_terminator_returns_false_for_unclosed_block_comment_test.go +31 -0
- package/linthost/source_has_statement_terminator_returns_false_when_absent_test.go +29 -0
- package/linthost/source_has_statement_terminator_skips_trailing_block_comment_test.go +30 -0
- package/linthost/source_has_statement_terminator_skips_trailing_whitespace_test.go +31 -0
- package/linthost/standalone_checker_resolves_cross_file_type_after_pooled_diagnostics_test.go +85 -0
- package/linthost/storybook_deletion_findings_tag_unnecessary_test.go +127 -0
- package/linthost/storybook_legacy_api_findings_tag_deprecated_test.go +110 -0
- package/linthost/strict_boolean_expressions_test.go +49 -0
- package/linthost/switch_exhaustiveness_check_advanced_type_shapes_test.go +83 -0
- package/linthost/switch_exhaustiveness_check_finite_members_test.go +76 -0
- package/linthost/switch_exhaustiveness_check_helpers_test.go +99 -0
- package/linthost/switch_exhaustiveness_check_no_unchecked_indexed_access_test.go +56 -0
- package/linthost/switch_exhaustiveness_check_options_test.go +118 -0
- package/linthost/switch_exhaustiveness_check_parser_comment_ranges_test.go +64 -0
- package/linthost/switch_exhaustiveness_check_preserves_migrated_defaults_and_options_test.go +139 -0
- package/linthost/switch_exhaustiveness_check_test.go +73 -0
- package/linthost/tail_is_clean_terminator_returns_false_for_invalid_inputs_test.go +64 -0
- package/linthost/testing_library_helpers_test.go +71 -0
- package/linthost/tsdoc_syntax_test.go +64 -0
- package/linthost/ttsx_command_context_spawns_the_project_launcher_test.go +47 -0
- package/linthost/type_alias_reference_node_uses_borrowed_builder_context_test.go +128 -0
- package/linthost/type_args_start_and_end_guard_branches_test.go +58 -0
- package/linthost/type_instantiation_mappers_reach_runtime_endpoints_test.go +213 -0
- package/linthost/type_mapper_parallel_substitution_avoids_capture_test.go +106 -0
- package/linthost/typed_rule_semantic_helpers_test.go +34 -0
- package/linthost/unbound_method_test.go +53 -0
- package/linthost/unicorn_array_some_requires_an_existence_comparison_test.go +29 -0
- package/linthost/unicorn_await_literal_does_not_assume_an_object_has_no_then_test.go +33 -0
- package/linthost/unicorn_better_regex_constructor_fix_escapes_cooked_pattern_test.go +146 -0
- package/linthost/unicorn_better_regex_fix_is_idempotent_test.go +37 -0
- package/linthost/unicorn_better_regex_leaves_optimal_literals_test.go +36 -0
- package/linthost/unicorn_better_regex_reports_exact_range_and_message_test.go +52 -0
- package/linthost/unicorn_better_regex_reports_without_fix_on_source_member_test.go +38 -0
- package/linthost/unicorn_better_regex_rewrites_regexp_constructor_test.go +70 -0
- package/linthost/unicorn_better_regex_skips_unicode_flag_literals_test.go +34 -0
- package/linthost/unicorn_better_regex_sort_character_classes_option_test.go +39 -0
- package/linthost/unicorn_better_regex_test.go +44 -0
- package/linthost/unicorn_bigint_literal_requires_an_exact_integer_value_test.go +34 -0
- package/linthost/unicorn_consistent_destructuring_jsx_tag_names_are_exempt_test.go +53 -0
- package/linthost/unicorn_consistent_destructuring_skips_valid_forms_test.go +221 -0
- package/linthost/unicorn_consistent_destructuring_suggestion_is_opt_in_and_idempotent_test.go +54 -0
- package/linthost/unicorn_consistent_destructuring_test.go +306 -0
- package/linthost/unicorn_consistent_existence_index_check_fix_is_idempotent_test.go +45 -0
- package/linthost/unicorn_consistent_existence_index_check_fix_rewrites_magnitude_comparisons_test.go +96 -0
- package/linthost/unicorn_consistent_existence_index_check_skips_upstream_valid_forms_test.go +143 -0
- package/linthost/unicorn_consistent_existence_index_check_test.go +212 -0
- package/linthost/unicorn_consistent_function_scoping_chains_blocks_inside_loop_bodies_test.go +53 -0
- package/linthost/unicorn_consistent_function_scoping_checks_arrow_lexical_environment_test.go +48 -0
- package/linthost/unicorn_consistent_function_scoping_checks_returned_arrow_chains_test.go +29 -0
- package/linthost/unicorn_consistent_function_scoping_honors_check_arrow_functions_test.go +42 -0
- package/linthost/unicorn_consistent_function_scoping_keeps_shared_outer_references_together_test.go +28 -0
- package/linthost/unicorn_consistent_function_scoping_outer_reference_pins_recursive_function_test.go +31 -0
- package/linthost/unicorn_consistent_function_scoping_preserves_upstream_factory_exceptions_test.go +59 -0
- package/linthost/unicorn_consistent_function_scoping_protects_super_and_private_names_test.go +57 -0
- package/linthost/unicorn_consistent_function_scoping_reads_class_head_positions_as_lexical_environment_test.go +42 -0
- package/linthost/unicorn_consistent_function_scoping_reports_canonical_head_ranges_test.go +44 -0
- package/linthost/unicorn_consistent_function_scoping_resolves_jsx_component_captures_test.go +44 -0
- package/linthost/unicorn_consistent_function_scoping_test.go +45 -0
- package/linthost/unicorn_consistent_function_scoping_treats_loop_scopes_as_one_boundary_test.go +36 -0
- package/linthost/unicorn_consistent_function_scoping_uses_binding_identity_and_ignores_self_recursion_test.go +42 -0
- package/linthost/unicorn_consistent_function_scoping_validates_the_public_option_shape_test.go +58 -0
- package/linthost/unicorn_consistent_template_literal_escape_command_fix_idempotence_test.go +41 -0
- package/linthost/unicorn_consistent_template_literal_escape_fires_on_declaration_files_test.go +35 -0
- package/linthost/unicorn_consistent_template_literal_escape_fixes_template_literal_types_test.go +35 -0
- package/linthost/unicorn_consistent_template_literal_escape_fixes_upstream_invalid_corpus_test.go +80 -0
- package/linthost/unicorn_consistent_template_literal_escape_honors_backslash_parity_test.go +64 -0
- package/linthost/unicorn_consistent_template_literal_escape_preserves_continuations_crlf_and_unicode_test.go +34 -0
- package/linthost/unicorn_consistent_template_literal_escape_reports_exact_element_ranges_test.go +71 -0
- package/linthost/unicorn_consistent_template_literal_escape_reports_untagged_inside_tagged_test.go +43 -0
- package/linthost/unicorn_consistent_template_literal_escape_skips_tagged_templates_test.go +40 -0
- package/linthost/unicorn_consistent_template_literal_escape_skips_upstream_valid_corpus_test.go +49 -0
- package/linthost/unicorn_date_now_preserves_constructor_arguments_test.go +34 -0
- package/linthost/unicorn_escape_case_bounds_escape_digit_runs_test.go +97 -0
- package/linthost/unicorn_escape_case_honors_backslash_parity_test.go +67 -0
- package/linthost/unicorn_escape_case_reports_interpolated_template_segments_test.go +97 -0
- package/linthost/unicorn_escape_case_skips_tagged_templates_test.go +62 -0
- package/linthost/unicorn_escape_family_survives_crlf_and_astral_literals_test.go +67 -0
- package/linthost/unicorn_filename_case_cases_key_order_shapes_message_test.go +42 -0
- package/linthost/unicorn_filename_case_default_ignored_index_basenames_test.go +40 -0
- package/linthost/unicorn_filename_case_directory_handling_test.go +89 -0
- package/linthost/unicorn_filename_case_extension_lowercase_test.go +72 -0
- package/linthost/unicorn_filename_case_ignore_patterns_match_segments_test.go +78 -0
- package/linthost/unicorn_filename_case_multiple_file_extensions_option_test.go +77 -0
- package/linthost/unicorn_filename_case_option_validation_test.go +74 -0
- package/linthost/unicorn_filename_case_real_project_paths_test.go +50 -0
- package/linthost/unicorn_filename_case_report_anchors_and_no_fix_test.go +59 -0
- package/linthost/unicorn_filename_case_split_name_line_terminator_edge_test.go +37 -0
- package/linthost/unicorn_filename_case_test.go +131 -0
- package/linthost/unicorn_filename_case_unicode_segments_test.go +33 -0
- package/linthost/unicorn_filename_case_upstream_invalid_filenames_test.go +268 -0
- package/linthost/unicorn_filename_case_upstream_valid_filenames_test.go +173 -0
- package/linthost/unicorn_import_style_accepts_mixed_styles_when_all_allowed_test.go +29 -0
- package/linthost/unicorn_import_style_banned_module_reports_dedicated_message_test.go +70 -0
- package/linthost/unicorn_import_style_check_toggles_disable_each_syntax_family_test.go +61 -0
- package/linthost/unicorn_import_style_default_module_policy_matrix_test.go +69 -0
- package/linthost/unicorn_import_style_default_policies_at_exact_ranges_test.go +65 -0
- package/linthost/unicorn_import_style_default_policies_skip_compliant_and_unknown_modules_test.go +37 -0
- package/linthost/unicorn_import_style_disjunction_lists_allowed_styles_in_order_test.go +44 -0
- package/linthost/unicorn_import_style_dynamic_import_expression_forms_test.go +69 -0
- package/linthost/unicorn_import_style_evaluates_static_string_module_names_test.go +58 -0
- package/linthost/unicorn_import_style_extend_default_styles_false_drops_builtin_policies_test.go +46 -0
- package/linthost/unicorn_import_style_named_module_policy_matrix_test.go +81 -0
- package/linthost/unicorn_import_style_namespace_module_policy_matrix_test.go +63 -0
- package/linthost/unicorn_import_style_object_pattern_key_forms_test.go +46 -0
- package/linthost/unicorn_import_style_optional_require_calls_are_never_classified_test.go +24 -0
- package/linthost/unicorn_import_style_rejects_malformed_options_before_linting_test.go +56 -0
- package/linthost/unicorn_import_style_reports_no_automatic_fixes_test.go +31 -0
- package/linthost/unicorn_import_style_skips_non_matching_reference_shapes_test.go +47 -0
- package/linthost/unicorn_import_style_style_overrides_replace_inherited_flags_test.go +69 -0
- package/linthost/unicorn_import_style_test.go +87 -0
- package/linthost/unicorn_import_style_type_only_imports_follow_value_semantics_test.go +53 -0
- package/linthost/unicorn_import_style_unassigned_policy_accepts_unassigned_forms_test.go +31 -0
- package/linthost/unicorn_import_style_unassigned_policy_reports_every_assigned_form_test.go +66 -0
- package/linthost/unicorn_isolated_functions_arguments_test.go +48 -0
- package/linthost/unicorn_isolated_functions_browser_and_page_callees_test.go +63 -0
- package/linthost/unicorn_isolated_functions_comments_test.go +131 -0
- package/linthost/unicorn_isolated_functions_execute_script_func_property_test.go +83 -0
- package/linthost/unicorn_isolated_functions_function_name_callees_test.go +100 -0
- package/linthost/unicorn_isolated_functions_helpers_test.go +76 -0
- package/linthost/unicorn_isolated_functions_override_globals_test.go +92 -0
- package/linthost/unicorn_isolated_functions_parameter_default_capture_test.go +47 -0
- package/linthost/unicorn_isolated_functions_scope_internals_test.go +57 -0
- package/linthost/unicorn_isolated_functions_selector_test.go +43 -0
- package/linthost/unicorn_isolated_functions_test.go +75 -0
- package/linthost/unicorn_isolated_functions_this_and_super_test.go +110 -0
- package/linthost/unicorn_isolated_functions_typeof_this_test.go +45 -0
- package/linthost/unicorn_isolated_functions_typescript_types_test.go +39 -0
- package/linthost/unicorn_isolated_functions_unresolved_reference_test.go +41 -0
- package/linthost/unicorn_known_boundary_observations_test.go +113 -0
- package/linthost/unicorn_length_check_preserves_escaped_foreach_results_test.go +33 -0
- package/linthost/unicorn_negative_index_requires_its_own_receiver_and_index_argument_test.go +32 -0
- package/linthost/unicorn_no_hex_escape_honors_backslash_parity_test.go +63 -0
- package/linthost/unicorn_no_hex_escape_ignores_non_hex_escapes_test.go +75 -0
- package/linthost/unicorn_no_hex_escape_reports_interpolated_template_segments_test.go +86 -0
- package/linthost/unicorn_no_hex_escape_skips_tagged_templates_test.go +57 -0
- package/linthost/unicorn_no_typeof_undefined_check_global_variables_option_test.go +90 -0
- package/linthost/unicorn_no_typeof_undefined_declines_unsafe_fix_test.go +50 -0
- package/linthost/unicorn_no_typeof_undefined_fix_rewrites_comparisons_test.go +43 -0
- package/linthost/unicorn_no_typeof_undefined_skips_upstream_valid_forms_test.go +57 -0
- package/linthost/unicorn_no_typeof_undefined_test.go +88 -0
- package/linthost/unicorn_no_unnecessary_polyfills_checks_only_static_string_specifiers_test.go +50 -0
- package/linthost/unicorn_no_unnecessary_polyfills_config_discovery_test.go +109 -0
- package/linthost/unicorn_no_unnecessary_polyfills_core_js_compat_oracle_test.go +74 -0
- package/linthost/unicorn_no_unnecessary_polyfills_corpus_project_scenario_test.go +30 -0
- package/linthost/unicorn_no_unnecessary_polyfills_custom_stats_discovery_test.go +45 -0
- package/linthost/unicorn_no_unnecessary_polyfills_engine_oracle_test.go +101 -0
- package/linthost/unicorn_no_unnecessary_polyfills_engines_discovery_test.go +29 -0
- package/linthost/unicorn_no_unnecessary_polyfills_option_overrides_config_discovery_test.go +28 -0
- package/linthost/unicorn_no_unnecessary_polyfills_options_test.go +38 -0
- package/linthost/unicorn_no_unnecessary_polyfills_package_json_browserslist_section_test.go +25 -0
- package/linthost/unicorn_no_unnecessary_polyfills_pattern_table_oracle_test.go +47 -0
- package/linthost/unicorn_no_unnecessary_polyfills_rejects_malformed_options_test.go +48 -0
- package/linthost/unicorn_no_unnecessary_polyfills_silent_without_resolvable_targets_test.go +26 -0
- package/linthost/unicorn_no_unnecessary_polyfills_test.go +128 -0
- package/linthost/unicorn_no_unnecessary_polyfills_upstream_invalid_targets_test.go +73 -0
- package/linthost/unicorn_no_unused_properties_corpus_test.go +81 -0
- package/linthost/unicorn_no_unused_properties_key_matching_test.go +83 -0
- package/linthost/unicorn_no_unused_properties_object_literal_semantics_test.go +211 -0
- package/linthost/unicorn_no_unused_properties_reference_identity_test.go +72 -0
- package/linthost/unicorn_no_unused_properties_reporting_shape_test.go +89 -0
- package/linthost/unicorn_no_unused_properties_script_global_scope_test.go +60 -0
- package/linthost/unicorn_no_unused_properties_template_keys_test.go +35 -0
- package/linthost/unicorn_no_unused_properties_type_literal_semantics_test.go +155 -0
- package/linthost/unicorn_number_literal_case_fix_is_idempotent_test.go +54 -0
- package/linthost/unicorn_number_literal_case_fixes_bigint_and_separated_literals_test.go +43 -0
- package/linthost/unicorn_number_literal_case_fixes_every_literal_in_one_pass_test.go +37 -0
- package/linthost/unicorn_number_literal_case_fixes_literals_in_every_syntactic_position_test.go +51 -0
- package/linthost/unicorn_number_literal_case_fixes_radix_prefix_and_hex_digits_test.go +42 -0
- package/linthost/unicorn_number_literal_case_fixes_uppercase_exponent_test.go +42 -0
- package/linthost/unicorn_number_literal_case_reports_exact_range_and_message_test.go +53 -0
- package/linthost/unicorn_number_literal_case_skips_canonical_literals_test.go +38 -0
- package/linthost/unicorn_number_literal_case_uppercases_hex_exponent_digits_test.go +44 -0
- package/linthost/unicorn_prefer_number_properties_autofixes_is_na_n_with_number_argument_test.go +24 -0
- package/linthost/unicorn_prefer_number_properties_autofixes_safe_global_test.go +24 -0
- package/linthost/unicorn_prefer_number_properties_checks_infinity_when_enabled_test.go +43 -0
- package/linthost/unicorn_prefer_number_properties_checks_na_n_when_enabled_test.go +30 -0
- package/linthost/unicorn_prefer_number_properties_expands_shorthand_fix_test.go +24 -0
- package/linthost/unicorn_prefer_number_properties_fixes_negative_infinity_test.go +25 -0
- package/linthost/unicorn_prefer_number_properties_interpolates_message_test.go +33 -0
- package/linthost/unicorn_prefer_number_properties_leaves_infinity_and_na_n_under_defaults_test.go +24 -0
- package/linthost/unicorn_prefer_number_properties_reports_object_value_positions_test.go +37 -0
- package/linthost/unicorn_prefer_number_properties_skips_base10_and_missing_radix_test.go +35 -0
- package/linthost/unicorn_prefer_number_properties_skips_shadowed_bindings_test.go +40 -0
- package/linthost/unicorn_prefer_number_properties_suggests_unsafe_is_na_n_test.go +38 -0
- package/linthost/unicorn_prefer_number_properties_test.go +81 -0
- package/linthost/unicorn_prefer_number_properties_validates_options_test.go +64 -0
- package/linthost/unicorn_prefer_optional_catch_binding_test.go +53 -0
- package/linthost/unicorn_prefer_simple_condition_first_handles_or_chains_and_non_logical_type_wrappers_test.go +45 -0
- package/linthost/unicorn_prefer_simple_condition_first_parser_aware_comments_do_not_mistake_literal_text_test.go +28 -0
- package/linthost/unicorn_prefer_simple_condition_first_preserves_mixed_operators_and_parentheses_test.go +32 -0
- package/linthost/unicorn_prefer_simple_condition_first_reports_exact_safe_finding_and_stable_fix_test.go +64 -0
- package/linthost/unicorn_prefer_simple_condition_first_restricts_reports_to_boolean_contexts_test.go +68 -0
- package/linthost/unicorn_prefer_simple_condition_first_reviews_each_homogeneous_mixed_operator_chain_test.go +55 -0
- package/linthost/unicorn_prefer_simple_condition_first_uses_canonical_simple_expression_grammar_test.go +105 -0
- package/linthost/unicorn_prefer_simple_condition_first_withholds_unsafe_and_syntax_owned_fixes_test.go +57 -0
- package/linthost/unicorn_prefer_string_raw_survives_unterminated_literals_test.go +36 -0
- package/linthost/unicorn_prevent_abbreviations_allows_generated_names_to_shadow_without_capture_test.go +23 -0
- package/linthost/unicorn_prevent_abbreviations_allows_reserved_words_in_property_suggestions_test.go +43 -0
- package/linthost/unicorn_prevent_abbreviations_applies_import_controls_to_static_require_bindings_test.go +29 -0
- package/linthost/unicorn_prevent_abbreviations_applies_import_mode_to_external_import_equals_test.go +29 -0
- package/linthost/unicorn_prevent_abbreviations_applies_internal_import_defaults_and_preserves_imported_names_test.go +40 -0
- package/linthost/unicorn_prevent_abbreviations_avoids_catch_parameter_body_redeclarations_test.go +23 -0
- package/linthost/unicorn_prevent_abbreviations_avoids_compiler_provided_global_bindings_test.go +23 -0
- package/linthost/unicorn_prevent_abbreviations_avoids_var_lexical_early_error_collisions_test.go +23 -0
- package/linthost/unicorn_prevent_abbreviations_checks_physical_filename_without_offering_edits_test.go +52 -0
- package/linthost/unicorn_prevent_abbreviations_checks_shorthand_destructuring_only_when_enabled_test.go +25 -0
- package/linthost/unicorn_prevent_abbreviations_does_not_apply_require_mode_to_qualified_import_equals_test.go +24 -0
- package/linthost/unicorn_prevent_abbreviations_does_not_capture_outer_reads_with_unused_inner_bindings_test.go +23 -0
- package/linthost/unicorn_prevent_abbreviations_does_not_capture_unresolved_names_test.go +23 -0
- package/linthost/unicorn_prevent_abbreviations_does_not_report_destructuring_assignment_keys_as_properties_test.go +23 -0
- package/linthost/unicorn_prevent_abbreviations_does_not_treat_destructuring_property_keys_as_collisions_test.go +23 -0
- package/linthost/unicorn_prevent_abbreviations_expands_compound_and_cased_names_but_skips_constants_test.go +23 -0
- package/linthost/unicorn_prevent_abbreviations_false_replacement_disables_compound_matches_test.go +23 -0
- package/linthost/unicorn_prevent_abbreviations_false_replacement_stops_case_variant_fallback_test.go +22 -0
- package/linthost/unicorn_prevent_abbreviations_honors_negative_replacement_and_allow_list_patches_test.go +40 -0
- package/linthost/unicorn_prevent_abbreviations_honors_replacement_allow_and_ignore_options_test.go +42 -0
- package/linthost/unicorn_prevent_abbreviations_ignores_detached_js_doc_when_deciding_fix_safety_test.go +47 -0
- package/linthost/unicorn_prevent_abbreviations_ignores_non_lexical_jsx_and_tuple_names_for_collisions_test.go +24 -0
- package/linthost/unicorn_prevent_abbreviations_keeps_exported_js_doc_and_jsx_bindings_diagnostic_only_test.go +107 -0
- package/linthost/unicorn_prevent_abbreviations_keeps_independent_loop_and_switch_scopes_independent_test.go +23 -0
- package/linthost/unicorn_prevent_abbreviations_keeps_mapped_and_conditional_type_scopes_independent_test.go +23 -0
- package/linthost/unicorn_prevent_abbreviations_keeps_shadowed_bindings_independent_and_avoids_collisions_test.go +23 -0
- package/linthost/unicorn_prevent_abbreviations_keeps_type_script_signature_scopes_independent_test.go +23 -0
- package/linthost/unicorn_prevent_abbreviations_offers_whole_binding_suggestions_for_ambiguous_names_test.go +40 -0
- package/linthost/unicorn_prevent_abbreviations_preserves_astral_first_rune_casing_test.go +27 -0
- package/linthost/unicorn_prevent_abbreviations_preserves_canonical_upper_first_for_uncased_prefixes_test.go +23 -0
- package/linthost/unicorn_prevent_abbreviations_preserves_explicit_imported_alias_names_test.go +22 -0
- package/linthost/unicorn_prevent_abbreviations_preserves_exported_alias_names_test.go +35 -0
- package/linthost/unicorn_prevent_abbreviations_property_checks_are_opt_in_and_suggestion_only_test.go +34 -0
- package/linthost/unicorn_prevent_abbreviations_recognizes_only_canonical_static_require_calls_test.go +43 -0
- package/linthost/unicorn_prevent_abbreviations_rejects_malformed_options_test.go +36 -0
- package/linthost/unicorn_prevent_abbreviations_renames_class_inner_and_outer_references_together_test.go +23 -0
- package/linthost/unicorn_prevent_abbreviations_renames_default_export_local_names_test.go +23 -0
- package/linthost/unicorn_prevent_abbreviations_renames_merged_type_and_value_references_together_test.go +23 -0
- package/linthost/unicorn_prevent_abbreviations_renames_type_predicate_references_test.go +23 -0
- package/linthost/unicorn_prevent_abbreviations_reports_binding_once_and_fixes_every_reference_test.go +31 -0
- package/linthost/unicorn_prevent_abbreviations_separates_generated_names_at_cross_scope_reads_test.go +23 -0
- package/linthost/unicorn_prevent_abbreviations_separates_generated_names_in_one_scope_test.go +23 -0
- package/linthost/unicorn_prevent_abbreviations_supports_canonical_empty_replacement_spelling_test.go +23 -0
- package/linthost/unicorn_prevent_abbreviations_test.go +34 -0
- package/linthost/unicorn_prevent_abbreviations_uses_default_import_control_for_named_default_syntax_test.go +25 -0
- package/linthost/unicorn_prevent_abbreviations_uses_function_scope_for_destructured_var_collisions_test.go +23 -0
- package/linthost/unicorn_prevent_abbreviations_uses_function_scope_for_var_collisions_test.go +23 -0
- package/linthost/unicorn_prevent_abbreviations_uses_java_script_full_unicode_casing_test.go +29 -0
- package/linthost/unicorn_prevent_abbreviations_uses_strict_binding_grammar_for_custom_replacements_test.go +51 -0
- package/linthost/unicorn_regexp_test_requires_a_boolean_result_consumer_test.go +33 -0
- package/linthost/unicorn_relative_url_style_preserves_leading_trimmed_characters_test.go +47 -0
- package/linthost/unicorn_report_only_advice_exposes_semantic_preconditions_test.go +48 -0
- package/linthost/unicorn_rule_finding_helpers_test.go +14 -0
- package/linthost/unicorn_rule_names_helpers_test.go +11 -0
- package/linthost/unicorn_single_call_excludes_event_listener_registration_test.go +30 -0
- package/linthost/unicorn_slice_end_preserves_other_receiver_bounds_test.go +30 -0
- package/linthost/unicorn_splice_count_preserves_bounds_and_insertions_test.go +33 -0
- package/linthost/unicorn_spread_fallback_is_load_bearing_for_arrays_test.go +31 -0
- package/linthost/unicorn_string_content_applies_first_matching_pattern_in_configured_order_test.go +55 -0
- package/linthost/unicorn_string_content_escapes_backticks_and_dollars_in_template_fix_test.go +75 -0
- package/linthost/unicorn_string_content_escapes_delimiter_quotes_in_literal_fix_test.go +60 -0
- package/linthost/unicorn_string_content_escapes_line_separators_keeps_other_whitespace_raw_test.go +79 -0
- package/linthost/unicorn_string_content_fix_false_reports_suggestion_only_test.go +73 -0
- package/linthost/unicorn_string_content_honors_custom_message_and_placeholders_test.go +41 -0
- package/linthost/unicorn_string_content_jsx_attribute_fix_uses_html_entities_test.go +103 -0
- package/linthost/unicorn_string_content_matches_case_insensitively_when_configured_test.go +68 -0
- package/linthost/unicorn_string_content_normalizes_template_line_endings_like_acorn_test.go +87 -0
- package/linthost/unicorn_string_content_preserves_control_escapes_in_literal_fix_test.go +93 -0
- package/linthost/unicorn_string_content_rejects_malformed_options_before_linting_test.go +79 -0
- package/linthost/unicorn_string_content_reports_and_fixes_plain_string_literal_test.go +54 -0
- package/linthost/unicorn_string_content_reports_each_template_quasi_at_exact_ranges_test.go +61 -0
- package/linthost/unicorn_string_content_selector_matches_keep_ignored_tag_exemption_test.go +33 -0
- package/linthost/unicorn_string_content_selectors_restrict_checked_nodes_test.go +68 -0
- package/linthost/unicorn_string_content_skips_empty_and_non_string_literals_test.go +43 -0
- package/linthost/unicorn_string_content_skips_ignored_template_tags_test.go +81 -0
- package/linthost/unicorn_string_content_stays_silent_without_pattern_options_test.go +34 -0
- package/linthost/unicorn_string_content_treats_pattern_as_regular_expression_test.go +77 -0
- package/linthost/unicorn_switch_case_break_position_declines_unsafe_or_semantic_moves_test.go +111 -0
- package/linthost/unicorn_switch_case_break_position_fix_preserves_statements_comments_and_eol_test.go +187 -0
- package/linthost/unicorn_switch_case_break_position_reports_every_supported_terminator_at_exact_range_test.go +132 -0
- package/linthost/unicorn_switch_case_break_position_requires_sole_non_empty_block_then_direct_terminator_test.go +112 -0
- package/linthost/unicorn_template_indent_accepts_parenthesized_jest_inline_snapshot_test.go +26 -0
- package/linthost/unicorn_template_indent_detects_tabs_outside_templates_test.go +31 -0
- package/linthost/unicorn_template_indent_falls_back_to_two_spaces_without_any_indent_signal_test.go +23 -0
- package/linthost/unicorn_template_indent_fix_preserves_quasis_substitutions_escapes_and_blank_lines_test.go +71 -0
- package/linthost/unicorn_template_indent_fixes_empty_boundary_quasis_with_insertions_test.go +37 -0
- package/linthost/unicorn_template_indent_fixes_nested_templates_without_touching_expressions_test.go +52 -0
- package/linthost/unicorn_template_indent_honors_configured_tags_functions_comments_and_selectors_test.go +69 -0
- package/linthost/unicorn_template_indent_honors_numeric_and_whitespace_indent_options_test.go +51 -0
- package/linthost/unicorn_template_indent_pins_every_default_matcher_test.go +46 -0
- package/linthost/unicorn_template_indent_preserves_content_trailing_spaces_test.go +31 -0
- package/linthost/unicorn_template_indent_preserves_crlf_test.go +35 -0
- package/linthost/unicorn_template_indent_preserves_every_interior_ecma_script_line_ending_test.go +39 -0
- package/linthost/unicorn_template_indent_preserves_leading_byte_order_mark_test.go +27 -0
- package/linthost/unicorn_template_indent_preserves_mixed_interior_line_endings_test.go +35 -0
- package/linthost/unicorn_template_indent_recognizes_every_ecma_script_source_line_separator_test.go +48 -0
- package/linthost/unicorn_template_indent_rejects_jest_inline_snapshot_near_misses_test.go +35 -0
- package/linthost/unicorn_template_indent_rejects_malformed_options_before_linting_test.go +52 -0
- package/linthost/unicorn_template_indent_selects_every_official_entry_point_at_exact_range_test.go +56 -0
- package/linthost/unicorn_template_indent_skips_unselected_single_line_and_already_correct_templates_test.go +37 -0
- package/linthost/unicorn_template_indent_test.go +20 -0
- package/linthost/unicorn_text_encoding_identifier_case_enforces_dash_in_jsx_charset_attributes_test.go +69 -0
- package/linthost/unicorn_text_encoding_identifier_case_enforces_dash_in_text_decoder_test.go +47 -0
- package/linthost/unicorn_text_encoding_identifier_case_fixes_fs_read_file_encoding_test.go +44 -0
- package/linthost/unicorn_text_encoding_identifier_case_handles_template_literals_test.go +46 -0
- package/linthost/unicorn_text_encoding_identifier_case_reports_suggestion_range_and_message_test.go +78 -0
- package/linthost/unicorn_text_encoding_identifier_case_skips_canonical_and_unknown_labels_test.go +35 -0
- package/linthost/unicorn_text_encoding_identifier_case_suggests_without_fixing_off_read_file_positions_test.go +36 -0
- package/linthost/unicorn_text_encoding_identifier_case_withdash_option_prefers_dash_test.go +52 -0
- package/linthost/unicorn_throw_new_error_fix_parenthesizes_a_shielded_call_chain_test.go +69 -0
- package/linthost/unicorn_throw_new_error_fix_spaces_an_abutting_throw_keyword_test.go +64 -0
- package/linthost/unicorn_throw_new_error_fixes_every_throw_in_one_pass_test.go +42 -0
- package/linthost/unicorn_throw_new_error_fixes_upstream_invalid_corpus_test.go +114 -0
- package/linthost/unicorn_throw_new_error_reports_custom_and_member_callees_test.go +62 -0
- package/linthost/unicorn_throw_new_error_skips_non_matching_callees_test.go +68 -0
- package/linthost/unregistered_rule_code_lookup_preserves_registered_assignments_test.go +102 -0
- package/linthost/use_unknown_in_catch_callback_variable_test.go +48 -0
- package/linthost/user_pattern_cache_follows_resolver_ownership_test.go +87 -0
- package/linthost/user_pattern_cache_parallel_reuses_results_test.go +67 -0
- package/linthost/user_source_files_exclude_imported_declarations_and_javascript_test.go +82 -0
- package/linthost/user_source_files_span_program_typescript_sources_test.go +72 -0
- package/linthost/valid_typeof_equality_operator_scope_test.go +173 -0
- package/linthost/verbatim_range_returns_empty_for_invalid_range_test.go +53 -0
- package/linthost/verbatim_returns_empty_for_nil_node_test.go +30 -0
- package/linthost/verbatim_returns_empty_for_out_of_range_node_test.go +52 -0
- package/linthost/vitest_expect_expect_reports_empty_test_test.go +35 -0
- package/linthost/vitest_finding_helpers_test.go +14 -0
- package/linthost/vitest_no_conditional_expect_reports_expect_inside_if_test.go +37 -0
- package/linthost/vitest_no_conditional_tests_reports_test_inside_if_test.go +35 -0
- package/linthost/vitest_no_disabled_tests_reports_skip_test.go +34 -0
- package/linthost/vitest_no_done_callback_reports_test_parameter_test.go +34 -0
- package/linthost/vitest_no_focused_tests_reports_only_test.go +34 -0
- package/linthost/vitest_no_identical_title_reports_duplicate_sibling_test.go +35 -0
- package/linthost/vitest_no_standalone_expect_reports_top_level_expect_test.go +33 -0
- package/linthost/vitest_no_test_return_statement_reports_return_test.go +35 -0
- package/linthost/vitest_prefer_to_have_length_reports_length_matcher_test.go +34 -0
- package/linthost/vitest_valid_describe_callback_reports_async_callback_test.go +34 -0
- package/linthost/vitest_valid_expect_reports_missing_matcher_test.go +35 -0
- package/linthost/vitest_valid_title_reports_empty_title_test.go +34 -0
- package/linthost/wait_for_assertion_and_side_effect_guards_test.go +55 -0
- package/linthost/windows_junction_dependency_entry_matches_node_fingerprint_test.go +55 -0
- package/linthost/windows_loader_temp_base_stays_on_config_volume_test.go +98 -0
- package/linthost/windows_project_source_selection_preserves_physical_aliases_test.go +69 -0
- package/linthost/windows_real_project_path_expands_windows_short_ancestor_test.go +47 -0
- package/linthost/windows_resolve_config_tsgo_through_linked_typescript_install_test.go +52 -0
- package/linthost/windows_short_path_other_test.go +11 -0
- package/linthost/windows_short_path_windows_test.go +39 -0
- package/linthost/workspace_link_resolves_a_sibling_package_to_its_source_test.go +86 -0
- package/package.json +5 -3
- package/rule/astutil/astutil.go +165 -59
- package/rule/context_decode_options_preserves_defaults_and_decoder_errors_test.go +87 -0
- package/rule/graph.go +82 -16
- package/rule/hint.go +95 -28
- package/rule/new_project_context_preserves_snapshot_ownership_test.go +62 -0
- package/rule/new_project_input_context_preserves_owned_options_test.go +59 -0
- package/rule/new_project_rule_result_preserves_snapshot_ownership_test.go +63 -0
- package/rule/project.go +382 -22
- package/rule/project_input_reader.go +163 -0
- package/rule/rule.go +540 -92
- package/src/createTtscPlugin.ts +3010 -0
- package/src/index.ts +1 -2974
- package/src/internal/configEvaluatorFailure.ts +17 -9
- package/src/internal/lintTrace.ts +106 -0
- package/src/internal/normalizeContributors.ts +79 -0
- package/src/structures/ITtscLintConfig.ts +27 -8
- package/src/structures/ITtscLintPlugin.ts +13 -8
- package/src/structures/ITtscLintPluginConfig.ts +18 -7
- package/src/structures/ITtscLintPluginMeta.ts +10 -7
- package/src/structures/TtscLintRuleSetting.ts +18 -13
- package/src/structures/TtscLintSeverity.ts +5 -0
- package/src/structures/format/ITtscLintFormat.ts +14 -8
- package/src/structures/format/ITtscLintFormatJsDoc.ts +8 -1
- package/src/structures/format/ITtscLintFormatSortImports.ts +14 -8
- package/src/structures/rules/ITtscLintBoundariesRuleOptions.ts +133 -25
- package/src/structures/rules/ITtscLintBoundariesRules.ts +10 -5
- package/src/structures/rules/ITtscLintContributorRules.ts +20 -13
- package/src/structures/rules/ITtscLintCoreRuleOptions.ts +226 -24
- package/src/structures/rules/ITtscLintCoreRules.ts +92 -72
- package/src/structures/rules/ITtscLintCypressRuleOptions.ts +8 -1
- package/src/structures/rules/ITtscLintCypressRules.ts +24 -21
- package/src/structures/rules/ITtscLintFunctionalRuleOptions.ts +140 -24
- package/src/structures/rules/ITtscLintFunctionalRules.ts +20 -12
- package/src/structures/rules/ITtscLintJestRules.ts +22 -16
- package/src/structures/rules/ITtscLintJsdocRules.ts +5 -0
- package/src/structures/rules/ITtscLintJsxA11yRules.ts +24 -21
- package/src/structures/rules/ITtscLintNextjsRules.ts +40 -42
- package/src/structures/rules/ITtscLintPlaywrightRules.ts +24 -14
- package/src/structures/rules/ITtscLintPromiseRules.ts +23 -14
- package/src/structures/rules/ITtscLintReactPerfRuleOptions.ts +8 -1
- package/src/structures/rules/ITtscLintReactPerfRules.ts +18 -15
- package/src/structures/rules/ITtscLintReactRuleOptions.ts +14 -4
- package/src/structures/rules/ITtscLintReactRules.ts +33 -27
- package/src/structures/rules/ITtscLintRegexpRules.ts +18 -4
- package/src/structures/rules/ITtscLintRuleOptionsMap.ts +150 -15
- package/src/structures/rules/ITtscLintRules.ts +13 -9
- package/src/structures/rules/ITtscLintSecurityRules.ts +33 -23
- package/src/structures/rules/ITtscLintSolidRules.ts +57 -47
- package/src/structures/rules/ITtscLintStorybookRuleOptions.ts +10 -2
- package/src/structures/rules/ITtscLintStorybookRules.ts +52 -62
- package/src/structures/rules/ITtscLintTanstackQueryRules.ts +34 -30
- package/src/structures/rules/ITtscLintTestingLibraryRuleOptions.ts +12 -3
- package/src/structures/rules/ITtscLintTestingLibraryRules.ts +20 -15
- package/src/structures/rules/ITtscLintTypeScriptRuleOptions.ts +116 -16
- package/src/structures/rules/ITtscLintTypeScriptRules.ts +62 -51
- package/src/structures/rules/ITtscLintUnicornRuleOptions.ts +241 -48
- package/src/structures/rules/ITtscLintUnicornRules.ts +97 -44
- package/src/structures/rules/ITtscLintVitestRules.ts +19 -11
- package/src/structures/rules/TtscLintContributorOverlay.ts +40 -0
- package/src/structures/rules/index.ts +1 -0
|
@@ -0,0 +1,2704 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.TTSX_EXTRACTOR_SCRIPT = void 0;
|
|
7
|
+
exports.default = createTtscPlugin;
|
|
8
|
+
const node_buffer_1 = require("node:buffer");
|
|
9
|
+
const node_child_process_1 = require("node:child_process");
|
|
10
|
+
const node_crypto_1 = require("node:crypto");
|
|
11
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
12
|
+
const node_module_1 = require("node:module");
|
|
13
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
14
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
15
|
+
const node_url_1 = require("node:url");
|
|
16
|
+
const configEvaluatorFailure_1 = require("./internal/configEvaluatorFailure");
|
|
17
|
+
const lintTrace_1 = require("./internal/lintTrace");
|
|
18
|
+
const normalizeContributors_1 = require("./internal/normalizeContributors");
|
|
19
|
+
// Namespace becomes the rule-name prefix (`<ns>/<rule>`). Mirrors ESLint
|
|
20
|
+
// plugin namespace conventions: lowercase ASCII, digits, hyphens, and
|
|
21
|
+
// underscores; leading character must be alphabetic so the prefix never
|
|
22
|
+
// collides with a rule name that itself starts with a digit. Hyphens
|
|
23
|
+
// are encoded into underscores for the Go sub-package name (see
|
|
24
|
+
// `goSubpackageName`); the user-facing prefix keeps the original form.
|
|
25
|
+
const NAMESPACE_PATTERN = /^[a-z][a-z0-9_-]*$/;
|
|
26
|
+
const LINT_CONFIG_FILENAMES = [
|
|
27
|
+
"lint.config.json",
|
|
28
|
+
"lint.config.js",
|
|
29
|
+
"lint.config.mjs",
|
|
30
|
+
"lint.config.cjs",
|
|
31
|
+
"lint.config.ts",
|
|
32
|
+
"lint.config.mts",
|
|
33
|
+
"lint.config.cts",
|
|
34
|
+
"ttsc-lint.config.json",
|
|
35
|
+
"ttsc-lint.config.js",
|
|
36
|
+
"ttsc-lint.config.mjs",
|
|
37
|
+
"ttsc-lint.config.cjs",
|
|
38
|
+
"ttsc-lint.config.ts",
|
|
39
|
+
"ttsc-lint.config.mts",
|
|
40
|
+
"ttsc-lint.config.cts",
|
|
41
|
+
];
|
|
42
|
+
/**
|
|
43
|
+
* Tsconfig plugin-entry keys owned by the ttsc host framework. They are
|
|
44
|
+
* accepted alongside the single lint-specific `configFile` key; every other key
|
|
45
|
+
* is rejected so a stale inline option (`rules`, `format`, `extends`, legacy
|
|
46
|
+
* `config`, `plugins`) surfaces as a clear migration error instead of being
|
|
47
|
+
* silently ignored. Mirrors `@ttsc/banner` and `@ttsc/strip`.
|
|
48
|
+
*/
|
|
49
|
+
const FRAMEWORK_KEYS = new Set(["enabled", "transform"]);
|
|
50
|
+
/**
|
|
51
|
+
* Plugin descriptor factory consumed by ttsc package discovery.
|
|
52
|
+
*
|
|
53
|
+
* Contributor lint plugins come from one place: the project's lint config file
|
|
54
|
+
* (`lint.config.{ts,cts,mts,js,cjs,mjs,json}` or `ttsc-lint.config.*`). The
|
|
55
|
+
* tsconfig plugin entry carries no rule or plugin surface — it optionally names
|
|
56
|
+
* the config file via `configFile`, otherwise the file is discovered by walking
|
|
57
|
+
* upward from the tsconfig directory (or from the caller-declared
|
|
58
|
+
* `pluginConfigDir` when the resolved tsconfig is a generated wrapper in a temp
|
|
59
|
+
* directory).
|
|
60
|
+
*
|
|
61
|
+
* The factory locates the config file and evaluates contributor-bearing configs
|
|
62
|
+
* in an isolated ttsx process. JSON without plugins or an extends chain needs
|
|
63
|
+
* no evaluator. The extractor reads plugin maps from the resolved config and
|
|
64
|
+
* its bases and forwards contributor Go sources to the descriptor's
|
|
65
|
+
* `contributors` field. Its dependency envelope owns config observations; the
|
|
66
|
+
* child's bootstrap does not inherit the parent descriptor's observation
|
|
67
|
+
* channel.
|
|
68
|
+
*
|
|
69
|
+
* @evidence contracts/common.md#principled-implementation Entry validation and config-origin discovery resolve registered contributor sources and observed inputs before constructing the check-stage descriptor with supported capabilities.
|
|
70
|
+
* @evidence contracts/common.md#clear-and-simple-design The exported factory composes validation, discovery and descriptor construction; helpers own module loading and dependency fingerprints separately.
|
|
71
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Contributors use the supported Go-source extension boundary and config-file schema; no foreign method replacement or fixture-specific descriptor is installed.
|
|
72
|
+
* @evidence contracts/common.md#meaningful-documentation Native paragraphs explain config origins, evaluator formats and contributor forwarding; separated prose and tags follow documentation guidance.
|
|
73
|
+
*/
|
|
74
|
+
function createTtscPlugin(context) {
|
|
75
|
+
rejectUnsupportedEntryKeys(context.plugin);
|
|
76
|
+
const resolvedConfig = resolveConfigFileContributors(context);
|
|
77
|
+
// Build the descriptor without a `contributors` key when none were
|
|
78
|
+
// declared, so consumers (and the existing key-shape regression
|
|
79
|
+
// tests) see the same surface as before this feature shipped.
|
|
80
|
+
const descriptor = {
|
|
81
|
+
capabilities: {
|
|
82
|
+
checkObservations: true,
|
|
83
|
+
compilerArgsCwd: true,
|
|
84
|
+
diagnosticsTiming: true,
|
|
85
|
+
graphNodes: true,
|
|
86
|
+
lsp: true,
|
|
87
|
+
projectContextArgs: true,
|
|
88
|
+
projectDiagnostics: true,
|
|
89
|
+
projectInputs: true,
|
|
90
|
+
residentCheck: true,
|
|
91
|
+
threadingArgs: true,
|
|
92
|
+
},
|
|
93
|
+
hostInputHashes: resolvedConfig.hostInputHashes,
|
|
94
|
+
hostInputRealpaths: resolvedConfig.hostInputRealpaths,
|
|
95
|
+
hostInputs: resolvedConfig.hostInputs,
|
|
96
|
+
name: "@ttsc/lint",
|
|
97
|
+
reportsTypeScriptDiagnostics: true,
|
|
98
|
+
// `context.dirname` is this descriptor's own directory in every load mode —
|
|
99
|
+
// the ESM-safe replacement for `__dirname`, which is undefined when ttsc
|
|
100
|
+
// loads a descriptor as `.ts` source or ESM.
|
|
101
|
+
source: node_path_1.default.resolve(context.dirname, "..", "plugin"),
|
|
102
|
+
stage: "check",
|
|
103
|
+
};
|
|
104
|
+
if (resolvedConfig.contributors.length > 0) {
|
|
105
|
+
descriptor.contributors = resolvedConfig.contributors;
|
|
106
|
+
}
|
|
107
|
+
return descriptor;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Resolves the contributor lint plugins declared in the project's lint config
|
|
111
|
+
* file.
|
|
112
|
+
*
|
|
113
|
+
* - When the tsconfig plugin entry sets `configFile`, that exact file is loaded
|
|
114
|
+
* (relative paths resolve against the tsconfig directory, or against the
|
|
115
|
+
* caller-declared `pluginConfigDir` when present).
|
|
116
|
+
* - Otherwise a `lint.config.*` / `ttsc-lint.config.*` file is discovered by
|
|
117
|
+
* walking upward from the tsconfig directory (or from `pluginConfigDir` when
|
|
118
|
+
* present).
|
|
119
|
+
*
|
|
120
|
+
* Returns no contributors while preserving observed discovery inputs when no
|
|
121
|
+
* config file is set or discovered. The Go sidecar reports a missing config.
|
|
122
|
+
*/
|
|
123
|
+
function resolveConfigFileContributors(context) {
|
|
124
|
+
const configFile = readConfigFileOption(context);
|
|
125
|
+
const explicitConfigPath = configFile === undefined
|
|
126
|
+
? undefined
|
|
127
|
+
: node_path_1.default.resolve(pluginConfigBaseDir(context), configFile);
|
|
128
|
+
const discovery = explicitConfigPath === undefined
|
|
129
|
+
? discoverLintConfigFile(context)
|
|
130
|
+
: {
|
|
131
|
+
configPath: explicitConfigPath,
|
|
132
|
+
hostInputHashes: hashHostInputPaths([explicitConfigPath]),
|
|
133
|
+
hostInputRealpaths: realpathHostInputPaths([explicitConfigPath]),
|
|
134
|
+
hostInputs: [explicitConfigPath],
|
|
135
|
+
};
|
|
136
|
+
const { configPath } = discovery;
|
|
137
|
+
if (!configPath || !node_fs_1.default.existsSync(configPath)) {
|
|
138
|
+
return {
|
|
139
|
+
contributors: [],
|
|
140
|
+
hostInputHashes: discovery.hostInputHashes,
|
|
141
|
+
hostInputRealpaths: discovery.hostInputRealpaths,
|
|
142
|
+
hostInputs: discovery.hostInputs,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
const evaluation = readConfigPluginEntries(configPath, context);
|
|
146
|
+
const entries = evaluation.entries;
|
|
147
|
+
const out = (0, normalizeContributors_1.normalizeContributors)(entries, configPath);
|
|
148
|
+
const dependencyInputs = evaluation.dependencies
|
|
149
|
+
.filter((dependency) => dependency.scope === "watch" && dependency.kind !== "directory")
|
|
150
|
+
.map((dependency) => dependency.path);
|
|
151
|
+
const hostInputHashes = { ...discovery.hostInputHashes };
|
|
152
|
+
const hostInputRealpaths = { ...discovery.hostInputRealpaths };
|
|
153
|
+
const unstableRealpaths = new Set();
|
|
154
|
+
const unprovenInputs = new Set();
|
|
155
|
+
const missingOptionalDigest = (0, node_crypto_1.createHash)("sha256")
|
|
156
|
+
.update("missing\0")
|
|
157
|
+
.digest("hex");
|
|
158
|
+
const directoryCandidateDigest = (0, node_crypto_1.createHash)("sha256")
|
|
159
|
+
.update("ttsc:host-input:directory\0")
|
|
160
|
+
.digest("hex");
|
|
161
|
+
for (const dependency of evaluation.dependencies) {
|
|
162
|
+
if (dependency.scope !== "watch" || dependency.kind === "directory") {
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
const input = node_path_1.default.resolve(dependency.path);
|
|
166
|
+
const realpath = dependency.realpath;
|
|
167
|
+
if (!dependency.identityStable) {
|
|
168
|
+
delete hostInputRealpaths[input];
|
|
169
|
+
delete hostInputHashes[input];
|
|
170
|
+
unstableRealpaths.add(input);
|
|
171
|
+
unprovenInputs.add(input);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (Object.prototype.hasOwnProperty.call(hostInputRealpaths, input) &&
|
|
175
|
+
hostInputRealpaths[input] !== realpath) {
|
|
176
|
+
delete hostInputRealpaths[input];
|
|
177
|
+
delete hostInputHashes[input];
|
|
178
|
+
unstableRealpaths.add(input);
|
|
179
|
+
}
|
|
180
|
+
else if (!unstableRealpaths.has(input)) {
|
|
181
|
+
hostInputRealpaths[input] = realpath;
|
|
182
|
+
}
|
|
183
|
+
let hash;
|
|
184
|
+
if (dependency.kind === "file" &&
|
|
185
|
+
/^[0-9a-f]{64}$/.test(dependency.digest)) {
|
|
186
|
+
hash = dependency.digest;
|
|
187
|
+
}
|
|
188
|
+
else if (dependency.digest === missingOptionalDigest) {
|
|
189
|
+
// The evaluator's optional-file digest includes a state prefix. The
|
|
190
|
+
// public host-input contract uses null for the observed missing state.
|
|
191
|
+
hash = null;
|
|
192
|
+
}
|
|
193
|
+
else if (dependency.digest === directoryCandidateDigest) {
|
|
194
|
+
// A path that is currently a directory is still an exact file candidate:
|
|
195
|
+
// replacing it with a file changes module/config selection.
|
|
196
|
+
hash = directoryCandidateDigest;
|
|
197
|
+
}
|
|
198
|
+
if (hash === undefined) {
|
|
199
|
+
delete hostInputHashes[input];
|
|
200
|
+
unprovenInputs.add(input);
|
|
201
|
+
}
|
|
202
|
+
else if (unprovenInputs.has(input)) {
|
|
203
|
+
// A later observation cannot revive proof another evaluation stage
|
|
204
|
+
// could not provide for the same combined descriptor result.
|
|
205
|
+
}
|
|
206
|
+
else if (Object.prototype.hasOwnProperty.call(hostInputHashes, input) &&
|
|
207
|
+
hostInputHashes[input] !== hash) {
|
|
208
|
+
delete hostInputHashes[input];
|
|
209
|
+
unprovenInputs.add(input);
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
hostInputHashes[input] = hash;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return {
|
|
216
|
+
contributors: out,
|
|
217
|
+
hostInputHashes,
|
|
218
|
+
hostInputRealpaths,
|
|
219
|
+
hostInputs: [...discovery.hostInputs, ...dependencyInputs],
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
/** Snapshot config candidates before any discovery/evaluation side effect. */
|
|
223
|
+
function hashHostInputPaths(inputs) {
|
|
224
|
+
return Object.fromEntries(inputs.map((input) => {
|
|
225
|
+
const file = node_path_1.default.resolve(input);
|
|
226
|
+
try {
|
|
227
|
+
if (node_fs_1.default.statSync(file).isDirectory()) {
|
|
228
|
+
return [
|
|
229
|
+
file,
|
|
230
|
+
(0, node_crypto_1.createHash)("sha256")
|
|
231
|
+
.update("ttsc:host-input:directory\0")
|
|
232
|
+
.digest("hex"),
|
|
233
|
+
];
|
|
234
|
+
}
|
|
235
|
+
return [
|
|
236
|
+
file,
|
|
237
|
+
(0, node_crypto_1.createHash)("sha256").update(node_fs_1.default.readFileSync(file)).digest("hex"),
|
|
238
|
+
];
|
|
239
|
+
}
|
|
240
|
+
catch {
|
|
241
|
+
return [file, null];
|
|
242
|
+
}
|
|
243
|
+
}));
|
|
244
|
+
}
|
|
245
|
+
function hostInputRealpath(file) {
|
|
246
|
+
try {
|
|
247
|
+
return node_fs_1.default.realpathSync.native(file);
|
|
248
|
+
}
|
|
249
|
+
catch {
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
function realpathHostInputPaths(inputs) {
|
|
254
|
+
return Object.fromEntries(inputs.map((input) => {
|
|
255
|
+
const file = node_path_1.default.resolve(input);
|
|
256
|
+
return [file, hostInputRealpath(file)];
|
|
257
|
+
}));
|
|
258
|
+
}
|
|
259
|
+
/** Mirror native discovery and fingerprint every candidate before selecting. */
|
|
260
|
+
function discoverLintConfigFile(context) {
|
|
261
|
+
const hostInputHashes = {};
|
|
262
|
+
const hostInputRealpaths = {};
|
|
263
|
+
const hostInputs = [];
|
|
264
|
+
const recordCandidates = (candidates) => {
|
|
265
|
+
for (const candidate of candidates) {
|
|
266
|
+
const absolute = node_path_1.default.resolve(candidate);
|
|
267
|
+
if (Object.prototype.hasOwnProperty.call(hostInputHashes, absolute)) {
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
hostInputs.push(absolute);
|
|
271
|
+
Object.assign(hostInputHashes, hashHostInputPaths([absolute]));
|
|
272
|
+
Object.assign(hostInputRealpaths, realpathHostInputPaths([absolute]));
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
for (const origin of discoveryConfigBaseDirs(context)) {
|
|
276
|
+
for (let directory = origin;; directory = node_path_1.default.dirname(directory)) {
|
|
277
|
+
const candidates = LINT_CONFIG_FILENAMES.map((name) => node_path_1.default.join(directory, name));
|
|
278
|
+
recordCandidates(candidates);
|
|
279
|
+
const matches = lintConfigMatchesIn(directory);
|
|
280
|
+
if (matches.length === 1) {
|
|
281
|
+
return {
|
|
282
|
+
configPath: matches[0],
|
|
283
|
+
hostInputHashes,
|
|
284
|
+
hostInputRealpaths,
|
|
285
|
+
hostInputs,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
if (matches.length > 1) {
|
|
289
|
+
throw new Error(`@ttsc/lint: multiple lint config files found in ${directory} (${matches
|
|
290
|
+
.map((file) => node_path_1.default.basename(file))
|
|
291
|
+
.join(", ")}); set "configFile" explicitly`);
|
|
292
|
+
}
|
|
293
|
+
const parent = node_path_1.default.dirname(directory);
|
|
294
|
+
if (parent === directory)
|
|
295
|
+
break;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return { hostInputHashes, hostInputRealpaths, hostInputs };
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Rejects any tsconfig plugin-entry key that is neither a host framework key
|
|
302
|
+
* nor the single lint-specific `configFile` key. Rule, format, and plugin
|
|
303
|
+
* settings live only in the lint config file, so a leftover inline key is
|
|
304
|
+
* surfaced as an explicit migration error rather than silently ignored.
|
|
305
|
+
*/
|
|
306
|
+
function rejectUnsupportedEntryKeys(entry) {
|
|
307
|
+
for (const key of Object.keys(entry)) {
|
|
308
|
+
if (FRAMEWORK_KEYS.has(key) || key === "configFile") {
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
throw new Error(`@ttsc/lint: tsconfig plugin entry contains unsupported key ${JSON.stringify(key)}. ` +
|
|
312
|
+
`Only "transform", "enabled", and "configFile" are accepted here; ` +
|
|
313
|
+
`put lint rules, format, and contributors in a ` +
|
|
314
|
+
`lint.config.{ts,cts,mts,js,cjs,mjs,json} file.`);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Reads the optional `configFile` key from the tsconfig plugin entry. It is the
|
|
319
|
+
* only lint-specific key the entry accepts; when present it overrides
|
|
320
|
+
* auto-discovery of the lint config file.
|
|
321
|
+
*/
|
|
322
|
+
function readConfigFileOption(context) {
|
|
323
|
+
const value = context.plugin.configFile;
|
|
324
|
+
if (value === undefined)
|
|
325
|
+
return undefined;
|
|
326
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
327
|
+
throw new Error(`@ttsc/lint: "configFile" must be a non-empty string path`);
|
|
328
|
+
}
|
|
329
|
+
return value;
|
|
330
|
+
}
|
|
331
|
+
function discoveryConfigBaseDirs(context) {
|
|
332
|
+
if (context.pluginConfigDir) {
|
|
333
|
+
return [node_path_1.default.resolve(context.cwd ?? ".", context.pluginConfigDir)];
|
|
334
|
+
}
|
|
335
|
+
const tsconfigDir = tsconfigBaseDir(context);
|
|
336
|
+
const cwd = node_path_1.default.resolve(context.cwd ?? context.projectRoot);
|
|
337
|
+
return tsconfigDir === cwd ? [tsconfigDir] : [tsconfigDir, cwd];
|
|
338
|
+
}
|
|
339
|
+
/** Return the non-directory candidates native discovery recognizes. */
|
|
340
|
+
function lintConfigMatchesIn(directory) {
|
|
341
|
+
const matches = [];
|
|
342
|
+
for (const name of LINT_CONFIG_FILENAMES) {
|
|
343
|
+
const candidate = node_path_1.default.join(directory, name);
|
|
344
|
+
try {
|
|
345
|
+
// Go's os.Stat follows symlinks and junctions. Follow them here too so a
|
|
346
|
+
// directory or dangling link cannot stop descriptor discovery before
|
|
347
|
+
// the native host reaches a valid ancestor config. Probing the canonical
|
|
348
|
+
// candidate spelling also preserves Go's behavior on case-insensitive
|
|
349
|
+
// filesystems when the directory entry uses different casing.
|
|
350
|
+
if (!node_fs_1.default.statSync(candidate).isDirectory())
|
|
351
|
+
matches.push(candidate);
|
|
352
|
+
}
|
|
353
|
+
catch {
|
|
354
|
+
// Missing, dangling, and unreadable candidates are not native matches.
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
return matches;
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Base directory for resolving a relative `configFile` from the tsconfig plugin
|
|
361
|
+
* entry. Mirrors the Go side (driver.PluginConfigBaseDir): the caller-declared
|
|
362
|
+
* pluginConfigDir wins when present — the resolved tsconfig is then a generated
|
|
363
|
+
* wrapper in a temp directory that no longer identifies the project — otherwise
|
|
364
|
+
* the tsconfig directory, falling back to the working directory.
|
|
365
|
+
*/
|
|
366
|
+
function pluginConfigBaseDir(context) {
|
|
367
|
+
if (context.pluginConfigDir) {
|
|
368
|
+
return node_path_1.default.resolve(context.cwd ?? ".", context.pluginConfigDir);
|
|
369
|
+
}
|
|
370
|
+
return tsconfigBaseDir(context);
|
|
371
|
+
}
|
|
372
|
+
function tsconfigBaseDir(context) {
|
|
373
|
+
const cwd = context.cwd ?? context.projectRoot;
|
|
374
|
+
if (context.tsconfig) {
|
|
375
|
+
return node_path_1.default.dirname(node_path_1.default.isAbsolute(context.tsconfig)
|
|
376
|
+
? context.tsconfig
|
|
377
|
+
: node_path_1.default.join(cwd, context.tsconfig));
|
|
378
|
+
}
|
|
379
|
+
return node_path_1.default.resolve(cwd);
|
|
380
|
+
}
|
|
381
|
+
function readConfigPluginEntries(configPath, context) {
|
|
382
|
+
// A JSON config that can bring no contributor with it — no `plugins` map and
|
|
383
|
+
// no `extends` chain to follow — has nothing to extract, and reading it runs
|
|
384
|
+
// no user code, so the isolated evaluator is not needed to keep its strings
|
|
385
|
+
// away from stdout. Skipping it there matters beyond the cost: the evaluator
|
|
386
|
+
// is a real subprocess, and a host that only wanted to know whether there
|
|
387
|
+
// were contributors would otherwise depend on a launcher being resolvable and
|
|
388
|
+
// on a compiler accepting one more invocation.
|
|
389
|
+
if (jsonConfigDeclaresNoContributor(configPath)) {
|
|
390
|
+
return { dependencies: [], entries: [] };
|
|
391
|
+
}
|
|
392
|
+
// Every other config uses the same isolated evaluator. Executable config can
|
|
393
|
+
// name contributor packages whose top-level code writes to stdout, so loading
|
|
394
|
+
// it in this host process would corrupt CLI JSON or preface the first LSP
|
|
395
|
+
// frame.
|
|
396
|
+
return readTtsxConfigPlugins(configPath, context);
|
|
397
|
+
}
|
|
398
|
+
function jsonConfigDeclaresNoContributor(configPath) {
|
|
399
|
+
if (node_path_1.default.extname(configPath).toLowerCase() !== ".json")
|
|
400
|
+
return false;
|
|
401
|
+
try {
|
|
402
|
+
const value = JSON.parse(node_fs_1.default.readFileSync(configPath, "utf8"));
|
|
403
|
+
return !configMayDeclareContributor(value);
|
|
404
|
+
}
|
|
405
|
+
catch {
|
|
406
|
+
// A malformed config is the evaluator's diagnostic to report, not this
|
|
407
|
+
// shortcut's, so it falls through to the path that reports it.
|
|
408
|
+
return false;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Whether any object in a config could still bring a contributor with it.
|
|
413
|
+
*
|
|
414
|
+
* A `plugins` map names one directly. An `extends` chain names one indirectly:
|
|
415
|
+
* the base it points at may be executable and may declare contributors of its
|
|
416
|
+
* own, and following that chain is the evaluator's job. Treating a config that
|
|
417
|
+
* extends anything as undecidable here is what keeps this shortcut from
|
|
418
|
+
* silently dropping a contributor the base would have supplied.
|
|
419
|
+
*/
|
|
420
|
+
function configMayDeclareContributor(value) {
|
|
421
|
+
if (Array.isArray(value)) {
|
|
422
|
+
return value.some((entry) => configMayDeclareContributor(entry));
|
|
423
|
+
}
|
|
424
|
+
if (value === null || typeof value !== "object")
|
|
425
|
+
return false;
|
|
426
|
+
const record = value;
|
|
427
|
+
for (const key of ["plugins", "extends"]) {
|
|
428
|
+
const declared = record[key];
|
|
429
|
+
if (declared !== undefined && declared !== null)
|
|
430
|
+
return true;
|
|
431
|
+
}
|
|
432
|
+
return false;
|
|
433
|
+
}
|
|
434
|
+
// TypeScript source written to a temp file and executed via ttsx. The
|
|
435
|
+
// %CONFIG_IMPORT% placeholder is replaced with a JSON-quoted file URL
|
|
436
|
+
// before the file hits disk. The script walks the exported config object,
|
|
437
|
+
// collects plugin source paths and dependency fingerprints into one JSON
|
|
438
|
+
// envelope for the parent. Arbitrary in-memory plugin objects do not need to
|
|
439
|
+
// cross the process boundary.
|
|
440
|
+
// The URL lives in a variable so tsgo does not statically resolve it.
|
|
441
|
+
/**
|
|
442
|
+
* The descriptor extractor's emitted source.
|
|
443
|
+
*
|
|
444
|
+
* Exported so a regression can inspect the same bytes the loader executes. The
|
|
445
|
+
* template consumes its own escapes, so reading this file's text instead would
|
|
446
|
+
* check characters no consumer ever sees.
|
|
447
|
+
*/
|
|
448
|
+
exports.TTSX_EXTRACTOR_SCRIPT = `// @ts-ignore -- internal loader must not require user-installed Node typings.
|
|
449
|
+
import * as fs from "node:fs";
|
|
450
|
+
// @ts-ignore -- internal loader must not require user-installed Node typings.
|
|
451
|
+
import { Buffer } from "node:buffer";
|
|
452
|
+
// @ts-ignore -- internal loader must not require user-installed Node typings.
|
|
453
|
+
import { createHash } from "node:crypto";
|
|
454
|
+
// @ts-ignore -- internal loader must not require user-installed Node typings.
|
|
455
|
+
import { createRequire, registerHooks } from "node:module";
|
|
456
|
+
// @ts-ignore -- internal loader must not require user-installed Node typings.
|
|
457
|
+
import * as path from "node:path";
|
|
458
|
+
// @ts-ignore -- internal loader must not require user-installed Node typings.
|
|
459
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
460
|
+
|
|
461
|
+
const configUrl = %CONFIG_IMPORT%;
|
|
462
|
+
const outputPath = %CONFIG_OUTPUT%;
|
|
463
|
+
const resolutionRoot = path.resolve(%CONFIG_ROOT%);
|
|
464
|
+
const CONFIG_KEYS = new Set<string>([
|
|
465
|
+
"files",
|
|
466
|
+
"ignores",
|
|
467
|
+
"extends",
|
|
468
|
+
"plugins",
|
|
469
|
+
"rules",
|
|
470
|
+
"format",
|
|
471
|
+
]);
|
|
472
|
+
const dependencies = new Map<string, {
|
|
473
|
+
digest: string;
|
|
474
|
+
identityStable: boolean;
|
|
475
|
+
kind: "directory" | "file" | "optional-file";
|
|
476
|
+
path: string;
|
|
477
|
+
owners: Set<string>;
|
|
478
|
+
realpath: string | null;
|
|
479
|
+
}>();
|
|
480
|
+
const graphNodes = new Map<string, string>();
|
|
481
|
+
const graphEdges: Array<{
|
|
482
|
+
child: string;
|
|
483
|
+
packageBoundary: boolean;
|
|
484
|
+
parent: string;
|
|
485
|
+
}> = [];
|
|
486
|
+
const configLocation = fileURLToPath(configUrl);
|
|
487
|
+
// Every spelling of this config the module system might key an edge under.
|
|
488
|
+
//
|
|
489
|
+
// Which one it uses is not knowable from here, and guessing has failed in both
|
|
490
|
+
// directions. A path handed in by another producer can be escaped by a rule
|
|
491
|
+
// Node does not share. Node respells a resolved file module through its real
|
|
492
|
+
// path unless "--preserve-symlinks" is set, so a config reached through a
|
|
493
|
+
// symlinked directory is keyed by its target. And a Windows 8.3 short name is
|
|
494
|
+
// not a symlink: fs.realpathSync expands it, the module resolver does not, so
|
|
495
|
+
// asking the volume there produces a spelling no edge carries.
|
|
496
|
+
//
|
|
497
|
+
// A seed that names a URL no edge was keyed under sits on a node with no
|
|
498
|
+
// outgoing edges, the walk ends immediately, and every dependency recorded
|
|
499
|
+
// after the first import is demoted from watch to cache. That failure is
|
|
500
|
+
// silent: the build still succeeds and simply stops reacting. Seeding every
|
|
501
|
+
// spelling costs one extra queue entry and cannot be wrong.
|
|
502
|
+
const configUrlSpellings = [
|
|
503
|
+
...new Set([
|
|
504
|
+
configUrl,
|
|
505
|
+
pathToFileURL(configLocation).href,
|
|
506
|
+
pathToFileURL(realConfigLocation()).href,
|
|
507
|
+
]),
|
|
508
|
+
];
|
|
509
|
+
const configEntryUrls = new Set(configUrlSpellings);
|
|
510
|
+
const moduleProbeExtensions = [
|
|
511
|
+
".ts",
|
|
512
|
+
".tsx",
|
|
513
|
+
".mts",
|
|
514
|
+
".cts",
|
|
515
|
+
".js",
|
|
516
|
+
".mjs",
|
|
517
|
+
".cjs",
|
|
518
|
+
".json",
|
|
519
|
+
".node",
|
|
520
|
+
] as const;
|
|
521
|
+
const jsToTsProbeExtensions = new Map<string, readonly string[]>([
|
|
522
|
+
[".js", [".ts", ".tsx"]],
|
|
523
|
+
[".jsx", [".tsx"]],
|
|
524
|
+
[".mjs", [".mts"]],
|
|
525
|
+
[".cjs", [".cts"]],
|
|
526
|
+
]);
|
|
527
|
+
for (const spelling of configUrlSpellings) {
|
|
528
|
+
graphNodes.set(spelling, configLocation);
|
|
529
|
+
}
|
|
530
|
+
recordDependency(
|
|
531
|
+
"file",
|
|
532
|
+
configLocation,
|
|
533
|
+
createHash("sha256").update(fs.readFileSync(configLocation)).digest("hex"),
|
|
534
|
+
configUrlSpellings,
|
|
535
|
+
);
|
|
536
|
+
recordPackageManifests(configLocation, configUrlSpellings);
|
|
537
|
+
|
|
538
|
+
declare const process: {
|
|
539
|
+
cwd(): string;
|
|
540
|
+
platform: string;
|
|
541
|
+
stdout: { write(value: string): void };
|
|
542
|
+
stderr: { write(value: string): void };
|
|
543
|
+
exit(code?: number): never;
|
|
544
|
+
};
|
|
545
|
+
|
|
546
|
+
const hooks = registerHooks({
|
|
547
|
+
resolve(specifier, context, nextResolve) {
|
|
548
|
+
const requestedParent =
|
|
549
|
+
context.parentURL && new URL(context.parentURL).href;
|
|
550
|
+
if (requestedParent !== undefined && graphNodes.has(requestedParent)) {
|
|
551
|
+
recordLocalResolutionCandidates(specifier, requestedParent);
|
|
552
|
+
}
|
|
553
|
+
const resolved = nextResolve(specifier, context);
|
|
554
|
+
if (typeof resolved.url !== "string" || !resolved.url.startsWith("file:")) {
|
|
555
|
+
return resolved;
|
|
556
|
+
}
|
|
557
|
+
const url = new URL(resolved.url).href;
|
|
558
|
+
const parent = context.parentURL && new URL(context.parentURL).href;
|
|
559
|
+
const location = fileURLToPath(url);
|
|
560
|
+
// The entry is recognized by what was asked for, not only by what came
|
|
561
|
+
// back. A module URL is assigned by whoever loaded it: a compiling loader
|
|
562
|
+
// can serve the config from its emitted output, and a platform can hand
|
|
563
|
+
// back a different spelling of the same file. Either way the URL bears no
|
|
564
|
+
// resemblance to the one this process was given, so the config's own
|
|
565
|
+
// imports would be rejected here — their parent is a URL no node was
|
|
566
|
+
// recorded under — and the graph would collapse to the records made before
|
|
567
|
+
// the first import. The request itself is unambiguous, so it decides.
|
|
568
|
+
const entry =
|
|
569
|
+
configEntryUrls.has(specifier) ||
|
|
570
|
+
url === new URL(configUrl).href ||
|
|
571
|
+
samePhysicalPath(location, configLocation);
|
|
572
|
+
if (!entry && (parent === undefined || !graphNodes.has(parent))) {
|
|
573
|
+
return resolved;
|
|
574
|
+
}
|
|
575
|
+
graphNodes.set(url, location);
|
|
576
|
+
if (entry && configEntryUrls.has(specifier) && specifier !== url) {
|
|
577
|
+
graphEdges.push({ child: url, packageBoundary: false, parent: specifier });
|
|
578
|
+
}
|
|
579
|
+
if (parent !== undefined) {
|
|
580
|
+
graphEdges.push({
|
|
581
|
+
child: url,
|
|
582
|
+
packageBoundary:
|
|
583
|
+
pathHasNodeModules(location) && !isLocalModuleSpecifier(specifier),
|
|
584
|
+
parent,
|
|
585
|
+
});
|
|
586
|
+
recordResolutionTopology(
|
|
587
|
+
specifier,
|
|
588
|
+
parent,
|
|
589
|
+
url,
|
|
590
|
+
location,
|
|
591
|
+
context.conditions,
|
|
592
|
+
);
|
|
593
|
+
}
|
|
594
|
+
try {
|
|
595
|
+
recordDependency(
|
|
596
|
+
"file",
|
|
597
|
+
location,
|
|
598
|
+
createHash("sha256").update(fs.readFileSync(location)).digest("hex"),
|
|
599
|
+
[url],
|
|
600
|
+
);
|
|
601
|
+
} catch {
|
|
602
|
+
// The evaluator remains authoritative for the load error. An unreadable
|
|
603
|
+
// dependency simply makes this result non-cacheable in the parent.
|
|
604
|
+
recordDependency("file", location, "", [url]);
|
|
605
|
+
}
|
|
606
|
+
return resolved;
|
|
607
|
+
},
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
// Wrapped and settled explicitly rather than written as a top-level await.
|
|
611
|
+
// The loader tsconfig's "module" now follows the config's own package, and
|
|
612
|
+
// TS1378 rejects top-level await under a CommonJS module option however this
|
|
613
|
+
// .mts file emits. The trailing catch is what a top-level await gave for
|
|
614
|
+
// free: without it a throw from the finally would leave the promise
|
|
615
|
+
// unsettled instead of failing the load.
|
|
616
|
+
(async () => {
|
|
617
|
+
try {
|
|
618
|
+
const importedConfig = configLocation.toLowerCase().endsWith(".json")
|
|
619
|
+
? JSON.parse(fs.readFileSync(configLocation, "utf8").replace(/^\uFEFF/, ""))
|
|
620
|
+
: await import(configUrl);
|
|
621
|
+
const current = await resolveConfig(importedConfig, true);
|
|
622
|
+
const entries = await collectPluginEntries(current, configLocation, %CONFIG_CHAIN%);
|
|
623
|
+
fs.writeFileSync(outputPath, JSON.stringify({
|
|
624
|
+
dependencies: finalizeDependencies(),
|
|
625
|
+
entries,
|
|
626
|
+
}), "utf8");
|
|
627
|
+
} catch (error) {
|
|
628
|
+
reportLoaderFailure(error);
|
|
629
|
+
} finally {
|
|
630
|
+
hooks.deregister();
|
|
631
|
+
}
|
|
632
|
+
})().catch((error) => {
|
|
633
|
+
// Reached only when the finally above throws: the catch already ends the
|
|
634
|
+
// process, so this is the deregistration's own failure, not the config's.
|
|
635
|
+
reportLoaderFailure(error);
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
// reportLoaderFailure ends this loader on an error it can name, on both of the
|
|
639
|
+
// channels the parent uses.
|
|
640
|
+
//
|
|
641
|
+
// The stack is for a reader and streams to stderr as it is written. The reason
|
|
642
|
+
// is a fact about the user's config that a caller has to act on, so it travels
|
|
643
|
+
// as data through the result file the parent already reads. Only a well-formed
|
|
644
|
+
// envelope is honoured there, so a partially written or unrelated file leaves
|
|
645
|
+
// the process status to speak for itself.
|
|
646
|
+
function reportLoaderFailure(error: unknown): never {
|
|
647
|
+
// The trailing newline ends the stack as a line of its own. Without it the
|
|
648
|
+
// parent's own message, written to this same stream, starts mid-line.
|
|
649
|
+
process.stderr.write((error instanceof Error && error.stack ? error.stack : String(error)) + "\\n");
|
|
650
|
+
try {
|
|
651
|
+
fs.writeFileSync(
|
|
652
|
+
outputPath,
|
|
653
|
+
JSON.stringify({ __ttscLoaderError: error instanceof Error ? error.message : String(error) }),
|
|
654
|
+
"utf8",
|
|
655
|
+
);
|
|
656
|
+
} catch {
|
|
657
|
+
// A reason that cannot be written leaves the exit status as the report.
|
|
658
|
+
}
|
|
659
|
+
return process.exit(1);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
function isObject(value: unknown): value is Record<string, unknown> {
|
|
663
|
+
return value !== null && typeof value === "object";
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
function recordDependency(
|
|
667
|
+
kind: "directory" | "file" | "optional-file",
|
|
668
|
+
location: string,
|
|
669
|
+
digest: string,
|
|
670
|
+
owners: readonly string[],
|
|
671
|
+
): void {
|
|
672
|
+
const key = kind + "\\0" + location;
|
|
673
|
+
const previous = dependencies.get(key);
|
|
674
|
+
const mergedOwners = previous?.owners ?? new Set<string>();
|
|
675
|
+
for (const owner of owners) mergedOwners.add(owner);
|
|
676
|
+
const realpath = dependencyRealpath(location);
|
|
677
|
+
const identityStable =
|
|
678
|
+
previous?.identityStable !== false &&
|
|
679
|
+
(previous === undefined || previous.realpath === realpath);
|
|
680
|
+
dependencies.set(key, {
|
|
681
|
+
digest:
|
|
682
|
+
!identityStable ||
|
|
683
|
+
(previous !== undefined && previous.digest !== digest)
|
|
684
|
+
? ""
|
|
685
|
+
: digest,
|
|
686
|
+
identityStable,
|
|
687
|
+
kind,
|
|
688
|
+
owners: mergedOwners,
|
|
689
|
+
path: location,
|
|
690
|
+
realpath,
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
function dependencyRealpath(location: string): string | null {
|
|
695
|
+
try {
|
|
696
|
+
return realPath(location);
|
|
697
|
+
} catch {
|
|
698
|
+
return null;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
function isLocalModuleSpecifier(specifier: string): boolean {
|
|
703
|
+
return specifier.startsWith(".") ||
|
|
704
|
+
specifier.startsWith("/") ||
|
|
705
|
+
specifier.startsWith("file:") ||
|
|
706
|
+
/^[A-Za-z]:[\\\\/]/.test(specifier);
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
function pathHasNodeModules(location: string): boolean {
|
|
710
|
+
return location.replaceAll("\\\\", "/").split("/").includes("node_modules");
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
function recordResolutionTopology(
|
|
714
|
+
specifier: string,
|
|
715
|
+
parentUrl: string,
|
|
716
|
+
childUrl: string,
|
|
717
|
+
childLocation: string,
|
|
718
|
+
conditions: readonly string[],
|
|
719
|
+
): void {
|
|
720
|
+
const owners = [parentUrl, childUrl];
|
|
721
|
+
const parentLocation = graphNodes.get(parentUrl);
|
|
722
|
+
if (parentLocation !== undefined && isLocalModuleSpecifier(specifier)) {
|
|
723
|
+
recordDirectoryDependency(path.dirname(parentLocation), owners);
|
|
724
|
+
}
|
|
725
|
+
recordDirectoryDependency(path.dirname(childLocation), owners);
|
|
726
|
+
recordPackageManifests(childLocation, owners);
|
|
727
|
+
if (parentLocation !== undefined && !isLocalModuleSpecifier(specifier)) {
|
|
728
|
+
recordNodeModulesSearchDirectories(
|
|
729
|
+
parentLocation,
|
|
730
|
+
specifier,
|
|
731
|
+
childLocation,
|
|
732
|
+
owners,
|
|
733
|
+
conditions,
|
|
734
|
+
);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
function recordDirectoryDependency(
|
|
739
|
+
location: string,
|
|
740
|
+
owners: readonly string[],
|
|
741
|
+
): void {
|
|
742
|
+
try {
|
|
743
|
+
recordDependency("directory", location, directoryDigest(location), owners);
|
|
744
|
+
} catch {
|
|
745
|
+
recordDependency("directory", location, "", owners);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
function directoryDigest(location: string): string {
|
|
750
|
+
const entries: Buffer[] = [];
|
|
751
|
+
if (process.platform === "win32") {
|
|
752
|
+
for (const entry of fs.readdirSync(location, { withFileTypes: true })) {
|
|
753
|
+
let target = Buffer.alloc(0);
|
|
754
|
+
if (entry.isSymbolicLink()) {
|
|
755
|
+
try {
|
|
756
|
+
target = Buffer.from(
|
|
757
|
+
fs.readlinkSync(path.join(location, entry.name)),
|
|
758
|
+
"utf8",
|
|
759
|
+
);
|
|
760
|
+
} catch {
|
|
761
|
+
target = Buffer.from("<unreadable>");
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
entries.push(directoryDigestRecord(Buffer.from(entry.name), entry, target));
|
|
765
|
+
}
|
|
766
|
+
} else {
|
|
767
|
+
for (const entry of fs.readdirSync(location, {
|
|
768
|
+
encoding: "buffer",
|
|
769
|
+
withFileTypes: true,
|
|
770
|
+
})) {
|
|
771
|
+
let target = Buffer.alloc(0);
|
|
772
|
+
if (entry.isSymbolicLink()) {
|
|
773
|
+
try {
|
|
774
|
+
target = fs.readlinkSync(
|
|
775
|
+
Buffer.concat([
|
|
776
|
+
Buffer.from(location),
|
|
777
|
+
Buffer.from(path.sep),
|
|
778
|
+
entry.name,
|
|
779
|
+
]),
|
|
780
|
+
{ encoding: "buffer" },
|
|
781
|
+
);
|
|
782
|
+
} catch {
|
|
783
|
+
target = Buffer.from("<unreadable>");
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
entries.push(directoryDigestRecord(entry.name, entry, target));
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
entries.sort(Buffer.compare);
|
|
790
|
+
const serialized = Buffer.concat(
|
|
791
|
+
entries.flatMap((entry, index) =>
|
|
792
|
+
index === 0 ? [entry] : [Buffer.from([0]), entry],
|
|
793
|
+
),
|
|
794
|
+
);
|
|
795
|
+
return createHash("sha256").update(serialized).digest("hex");
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
function directoryDigestRecord(
|
|
799
|
+
name: Buffer,
|
|
800
|
+
entry: {
|
|
801
|
+
isDirectory(): boolean;
|
|
802
|
+
isFile(): boolean;
|
|
803
|
+
isSymbolicLink(): boolean;
|
|
804
|
+
},
|
|
805
|
+
target: Buffer,
|
|
806
|
+
): Buffer {
|
|
807
|
+
const kind = entry.isDirectory()
|
|
808
|
+
? "directory"
|
|
809
|
+
: entry.isFile()
|
|
810
|
+
? "file"
|
|
811
|
+
: entry.isSymbolicLink()
|
|
812
|
+
? "symlink"
|
|
813
|
+
: "other";
|
|
814
|
+
return Buffer.concat([name, Buffer.from("\\0" + kind + "\\0"), target]);
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
function optionalFileDigest(location: string): string {
|
|
818
|
+
try {
|
|
819
|
+
const entry = fs.statSync(location);
|
|
820
|
+
if (entry.isFile()) {
|
|
821
|
+
return createHash("sha256")
|
|
822
|
+
.update(Buffer.concat([Buffer.from("file\\0"), fs.readFileSync(location)]))
|
|
823
|
+
.digest("hex");
|
|
824
|
+
}
|
|
825
|
+
if (entry.isDirectory()) {
|
|
826
|
+
return createHash("sha256")
|
|
827
|
+
.update("ttsc:host-input:directory\\0")
|
|
828
|
+
.digest("hex");
|
|
829
|
+
}
|
|
830
|
+
} catch {
|
|
831
|
+
// Missing and unreadable candidates share the absent state.
|
|
832
|
+
}
|
|
833
|
+
return createHash("sha256").update("missing\\0").digest("hex");
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
function recordOptionalFileDependency(
|
|
837
|
+
location: string,
|
|
838
|
+
owners: readonly string[],
|
|
839
|
+
): boolean {
|
|
840
|
+
try {
|
|
841
|
+
if (fs.statSync(location).isFile()) {
|
|
842
|
+
recordDependency(
|
|
843
|
+
"file",
|
|
844
|
+
location,
|
|
845
|
+
createHash("sha256").update(fs.readFileSync(location)).digest("hex"),
|
|
846
|
+
owners,
|
|
847
|
+
);
|
|
848
|
+
return true;
|
|
849
|
+
}
|
|
850
|
+
} catch {
|
|
851
|
+
// The exact missing path remains a dependency of the resolution result.
|
|
852
|
+
}
|
|
853
|
+
recordDependency("optional-file", location, optionalFileDigest(location), owners);
|
|
854
|
+
return false;
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
function moduleResolutionCandidates(base: string): string[] {
|
|
858
|
+
const extension = path.extname(base).toLowerCase();
|
|
859
|
+
const substitutions = jsToTsProbeExtensions.get(extension) ?? [];
|
|
860
|
+
const stem = base.slice(0, base.length - extension.length);
|
|
861
|
+
return [
|
|
862
|
+
base,
|
|
863
|
+
...substitutions.map((candidate) => stem + candidate),
|
|
864
|
+
...moduleProbeExtensions.map((candidate) => base + candidate),
|
|
865
|
+
path.join(base, "package.json"),
|
|
866
|
+
...moduleProbeExtensions.map((candidate) =>
|
|
867
|
+
path.join(base, "index" + candidate),
|
|
868
|
+
),
|
|
869
|
+
];
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
/** Record exact local probes before the runtime resolver chooses one. */
|
|
873
|
+
function recordLocalResolutionCandidates(
|
|
874
|
+
specifier: string,
|
|
875
|
+
parentUrl: string,
|
|
876
|
+
): void {
|
|
877
|
+
if (!isLocalModuleSpecifier(specifier)) return;
|
|
878
|
+
let bases: string[];
|
|
879
|
+
try {
|
|
880
|
+
if (specifier.startsWith("file:")) {
|
|
881
|
+
bases = [fileURLToPath(specifier)];
|
|
882
|
+
} else {
|
|
883
|
+
const directory = path.dirname(fileURLToPath(parentUrl));
|
|
884
|
+
const raw = path.resolve(directory, specifier);
|
|
885
|
+
const suffixStart = specifier.search(/[?#]/);
|
|
886
|
+
const pathname =
|
|
887
|
+
suffixStart === -1 ? specifier : specifier.slice(0, suffixStart);
|
|
888
|
+
bases = pathname === ""
|
|
889
|
+
? [raw]
|
|
890
|
+
: [...new Set([raw, path.resolve(directory, pathname)])];
|
|
891
|
+
}
|
|
892
|
+
} catch {
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
const owners = [parentUrl];
|
|
896
|
+
for (const base of bases) {
|
|
897
|
+
try {
|
|
898
|
+
if (fs.statSync(base).isFile()) {
|
|
899
|
+
recordOptionalFileDependency(base, owners);
|
|
900
|
+
continue;
|
|
901
|
+
}
|
|
902
|
+
} catch {
|
|
903
|
+
// A missing exact spelling falls through to source/extension/directory
|
|
904
|
+
// probes, all of which can redirect a later evaluation.
|
|
905
|
+
}
|
|
906
|
+
for (const candidate of moduleResolutionCandidates(base)) {
|
|
907
|
+
recordOptionalFileDependency(candidate, owners);
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
/** CommonJS LOAD_AS_FILE / LOAD_AS_DIRECTORY candidates for one legacy path. */
|
|
913
|
+
function recordLegacyPackagePathCandidates(
|
|
914
|
+
candidate: string,
|
|
915
|
+
owners: readonly string[],
|
|
916
|
+
): void {
|
|
917
|
+
for (const file of [
|
|
918
|
+
candidate,
|
|
919
|
+
candidate + ".js",
|
|
920
|
+
candidate + ".json",
|
|
921
|
+
candidate + ".node",
|
|
922
|
+
path.join(candidate, "package.json"),
|
|
923
|
+
path.join(candidate, "index.js"),
|
|
924
|
+
path.join(candidate, "index.json"),
|
|
925
|
+
path.join(candidate, "index.node"),
|
|
926
|
+
]) {
|
|
927
|
+
recordOptionalFileDependency(file, owners);
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
function recordPackageManifests(
|
|
932
|
+
location: string,
|
|
933
|
+
owners: readonly string[],
|
|
934
|
+
): void {
|
|
935
|
+
let current = path.dirname(location);
|
|
936
|
+
while (true) {
|
|
937
|
+
const manifest = path.join(current, "package.json");
|
|
938
|
+
if (recordOptionalFileDependency(manifest, owners)) return;
|
|
939
|
+
const parent = path.dirname(current);
|
|
940
|
+
if (parent === current || path.basename(current) === "node_modules") return;
|
|
941
|
+
current = parent;
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
function recordNodeModulesSearchDirectories(
|
|
946
|
+
parentLocation: string,
|
|
947
|
+
specifier: string,
|
|
948
|
+
childLocation: string,
|
|
949
|
+
owners: readonly string[],
|
|
950
|
+
conditions: readonly string[],
|
|
951
|
+
): void {
|
|
952
|
+
const packageName = modulePackageName(specifier);
|
|
953
|
+
const scope =
|
|
954
|
+
specifier.startsWith("@") && specifier.includes("/")
|
|
955
|
+
? specifier.slice(0, specifier.indexOf("/"))
|
|
956
|
+
: undefined;
|
|
957
|
+
let current = path.dirname(parentLocation);
|
|
958
|
+
while (true) {
|
|
959
|
+
// A newly created nearer node_modules directory can shadow the package
|
|
960
|
+
// selected by this evaluation, so missing search levels are dependencies.
|
|
961
|
+
recordDirectoryDependency(current, owners);
|
|
962
|
+
const modules = path.join(current, "node_modules");
|
|
963
|
+
try {
|
|
964
|
+
if (fs.statSync(modules).isDirectory()) {
|
|
965
|
+
recordDirectoryDependency(modules, owners);
|
|
966
|
+
if (scope !== undefined) {
|
|
967
|
+
const scoped = path.join(modules, scope);
|
|
968
|
+
try {
|
|
969
|
+
if (fs.statSync(scoped).isDirectory()) {
|
|
970
|
+
recordDirectoryDependency(scoped, owners);
|
|
971
|
+
}
|
|
972
|
+
} catch {
|
|
973
|
+
// The directory digest of node_modules records a missing scope.
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
} catch {
|
|
978
|
+
// Missing search levels do not participate in the current resolution.
|
|
979
|
+
}
|
|
980
|
+
if (packageName !== undefined) {
|
|
981
|
+
const selected = recordPackageCandidateTopology(
|
|
982
|
+
modules,
|
|
983
|
+
packageName,
|
|
984
|
+
specifier,
|
|
985
|
+
childLocation,
|
|
986
|
+
owners,
|
|
987
|
+
conditions,
|
|
988
|
+
);
|
|
989
|
+
if (
|
|
990
|
+
selected ||
|
|
991
|
+
resolvedPackageContains(modules, packageName, childLocation)
|
|
992
|
+
) {
|
|
993
|
+
return;
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
if (
|
|
997
|
+
packageName === undefined &&
|
|
998
|
+
samePhysicalPath(current, resolutionRoot)
|
|
999
|
+
) {
|
|
1000
|
+
return;
|
|
1001
|
+
}
|
|
1002
|
+
const parent = path.dirname(current);
|
|
1003
|
+
if (parent === current) return;
|
|
1004
|
+
current = parent;
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
function recordPackageCandidateTopology(
|
|
1009
|
+
modules: string,
|
|
1010
|
+
packageName: string,
|
|
1011
|
+
specifier: string,
|
|
1012
|
+
childLocation: string,
|
|
1013
|
+
owners: readonly string[],
|
|
1014
|
+
conditions: readonly string[],
|
|
1015
|
+
): boolean {
|
|
1016
|
+
const packageRoot = path.join(modules, packageName);
|
|
1017
|
+
const subpath = specifier
|
|
1018
|
+
.slice(packageName.length)
|
|
1019
|
+
.replace(/^[/\\\\]+/, "");
|
|
1020
|
+
try {
|
|
1021
|
+
if (!fs.statSync(packageRoot).isDirectory()) {
|
|
1022
|
+
recordOptionalFileDependency(
|
|
1023
|
+
path.join(packageRoot, "package.json"),
|
|
1024
|
+
owners,
|
|
1025
|
+
);
|
|
1026
|
+
recordLegacyPackagePathCandidates(
|
|
1027
|
+
subpath === "" ? packageRoot : path.join(packageRoot, subpath),
|
|
1028
|
+
owners,
|
|
1029
|
+
);
|
|
1030
|
+
return false;
|
|
1031
|
+
}
|
|
1032
|
+
} catch {
|
|
1033
|
+
recordOptionalFileDependency(
|
|
1034
|
+
path.join(packageRoot, "package.json"),
|
|
1035
|
+
owners,
|
|
1036
|
+
);
|
|
1037
|
+
recordLegacyPackagePathCandidates(
|
|
1038
|
+
subpath === "" ? packageRoot : path.join(packageRoot, subpath),
|
|
1039
|
+
owners,
|
|
1040
|
+
);
|
|
1041
|
+
return false;
|
|
1042
|
+
}
|
|
1043
|
+
const rootTopology = recordPackageRootTopology(
|
|
1044
|
+
packageRoot,
|
|
1045
|
+
owners,
|
|
1046
|
+
subpath === "",
|
|
1047
|
+
subpath === "" ? "." : "./" + subpath.replaceAll("\\\\", "/"),
|
|
1048
|
+
childLocation,
|
|
1049
|
+
conditions,
|
|
1050
|
+
);
|
|
1051
|
+
if (subpath !== "" && !rootTopology.hasExports) {
|
|
1052
|
+
return (
|
|
1053
|
+
recordPackageSubpathTopology(
|
|
1054
|
+
packageRoot,
|
|
1055
|
+
subpath,
|
|
1056
|
+
childLocation,
|
|
1057
|
+
owners,
|
|
1058
|
+
) || rootTopology.selected
|
|
1059
|
+
);
|
|
1060
|
+
}
|
|
1061
|
+
return rootTopology.selected;
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
function recordPackageRootTopology(
|
|
1065
|
+
packageRoot: string,
|
|
1066
|
+
owners: readonly string[],
|
|
1067
|
+
useMain: boolean,
|
|
1068
|
+
packageSubpath: string,
|
|
1069
|
+
childLocation: string,
|
|
1070
|
+
conditions: readonly string[],
|
|
1071
|
+
): { hasExports: boolean; selected: boolean } {
|
|
1072
|
+
const normalizedRoot = path.resolve(packageRoot);
|
|
1073
|
+
const manifest = path.join(normalizedRoot, "package.json");
|
|
1074
|
+
const legacySelected = (): boolean =>
|
|
1075
|
+
useMain &&
|
|
1076
|
+
packagePathCandidateMatchesChild(normalizedRoot, childLocation, true);
|
|
1077
|
+
if (useMain) recordLegacyPackagePathCandidates(normalizedRoot, owners);
|
|
1078
|
+
if (!recordOptionalFileDependency(manifest, owners)) {
|
|
1079
|
+
const selected = legacySelected();
|
|
1080
|
+
if (!selected) {
|
|
1081
|
+
recordPackageIndexCandidates(normalizedRoot, useMain, owners);
|
|
1082
|
+
}
|
|
1083
|
+
return { hasExports: false, selected };
|
|
1084
|
+
}
|
|
1085
|
+
try {
|
|
1086
|
+
const value = JSON.parse(fs.readFileSync(manifest, "utf8"));
|
|
1087
|
+
if (value !== null && typeof value === "object") {
|
|
1088
|
+
const metadata = value as Record<string, unknown>;
|
|
1089
|
+
const hasExports =
|
|
1090
|
+
metadata.exports !== undefined && metadata.exports !== null;
|
|
1091
|
+
if (hasExports) {
|
|
1092
|
+
const target = selectPackageExportsTarget(
|
|
1093
|
+
metadata.exports,
|
|
1094
|
+
packageSubpath,
|
|
1095
|
+
new Set(conditions),
|
|
1096
|
+
);
|
|
1097
|
+
const candidate =
|
|
1098
|
+
typeof target === "string"
|
|
1099
|
+
? packageExportsTarget(normalizedRoot, target)
|
|
1100
|
+
: undefined;
|
|
1101
|
+
const selected =
|
|
1102
|
+
candidate !== undefined &&
|
|
1103
|
+
packagePathCandidateMatchesChild(
|
|
1104
|
+
candidate,
|
|
1105
|
+
childLocation,
|
|
1106
|
+
false,
|
|
1107
|
+
);
|
|
1108
|
+
if (selected) {
|
|
1109
|
+
recordPackagePathCandidate(candidate, owners);
|
|
1110
|
+
} else if (candidate !== undefined) {
|
|
1111
|
+
// A nearer package the search skipped starts winning the moment its
|
|
1112
|
+
// own active target appears, and neither the parent node_modules
|
|
1113
|
+
// listing nor the manifest changes when only that file is created.
|
|
1114
|
+
recordOptionalFileDependency(candidate, owners);
|
|
1115
|
+
}
|
|
1116
|
+
return { hasExports: true, selected };
|
|
1117
|
+
}
|
|
1118
|
+
let selected = legacySelected();
|
|
1119
|
+
if (useMain && typeof metadata.main === "string") {
|
|
1120
|
+
// CommonJS main is a legacy path, not an exports target. Node resolves
|
|
1121
|
+
// it literally and permits absolute paths and paths outside the package.
|
|
1122
|
+
const main = path.resolve(normalizedRoot, metadata.main);
|
|
1123
|
+
recordPackagePathCandidate(main, owners);
|
|
1124
|
+
recordLegacyPackagePathCandidates(main, owners);
|
|
1125
|
+
selected =
|
|
1126
|
+
packagePathCandidateMatchesChild(main, childLocation, true) ||
|
|
1127
|
+
selected;
|
|
1128
|
+
}
|
|
1129
|
+
if (!selected) {
|
|
1130
|
+
recordPackageIndexCandidates(normalizedRoot, useMain, owners);
|
|
1131
|
+
}
|
|
1132
|
+
return {
|
|
1133
|
+
hasExports: false,
|
|
1134
|
+
selected,
|
|
1135
|
+
};
|
|
1136
|
+
}
|
|
1137
|
+
} catch {
|
|
1138
|
+
// Node owns malformed-manifest diagnostics; the manifest digest is enough
|
|
1139
|
+
// to invalidate this evaluation when its contents change.
|
|
1140
|
+
}
|
|
1141
|
+
const selected = legacySelected();
|
|
1142
|
+
if (!selected) {
|
|
1143
|
+
recordPackageIndexCandidates(normalizedRoot, useMain, owners);
|
|
1144
|
+
}
|
|
1145
|
+
return { hasExports: false, selected };
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
// recordPackageIndexCandidates pins the LOAD_INDEX fallbacks of a package root
|
|
1149
|
+
// this resolution walked past without selecting. An empty package directory, or
|
|
1150
|
+
// one whose manifest declares no usable entry, becomes resolvable as soon as one
|
|
1151
|
+
// of these files exists, and that creation changes neither the parent directory
|
|
1152
|
+
// listing nor the manifest digest already recorded for the candidate.
|
|
1153
|
+
function recordPackageIndexCandidates(
|
|
1154
|
+
packageRoot: string,
|
|
1155
|
+
useMain: boolean,
|
|
1156
|
+
owners: readonly string[],
|
|
1157
|
+
): void {
|
|
1158
|
+
if (!useMain) return;
|
|
1159
|
+
for (const name of ["index.js", "index.json", "index.node"]) {
|
|
1160
|
+
recordOptionalFileDependency(path.join(packageRoot, name), owners);
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
function selectPackageExportsTarget(
|
|
1165
|
+
exportsValue: unknown,
|
|
1166
|
+
packageSubpath: string,
|
|
1167
|
+
conditions: ReadonlySet<string>,
|
|
1168
|
+
): string | null | undefined {
|
|
1169
|
+
let mappings: unknown = exportsValue;
|
|
1170
|
+
if (
|
|
1171
|
+
typeof mappings === "string" ||
|
|
1172
|
+
Array.isArray(mappings) ||
|
|
1173
|
+
(isObject(mappings) &&
|
|
1174
|
+
Object.keys(mappings).every((key) => !key.startsWith(".")))
|
|
1175
|
+
) {
|
|
1176
|
+
if (packageSubpath !== ".") return undefined;
|
|
1177
|
+
return selectPackageTarget(mappings, "", false, conditions);
|
|
1178
|
+
}
|
|
1179
|
+
if (!isObject(mappings)) return undefined;
|
|
1180
|
+
if (
|
|
1181
|
+
Object.prototype.hasOwnProperty.call(mappings, packageSubpath) &&
|
|
1182
|
+
!packageSubpath.includes("*") &&
|
|
1183
|
+
!packageSubpath.endsWith("/")
|
|
1184
|
+
) {
|
|
1185
|
+
return selectPackageTarget(
|
|
1186
|
+
mappings[packageSubpath],
|
|
1187
|
+
"",
|
|
1188
|
+
false,
|
|
1189
|
+
conditions,
|
|
1190
|
+
);
|
|
1191
|
+
}
|
|
1192
|
+
let bestMatch = "";
|
|
1193
|
+
let bestSubpath = "";
|
|
1194
|
+
for (const key of Object.keys(mappings)) {
|
|
1195
|
+
const wildcard = key.indexOf("*");
|
|
1196
|
+
if (
|
|
1197
|
+
wildcard === -1 ||
|
|
1198
|
+
key.lastIndexOf("*") !== wildcard ||
|
|
1199
|
+
!packageSubpath.startsWith(key.slice(0, wildcard))
|
|
1200
|
+
) {
|
|
1201
|
+
continue;
|
|
1202
|
+
}
|
|
1203
|
+
const trailer = key.slice(wildcard + 1);
|
|
1204
|
+
if (
|
|
1205
|
+
packageSubpath.length < key.length ||
|
|
1206
|
+
!packageSubpath.endsWith(trailer) ||
|
|
1207
|
+
packagePatternKeyCompare(bestMatch, key) !== 1
|
|
1208
|
+
) {
|
|
1209
|
+
continue;
|
|
1210
|
+
}
|
|
1211
|
+
bestMatch = key;
|
|
1212
|
+
bestSubpath = packageSubpath.slice(
|
|
1213
|
+
wildcard,
|
|
1214
|
+
packageSubpath.length - trailer.length,
|
|
1215
|
+
);
|
|
1216
|
+
}
|
|
1217
|
+
return bestMatch === ""
|
|
1218
|
+
? undefined
|
|
1219
|
+
: selectPackageTarget(
|
|
1220
|
+
mappings[bestMatch],
|
|
1221
|
+
bestSubpath,
|
|
1222
|
+
true,
|
|
1223
|
+
conditions,
|
|
1224
|
+
);
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
function selectPackageTarget(
|
|
1228
|
+
target: unknown,
|
|
1229
|
+
subpath: string,
|
|
1230
|
+
pattern: boolean,
|
|
1231
|
+
conditions: ReadonlySet<string>,
|
|
1232
|
+
): string | null | undefined {
|
|
1233
|
+
if (typeof target === "string") {
|
|
1234
|
+
const selected = pattern ? target.replaceAll("*", subpath) : target;
|
|
1235
|
+
return validPackageExportsTarget(selected) ? selected : undefined;
|
|
1236
|
+
}
|
|
1237
|
+
if (Array.isArray(target)) {
|
|
1238
|
+
for (const item of target) {
|
|
1239
|
+
const selected = selectPackageTarget(
|
|
1240
|
+
item,
|
|
1241
|
+
subpath,
|
|
1242
|
+
pattern,
|
|
1243
|
+
conditions,
|
|
1244
|
+
);
|
|
1245
|
+
if (selected !== undefined && selected !== null) return selected;
|
|
1246
|
+
}
|
|
1247
|
+
return null;
|
|
1248
|
+
}
|
|
1249
|
+
if (isObject(target)) {
|
|
1250
|
+
for (const [condition, value] of Object.entries(target)) {
|
|
1251
|
+
if (condition !== "default" && !conditions.has(condition)) continue;
|
|
1252
|
+
const selected = selectPackageTarget(
|
|
1253
|
+
value,
|
|
1254
|
+
subpath,
|
|
1255
|
+
pattern,
|
|
1256
|
+
conditions,
|
|
1257
|
+
);
|
|
1258
|
+
if (selected !== undefined) return selected;
|
|
1259
|
+
}
|
|
1260
|
+
return undefined;
|
|
1261
|
+
}
|
|
1262
|
+
return target === null ? null : undefined;
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
function packagePatternKeyCompare(left: string, right: string): number {
|
|
1266
|
+
const leftWildcard = left.indexOf("*");
|
|
1267
|
+
const rightWildcard = right.indexOf("*");
|
|
1268
|
+
const leftBase =
|
|
1269
|
+
leftWildcard === -1 ? left.length : leftWildcard + 1;
|
|
1270
|
+
const rightBase =
|
|
1271
|
+
rightWildcard === -1 ? right.length : rightWildcard + 1;
|
|
1272
|
+
if (leftBase > rightBase) return -1;
|
|
1273
|
+
if (rightBase > leftBase) return 1;
|
|
1274
|
+
if (leftWildcard === -1) return 1;
|
|
1275
|
+
if (rightWildcard === -1) return -1;
|
|
1276
|
+
if (left.length > right.length) return -1;
|
|
1277
|
+
if (right.length > left.length) return 1;
|
|
1278
|
+
return 0;
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
function packageExportsTarget(
|
|
1282
|
+
packageRoot: string,
|
|
1283
|
+
target: string,
|
|
1284
|
+
): string | undefined {
|
|
1285
|
+
if (!validPackageExportsTarget(target)) return undefined;
|
|
1286
|
+
try {
|
|
1287
|
+
// Node resolves an exports target as a URL against the package manifest,
|
|
1288
|
+
// so percent escapes, query strings, and fragments all take part in the
|
|
1289
|
+
// path it finally loads. Joining the raw target by hand diverges from that
|
|
1290
|
+
// whenever the target is anything but a plain relative path, and a target
|
|
1291
|
+
// Node resolves while this model rejects loses the selected file's
|
|
1292
|
+
// fingerprint, leaving a retargeted symlink cached as fresh.
|
|
1293
|
+
const packageUrl = pathToFileURL(path.join(packageRoot, "package.json"));
|
|
1294
|
+
const resolved = new URL(target, packageUrl);
|
|
1295
|
+
const packagePath = new URL(".", packageUrl).pathname;
|
|
1296
|
+
if (!resolved.pathname.startsWith(packagePath)) return undefined;
|
|
1297
|
+
return fileURLToPath(resolved);
|
|
1298
|
+
} catch {
|
|
1299
|
+
return undefined;
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
function validPackageExportsTarget(target: string): boolean {
|
|
1304
|
+
if (!target.startsWith("./") || /%2f|%5c/i.test(target)) return false;
|
|
1305
|
+
const components = target
|
|
1306
|
+
.slice(2)
|
|
1307
|
+
.replaceAll("\\\\", "/")
|
|
1308
|
+
.split("/");
|
|
1309
|
+
if (
|
|
1310
|
+
components.some(
|
|
1311
|
+
(component) => {
|
|
1312
|
+
try {
|
|
1313
|
+
const decoded = decodeURIComponent(component);
|
|
1314
|
+
return (
|
|
1315
|
+
decoded === "." ||
|
|
1316
|
+
decoded === ".." ||
|
|
1317
|
+
decoded.includes("/") ||
|
|
1318
|
+
decoded.includes("\\\\") ||
|
|
1319
|
+
decoded.toLowerCase() === "node_modules"
|
|
1320
|
+
);
|
|
1321
|
+
} catch {
|
|
1322
|
+
return true;
|
|
1323
|
+
}
|
|
1324
|
+
},
|
|
1325
|
+
)
|
|
1326
|
+
) {
|
|
1327
|
+
return false;
|
|
1328
|
+
}
|
|
1329
|
+
return true;
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
function packagePathCandidateMatchesChild(
|
|
1333
|
+
candidate: string,
|
|
1334
|
+
childLocation: string,
|
|
1335
|
+
legacy: boolean,
|
|
1336
|
+
): boolean {
|
|
1337
|
+
let child: string;
|
|
1338
|
+
try {
|
|
1339
|
+
child = fs.realpathSync.native(childLocation);
|
|
1340
|
+
} catch {
|
|
1341
|
+
child = path.resolve(childLocation);
|
|
1342
|
+
}
|
|
1343
|
+
const candidates = legacy
|
|
1344
|
+
? [
|
|
1345
|
+
candidate,
|
|
1346
|
+
candidate + ".js",
|
|
1347
|
+
candidate + ".json",
|
|
1348
|
+
candidate + ".node",
|
|
1349
|
+
path.join(candidate, "index.js"),
|
|
1350
|
+
path.join(candidate, "index.json"),
|
|
1351
|
+
path.join(candidate, "index.node"),
|
|
1352
|
+
]
|
|
1353
|
+
: [candidate];
|
|
1354
|
+
return candidates.some((location) => {
|
|
1355
|
+
try {
|
|
1356
|
+
return sameResolutionPath(fs.realpathSync.native(location), child);
|
|
1357
|
+
} catch {
|
|
1358
|
+
return false;
|
|
1359
|
+
}
|
|
1360
|
+
});
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
function recordPackageSubpathTopology(
|
|
1364
|
+
packageRoot: string,
|
|
1365
|
+
subpath: string,
|
|
1366
|
+
childLocation: string,
|
|
1367
|
+
owners: readonly string[],
|
|
1368
|
+
): boolean {
|
|
1369
|
+
const candidate = boundedPackageTarget(packageRoot, subpath);
|
|
1370
|
+
if (candidate === undefined) return false;
|
|
1371
|
+
recordPackagePathCandidate(candidate, owners);
|
|
1372
|
+
recordLegacyPackagePathCandidates(candidate, owners);
|
|
1373
|
+
let selected = packagePathCandidateMatchesChild(
|
|
1374
|
+
candidate,
|
|
1375
|
+
childLocation,
|
|
1376
|
+
true,
|
|
1377
|
+
);
|
|
1378
|
+
try {
|
|
1379
|
+
if (!fs.statSync(candidate).isDirectory()) return selected;
|
|
1380
|
+
} catch {
|
|
1381
|
+
return selected;
|
|
1382
|
+
}
|
|
1383
|
+
const manifest = path.join(candidate, "package.json");
|
|
1384
|
+
if (!recordOptionalFileDependency(manifest, owners)) return selected;
|
|
1385
|
+
try {
|
|
1386
|
+
const value = JSON.parse(fs.readFileSync(manifest, "utf8"));
|
|
1387
|
+
if (value !== null && typeof value === "object") {
|
|
1388
|
+
const metadata = value as Record<string, unknown>;
|
|
1389
|
+
if (typeof metadata.main === "string") {
|
|
1390
|
+
const main = path.resolve(candidate, metadata.main);
|
|
1391
|
+
recordPackagePathCandidate(main, owners);
|
|
1392
|
+
recordLegacyPackagePathCandidates(main, owners);
|
|
1393
|
+
selected =
|
|
1394
|
+
packagePathCandidateMatchesChild(main, childLocation, true) ||
|
|
1395
|
+
selected;
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
} catch {
|
|
1399
|
+
// Node owns malformed nested-package diagnostics.
|
|
1400
|
+
}
|
|
1401
|
+
return selected;
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
function boundedPackageTarget(
|
|
1405
|
+
packageRoot: string,
|
|
1406
|
+
target: string,
|
|
1407
|
+
): string | undefined {
|
|
1408
|
+
const candidate = path.resolve(packageRoot, target);
|
|
1409
|
+
const relative = path.relative(packageRoot, candidate);
|
|
1410
|
+
if (
|
|
1411
|
+
relative === ".." ||
|
|
1412
|
+
relative.startsWith(".." + path.sep) ||
|
|
1413
|
+
path.isAbsolute(relative)
|
|
1414
|
+
) {
|
|
1415
|
+
return undefined;
|
|
1416
|
+
}
|
|
1417
|
+
return candidate;
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
function recordPackagePathCandidate(
|
|
1421
|
+
candidate: string,
|
|
1422
|
+
owners: readonly string[],
|
|
1423
|
+
visited: Set<string> = new Set(),
|
|
1424
|
+
depth = 0,
|
|
1425
|
+
): void {
|
|
1426
|
+
const normalized = path.resolve(candidate);
|
|
1427
|
+
// The depth bound owns termination. A platform-wide case fold would merge
|
|
1428
|
+
// paths that differ only by case, which a per-directory case-sensitive
|
|
1429
|
+
// Windows tree keeps distinct, and would truncate a valid symlink chain.
|
|
1430
|
+
if (depth >= 64 || visited.has(normalized)) return;
|
|
1431
|
+
visited.add(normalized);
|
|
1432
|
+
const parsed = path.parse(normalized);
|
|
1433
|
+
const components = normalized
|
|
1434
|
+
.slice(parsed.root.length)
|
|
1435
|
+
.split(path.sep)
|
|
1436
|
+
.filter(Boolean);
|
|
1437
|
+
let current = parsed.root;
|
|
1438
|
+
for (let index = 0; index < components.length; index++) {
|
|
1439
|
+
const component = components[index];
|
|
1440
|
+
const next = path.join(current, component);
|
|
1441
|
+
let entry: ReturnType<typeof fs.lstatSync>;
|
|
1442
|
+
try {
|
|
1443
|
+
entry = fs.lstatSync(next);
|
|
1444
|
+
} catch {
|
|
1445
|
+
recordDirectoryDependency(current, owners);
|
|
1446
|
+
return;
|
|
1447
|
+
}
|
|
1448
|
+
if (entry.isSymbolicLink()) {
|
|
1449
|
+
// The containing directory digest carries the raw link target.
|
|
1450
|
+
recordDirectoryDependency(current, owners);
|
|
1451
|
+
try {
|
|
1452
|
+
const target = fs.readlinkSync(next);
|
|
1453
|
+
const remainder = components.slice(index + 1);
|
|
1454
|
+
recordPackagePathCandidate(
|
|
1455
|
+
path.join(
|
|
1456
|
+
path.resolve(current, target),
|
|
1457
|
+
...remainder,
|
|
1458
|
+
),
|
|
1459
|
+
owners,
|
|
1460
|
+
visited,
|
|
1461
|
+
depth + 1,
|
|
1462
|
+
);
|
|
1463
|
+
} catch {
|
|
1464
|
+
// The lexical link record already carries the unreadable state.
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
let isDirectory = entry.isDirectory();
|
|
1468
|
+
if (entry.isSymbolicLink()) {
|
|
1469
|
+
try {
|
|
1470
|
+
isDirectory = fs.statSync(next).isDirectory();
|
|
1471
|
+
} catch {
|
|
1472
|
+
return;
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
if (index === components.length - 1) {
|
|
1476
|
+
recordDirectoryDependency(isDirectory ? next : current, owners);
|
|
1477
|
+
return;
|
|
1478
|
+
}
|
|
1479
|
+
if (!isDirectory) {
|
|
1480
|
+
recordDirectoryDependency(current, owners);
|
|
1481
|
+
return;
|
|
1482
|
+
}
|
|
1483
|
+
current = next;
|
|
1484
|
+
}
|
|
1485
|
+
recordDirectoryDependency(current, owners);
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
function modulePackageName(specifier: string): string | undefined {
|
|
1489
|
+
if (specifier.startsWith("@")) {
|
|
1490
|
+
const components = specifier.split("/");
|
|
1491
|
+
return components.length >= 2
|
|
1492
|
+
? components[0] + "/" + components[1]
|
|
1493
|
+
: undefined;
|
|
1494
|
+
}
|
|
1495
|
+
const [name] = specifier.split("/");
|
|
1496
|
+
return name && !name.startsWith("#") ? name : undefined;
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
function resolvedPackageContains(
|
|
1500
|
+
modules: string,
|
|
1501
|
+
packageName: string,
|
|
1502
|
+
childLocation: string,
|
|
1503
|
+
): boolean {
|
|
1504
|
+
try {
|
|
1505
|
+
const packageRoot = fs.realpathSync(path.join(modules, packageName));
|
|
1506
|
+
const child = fs.realpathSync(childLocation);
|
|
1507
|
+
const relative = path.relative(packageRoot, child);
|
|
1508
|
+
if (relative === ".." || relative.startsWith(".." + path.sep) || path.isAbsolute(relative)) {
|
|
1509
|
+
return false;
|
|
1510
|
+
}
|
|
1511
|
+
let ancestor = child;
|
|
1512
|
+
const depth = relative === "" ? 0 : relative.split(path.sep).length;
|
|
1513
|
+
for (let i = 0; i < depth; i++) ancestor = path.dirname(ancestor);
|
|
1514
|
+
return sameResolutionPath(packageRoot, ancestor);
|
|
1515
|
+
} catch {
|
|
1516
|
+
return false;
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
function sameResolutionPath(left: string, right: string): boolean {
|
|
1521
|
+
const leftPath = path.resolve(left);
|
|
1522
|
+
const rightPath = path.resolve(right);
|
|
1523
|
+
if (leftPath === rightPath) return true;
|
|
1524
|
+
if (path.relative(leftPath, rightPath) !== "") return false;
|
|
1525
|
+
// A native lexical case fold does not establish filesystem identity.
|
|
1526
|
+
// Verify case aliases without merging differently located hard links.
|
|
1527
|
+
try {
|
|
1528
|
+
const leftInfo = fs.statSync(leftPath, { bigint: true });
|
|
1529
|
+
const rightInfo = fs.statSync(rightPath, { bigint: true });
|
|
1530
|
+
return leftInfo.ino !== 0n && leftInfo.dev === rightInfo.dev && leftInfo.ino === rightInfo.ino;
|
|
1531
|
+
} catch {
|
|
1532
|
+
return false;
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
function samePhysicalPath(left: string, right: string): boolean {
|
|
1537
|
+
try {
|
|
1538
|
+
return sameResolutionPath(realPath(left), realPath(right));
|
|
1539
|
+
} catch {
|
|
1540
|
+
// Exact lexical spelling is still usable when a file disappears. A case
|
|
1541
|
+
// alias remains unproven until the filesystem identifies both paths.
|
|
1542
|
+
return sameResolutionPath(left, right);
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
/**
|
|
1547
|
+
* The config's real path, or its declared one when the volume will not say.
|
|
1548
|
+
*
|
|
1549
|
+
* A config can disappear between the host reading it and this loader starting,
|
|
1550
|
+
* and a throw here would replace a precise report from the import below with a
|
|
1551
|
+
* crash in bookkeeping. Seeding lexically instead only risks the demotion this
|
|
1552
|
+
* value exists to prevent, on a file that is already gone.
|
|
1553
|
+
*/
|
|
1554
|
+
function realConfigLocation(): string {
|
|
1555
|
+
try {
|
|
1556
|
+
return realPath(configLocation);
|
|
1557
|
+
} catch {
|
|
1558
|
+
return configLocation;
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
function realPath(location: string): string {
|
|
1563
|
+
return fs.realpathSync.native
|
|
1564
|
+
? fs.realpathSync.native(location)
|
|
1565
|
+
: fs.realpathSync(location);
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
function finalizeDependencies(): Array<{
|
|
1569
|
+
digest: string;
|
|
1570
|
+
identityStable: boolean;
|
|
1571
|
+
kind: "directory" | "file" | "optional-file";
|
|
1572
|
+
path: string;
|
|
1573
|
+
realpath: string | null;
|
|
1574
|
+
scope: "cache" | "watch";
|
|
1575
|
+
}> {
|
|
1576
|
+
// The evaluator may have observed a dependency, run arbitrary config code,
|
|
1577
|
+
// and then serialize after that path changed again. Re-read every recorded
|
|
1578
|
+
// dependency under its original ownership set. Differences between recorded
|
|
1579
|
+
// observations invalidate reuse; identical digest and realpath observations
|
|
1580
|
+
// do not establish that no transient replacement occurred between them.
|
|
1581
|
+
for (const dependency of [...dependencies.values()]) {
|
|
1582
|
+
recordDependency(
|
|
1583
|
+
dependency.kind,
|
|
1584
|
+
dependency.path,
|
|
1585
|
+
currentDependencyDigest(dependency.kind, dependency.path),
|
|
1586
|
+
[...dependency.owners],
|
|
1587
|
+
);
|
|
1588
|
+
}
|
|
1589
|
+
const watched = graphWatchReachability();
|
|
1590
|
+
return [...dependencies.values()].map(({ owners, ...dependency }) => ({
|
|
1591
|
+
...dependency,
|
|
1592
|
+
scope: [...owners].some((owner) => watched.has(owner))
|
|
1593
|
+
? "watch"
|
|
1594
|
+
: "cache",
|
|
1595
|
+
}));
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
function currentDependencyDigest(
|
|
1599
|
+
kind: "directory" | "file" | "optional-file",
|
|
1600
|
+
location: string,
|
|
1601
|
+
): string {
|
|
1602
|
+
try {
|
|
1603
|
+
if (kind === "directory") return directoryDigest(location);
|
|
1604
|
+
if (kind === "optional-file") return optionalFileDigest(location);
|
|
1605
|
+
return createHash("sha256")
|
|
1606
|
+
.update(fs.readFileSync(location))
|
|
1607
|
+
.digest("hex");
|
|
1608
|
+
} catch {
|
|
1609
|
+
return "";
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
function graphWatchReachability(): Set<string> {
|
|
1614
|
+
const adjacency = new Map<string, typeof graphEdges>();
|
|
1615
|
+
for (const edge of graphEdges) {
|
|
1616
|
+
const outgoing = adjacency.get(edge.parent) ?? [];
|
|
1617
|
+
outgoing.push(edge);
|
|
1618
|
+
adjacency.set(edge.parent, outgoing);
|
|
1619
|
+
}
|
|
1620
|
+
const queue: Array<{ url: string; watched: boolean }> =
|
|
1621
|
+
configUrlSpellings.map((url) => ({ url, watched: true }));
|
|
1622
|
+
const visited = new Set<string>();
|
|
1623
|
+
const watched = new Set<string>();
|
|
1624
|
+
for (let head = 0; head < queue.length; head++) {
|
|
1625
|
+
const state = queue[head]!;
|
|
1626
|
+
const key = state.url + "\\0" + (state.watched ? "1" : "0");
|
|
1627
|
+
if (visited.has(key)) continue;
|
|
1628
|
+
visited.add(key);
|
|
1629
|
+
if (state.watched) watched.add(state.url);
|
|
1630
|
+
for (const edge of adjacency.get(state.url) ?? []) {
|
|
1631
|
+
const childLocation = graphNodes.get(edge.child);
|
|
1632
|
+
const childWatched = edge.packageBoundary
|
|
1633
|
+
? false
|
|
1634
|
+
: childLocation !== undefined && !pathHasNodeModules(childLocation)
|
|
1635
|
+
? true
|
|
1636
|
+
: state.watched;
|
|
1637
|
+
queue.push({ url: edge.child, watched: childWatched });
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
return watched;
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
function hasOwn(value: Record<string, unknown>, key: string): boolean {
|
|
1644
|
+
return Object.prototype.hasOwnProperty.call(value, key);
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
async function resolveConfig(value: unknown, allowNamedConfig: boolean): Promise<unknown> {
|
|
1648
|
+
let current = value;
|
|
1649
|
+
for (let i = 0; i < 8; i++) {
|
|
1650
|
+
if (typeof current === "function") {
|
|
1651
|
+
current = await (current as () => unknown | Promise<unknown>)();
|
|
1652
|
+
allowNamedConfig = false;
|
|
1653
|
+
continue;
|
|
1654
|
+
}
|
|
1655
|
+
if (isObject(current) && !Array.isArray(current)) {
|
|
1656
|
+
if (hasOwn(current, "default")) {
|
|
1657
|
+
const defaultValue = current.default;
|
|
1658
|
+
if (isModuleNamespace(current) || !hasConfigKey(current)) {
|
|
1659
|
+
current = defaultValue;
|
|
1660
|
+
allowNamedConfig = false;
|
|
1661
|
+
continue;
|
|
1662
|
+
}
|
|
1663
|
+
const normalizedDefault = await resolveConfig(defaultValue, false);
|
|
1664
|
+
if (isObject(normalizedDefault) && !Array.isArray(normalizedDefault)) {
|
|
1665
|
+
current = mergeConfigObjects(normalizedDefault, current);
|
|
1666
|
+
allowNamedConfig = false;
|
|
1667
|
+
continue;
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
if (allowNamedConfig && hasOwn(current, "config")) {
|
|
1671
|
+
current = current.config;
|
|
1672
|
+
allowNamedConfig = false;
|
|
1673
|
+
continue;
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
break;
|
|
1677
|
+
}
|
|
1678
|
+
return current;
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
function isModuleNamespace(value: Record<string, unknown>): boolean {
|
|
1682
|
+
return Object.prototype.toString.call(value) === "[object Module]";
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
function hasConfigKey(value: Record<string, unknown>): boolean {
|
|
1686
|
+
for (const key of CONFIG_KEYS) {
|
|
1687
|
+
if (hasOwn(value, key)) {
|
|
1688
|
+
return true;
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
return false;
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
function mergeConfigObjects(
|
|
1695
|
+
base: Record<string, unknown>,
|
|
1696
|
+
override: Record<string, unknown>,
|
|
1697
|
+
): Record<string, unknown> {
|
|
1698
|
+
const out: Record<string, unknown> = {};
|
|
1699
|
+
for (const key of CONFIG_KEYS) {
|
|
1700
|
+
if (hasOwn(base, key)) {
|
|
1701
|
+
out[key] = base[key];
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
for (const key of CONFIG_KEYS) {
|
|
1705
|
+
if (hasOwn(override, key)) {
|
|
1706
|
+
out[key] = override[key];
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
return out;
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
// Follow the same containing-file-relative, base-first extends chain as the
|
|
1713
|
+
// native config reader. Each explicit base is a watch input even when it lives
|
|
1714
|
+
// in node_modules; imports made by that base retain ordinary package boundaries.
|
|
1715
|
+
async function collectPluginEntries(
|
|
1716
|
+
value: unknown,
|
|
1717
|
+
location: string,
|
|
1718
|
+
chain: readonly string[],
|
|
1719
|
+
): Promise<Array<{ namespace: string; source: string } | { configFile: string; chain: readonly string[] }>> {
|
|
1720
|
+
const out: Array<{ namespace: string; source: string } | { configFile: string; chain: readonly string[] }> = [];
|
|
1721
|
+
if (Array.isArray(value)) {
|
|
1722
|
+
for (const item of value) out.push(...await collectPluginEntries(item, location, chain));
|
|
1723
|
+
return out;
|
|
1724
|
+
}
|
|
1725
|
+
if (!isObject(value)) return out;
|
|
1726
|
+
if (value.extends !== undefined && value.extends !== null) {
|
|
1727
|
+
if (typeof value.extends !== "string" || value.extends.trim() === "") {
|
|
1728
|
+
throw new Error("extends must be a non-empty string path to another config file");
|
|
1729
|
+
}
|
|
1730
|
+
const next = path.resolve(path.dirname(location), value.extends);
|
|
1731
|
+
if (chain.includes(next)) {
|
|
1732
|
+
throw new Error("extends cycle detected: " + [...chain, next].join(" -> "));
|
|
1733
|
+
}
|
|
1734
|
+
if (chain.length >= 32) {
|
|
1735
|
+
throw new Error("extends chain exceeds the depth limit of 32: " + chain.join(" -> "));
|
|
1736
|
+
}
|
|
1737
|
+
const nextUrl = pathToFileURL(next).href;
|
|
1738
|
+
const parentUrl = pathToFileURL(location).href;
|
|
1739
|
+
configEntryUrls.add(nextUrl);
|
|
1740
|
+
graphNodes.set(nextUrl, next);
|
|
1741
|
+
graphEdges.push({ child: nextUrl, packageBoundary: false, parent: parentUrl });
|
|
1742
|
+
recordDependency("file", next, createHash("sha256").update(fs.readFileSync(next)).digest("hex"), [nextUrl]);
|
|
1743
|
+
recordPackageManifests(next, [nextUrl]);
|
|
1744
|
+
// The owning parent evaluates typed bases under their own synthetic project.
|
|
1745
|
+
// A dynamic import here would give a typed base the consumer's tsconfig
|
|
1746
|
+
// when it falls outside this evaluator's entry manifest.
|
|
1747
|
+
if ([".ts", ".cts", ".mts"].includes(path.extname(next).toLowerCase())) {
|
|
1748
|
+
out.push({ configFile: next, chain: [...chain, next] });
|
|
1749
|
+
} else {
|
|
1750
|
+
const imported = next.toLowerCase().endsWith(".json")
|
|
1751
|
+
? JSON.parse(fs.readFileSync(next, "utf8").replace(/^\uFEFF/, ""))
|
|
1752
|
+
: await import(nextUrl);
|
|
1753
|
+
const base = await resolveConfig(imported, true);
|
|
1754
|
+
out.push(...await collectPluginEntries(base, next, [...chain, next]));
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
if (hasOwn(value, "plugins") && isObject(value.plugins)) {
|
|
1758
|
+
for (const [namespace, plugin] of Object.entries(value.plugins)) {
|
|
1759
|
+
const source = extractPluginSource(plugin, location);
|
|
1760
|
+
if (source === undefined || source.length === 0) {
|
|
1761
|
+
throw new Error("contributor " + JSON.stringify(namespace) + " must resolve to an object with a non-empty source string");
|
|
1762
|
+
}
|
|
1763
|
+
out.push({ namespace, source });
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
return out;
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
function extractPluginSource(value: unknown, location: string): string | undefined {
|
|
1770
|
+
if (typeof value === "string") {
|
|
1771
|
+
value = createRequire(pathToFileURL(location))(value);
|
|
1772
|
+
}
|
|
1773
|
+
if (!isObject(value)) return undefined;
|
|
1774
|
+
// ESM-from-CJS interop wraps CJS modules' \`exports.default\` so the
|
|
1775
|
+
// plugin object can land under a \`.default\` indirection. Walk a few
|
|
1776
|
+
// hops so contributors authored as \`export default plugin\` and
|
|
1777
|
+
// contributors authored as plain \`module.exports = plugin\` both
|
|
1778
|
+
// resolve identically.
|
|
1779
|
+
let current: Record<string, unknown> = value;
|
|
1780
|
+
// Bound default-wrapper traversal so a cyclic descriptor cannot loop.
|
|
1781
|
+
for (let i = 0; i < 8; i++) {
|
|
1782
|
+
if (typeof current.source === "string") break;
|
|
1783
|
+
const next = current.default;
|
|
1784
|
+
if (!isObject(next)) break;
|
|
1785
|
+
current = next;
|
|
1786
|
+
}
|
|
1787
|
+
const source = current.source;
|
|
1788
|
+
return typeof source === "string" ? source : undefined;
|
|
1789
|
+
}
|
|
1790
|
+
`;
|
|
1791
|
+
/**
|
|
1792
|
+
* Resolves contributor plugin entries declared in any executable lint config,
|
|
1793
|
+
* memoized through the shared on-disk config cache.
|
|
1794
|
+
*
|
|
1795
|
+
* Evaluating such a config spawns a full `ttsx` subprocess. Typed extends bases
|
|
1796
|
+
* additionally use their own synthetic project and launcher, so their package
|
|
1797
|
+
* format is not replaced by the consuming project's compiler options.
|
|
1798
|
+
* JavaScript and JSON bases share their containing evaluator. A monorepo build
|
|
1799
|
+
* runs one `ttsc` process per package. A completed cache entry avoids another
|
|
1800
|
+
* evaluation of the same unchanged config; simultaneous cold processes may
|
|
1801
|
+
* still evaluate it independently. The cache key covers the entry's path and
|
|
1802
|
+
* exact contents; the payload also fingerprints every local module reached from
|
|
1803
|
+
* that entry. An entry or helper edit therefore re-evaluates cleanly without
|
|
1804
|
+
* treating installed packages as project watch inputs.
|
|
1805
|
+
*/
|
|
1806
|
+
function readTtsxConfigPlugins(configPath, context) {
|
|
1807
|
+
const resolutionRoot = node_path_1.default.resolve(pluginConfigBaseDir(context));
|
|
1808
|
+
const cacheKey = configCacheKey(`plugins\0${resolutionRoot}`, configPath);
|
|
1809
|
+
if (cacheKey) {
|
|
1810
|
+
const cached = readConfigPluginCache(cacheKey);
|
|
1811
|
+
// Re-validate cached entries before trusting them: a contributor's
|
|
1812
|
+
// resolved `source` directory may have moved since the entry was
|
|
1813
|
+
// written. A stale entry falls through to a fresh evaluation rather
|
|
1814
|
+
// than being forwarded to ttsc's plugin builder as a dead path.
|
|
1815
|
+
if (cached &&
|
|
1816
|
+
cached.entries.every(isValidConfigPluginEntry) &&
|
|
1817
|
+
configDependenciesAreCurrent(cached.dependencies)) {
|
|
1818
|
+
return cached;
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
// A config can be saved while it is being evaluated. Retry a bounded number
|
|
1822
|
+
// of times until every dependency still has the bytes the module hook saw.
|
|
1823
|
+
// A continuously changing config remains usable but is deliberately not
|
|
1824
|
+
// cached; watch will schedule another cycle.
|
|
1825
|
+
let evaluation;
|
|
1826
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
1827
|
+
evaluation = evaluateTtsxConfigPlugins(configPath, context);
|
|
1828
|
+
if (configDependenciesAreCurrent(evaluation.dependencies)) {
|
|
1829
|
+
if (cacheKey)
|
|
1830
|
+
writeConfigPluginCache(cacheKey, evaluation);
|
|
1831
|
+
return evaluation;
|
|
1832
|
+
}
|
|
1833
|
+
}
|
|
1834
|
+
return evaluation;
|
|
1835
|
+
}
|
|
1836
|
+
/**
|
|
1837
|
+
* Reports whether a cached plugin entry is still usable: a well-formed
|
|
1838
|
+
* namespace and an absolute `source` that still points at a directory. Pure
|
|
1839
|
+
* predicate — never throws — so a malformed cache entry simply triggers
|
|
1840
|
+
* re-evaluation instead of aborting plugin discovery.
|
|
1841
|
+
*/
|
|
1842
|
+
function isValidConfigPluginEntry(entry) {
|
|
1843
|
+
if (entry == null ||
|
|
1844
|
+
typeof entry !== "object" ||
|
|
1845
|
+
typeof entry.namespace !== "string" ||
|
|
1846
|
+
typeof entry.source !== "string") {
|
|
1847
|
+
return false;
|
|
1848
|
+
}
|
|
1849
|
+
const { namespace, source } = entry;
|
|
1850
|
+
if (!NAMESPACE_PATTERN.test(namespace) || !node_path_1.default.isAbsolute(source)) {
|
|
1851
|
+
return false;
|
|
1852
|
+
}
|
|
1853
|
+
try {
|
|
1854
|
+
return node_fs_1.default.statSync(source).isDirectory();
|
|
1855
|
+
}
|
|
1856
|
+
catch {
|
|
1857
|
+
return false;
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
/**
|
|
1861
|
+
* Evaluate typed bases with their own project and merge base-first entries and
|
|
1862
|
+
* observed inputs. JavaScript and JSON bases remain in their containing
|
|
1863
|
+
* evaluator. A call-owned memo avoids evaluating the same typed base twice; no
|
|
1864
|
+
* result escapes the validated aggregate config cache.
|
|
1865
|
+
*/
|
|
1866
|
+
function evaluateTtsxConfigPlugins(configPath, context, chain = [configPath], evaluated = new Map()) {
|
|
1867
|
+
const existing = evaluated.get(configPath);
|
|
1868
|
+
if (existing !== undefined)
|
|
1869
|
+
return existing;
|
|
1870
|
+
const tempDir = createCanonicalTempDirectory("ttsc-lint-cfg-", loaderTempBase(configPath));
|
|
1871
|
+
try {
|
|
1872
|
+
linkNearestNodeModules(tempDir, node_path_1.default.dirname(configPath));
|
|
1873
|
+
const loaderPath = node_path_1.default.join(tempDir, "loader.mts");
|
|
1874
|
+
const outputPath = node_path_1.default.join(tempDir, "result.json");
|
|
1875
|
+
const tsconfigPath = node_path_1.default.join(tempDir, "tsconfig.json");
|
|
1876
|
+
const loaderSource = exports.TTSX_EXTRACTOR_SCRIPT.replace("%CONFIG_IMPORT%", JSON.stringify((0, node_url_1.pathToFileURL)(configPath).href))
|
|
1877
|
+
.replace("%CONFIG_CHAIN%", JSON.stringify(chain))
|
|
1878
|
+
.replace("%CONFIG_OUTPUT%", JSON.stringify(outputPath))
|
|
1879
|
+
.replace("%CONFIG_ROOT%", JSON.stringify(node_path_1.default.resolve(pluginConfigBaseDir(context))));
|
|
1880
|
+
node_fs_1.default.writeFileSync(loaderPath, loaderSource, "utf8");
|
|
1881
|
+
node_fs_1.default.writeFileSync(tsconfigPath, JSON.stringify({
|
|
1882
|
+
compilerOptions: {
|
|
1883
|
+
// `.mjs` and `.js` configs reach this loader because Node
|
|
1884
|
+
// cannot `require()` ESM synchronously; ttsx's TypeScript
|
|
1885
|
+
// project compiler refuses to admit them without `allowJs`,
|
|
1886
|
+
// so set it alongside the strict bypass to make the loader
|
|
1887
|
+
// tolerant of any of `lint.config.{ts,cts,mts,js,mjs,cjs}`.
|
|
1888
|
+
allowImportingTsExtensions: true,
|
|
1889
|
+
allowJs: true,
|
|
1890
|
+
checkJs: false,
|
|
1891
|
+
// The config is a Node module, so Node's rule decides its format:
|
|
1892
|
+
// the nearest `package.json` `type` above it. Hardcoding one answer
|
|
1893
|
+
// ran every ambiguous `.ts` config as ESM and broke `__dirname` in
|
|
1894
|
+
// an ordinary CommonJS package (#1068). `moduleResolution` stays
|
|
1895
|
+
// `bundler`, which tsgo accepts for both kinds, so extensionless
|
|
1896
|
+
// relative imports keep resolving either way.
|
|
1897
|
+
module: configModuleOption(configPath),
|
|
1898
|
+
moduleResolution: "bundler",
|
|
1899
|
+
noImplicitAny: false,
|
|
1900
|
+
outDir: node_path_1.default.join(tempDir, "out").replace(/\\/g, "/"),
|
|
1901
|
+
rewriteRelativeImportExtensions: true,
|
|
1902
|
+
rootDir: node_path_1.default.parse(tempDir).root.replace(/\\/g, "/"),
|
|
1903
|
+
skipLibCheck: true,
|
|
1904
|
+
strict: false,
|
|
1905
|
+
target: "ES2022",
|
|
1906
|
+
// TypeScript 7 includes no ambient type package unless `types` asks
|
|
1907
|
+
// for it, and this Program extends nothing, so without the wildcard
|
|
1908
|
+
// a config could not name a single Node global (#1068). The loader
|
|
1909
|
+
// directory links the config's nearest `node_modules`, so the
|
|
1910
|
+
// default `typeRoots` walk finds exactly what the project installed.
|
|
1911
|
+
types: ["*"],
|
|
1912
|
+
},
|
|
1913
|
+
files: [
|
|
1914
|
+
loaderPath.replace(/\\/g, "/"),
|
|
1915
|
+
...(node_path_1.default.extname(configPath).toLowerCase() === ".json"
|
|
1916
|
+
? []
|
|
1917
|
+
: [configPath.replace(/\\/g, "/")]),
|
|
1918
|
+
],
|
|
1919
|
+
}, null, 2), "utf8");
|
|
1920
|
+
// The config comes first, so a project that pins its own ttsc gets it. This
|
|
1921
|
+
// descriptor's own location comes second, because a fixture or a workspace
|
|
1922
|
+
// that installs only the lint package cannot resolve ttsc from the config
|
|
1923
|
+
// at all, and the descriptor always sits beside the host that loaded it.
|
|
1924
|
+
const ttsxBinary = resolveTtsxLauncher([configPath, context.dirname]);
|
|
1925
|
+
// `--no-plugins` keeps this build hermetic: the loader only needs to
|
|
1926
|
+
// type-check and run the user's lint config to extract its plugin
|
|
1927
|
+
// entries. Loading the host project's transform/check plugins
|
|
1928
|
+
// (`@nestia/core`, `typia`, …) would run their project checks
|
|
1929
|
+
// against this deliberately lenient loader tsconfig and fail the
|
|
1930
|
+
// build — e.g. `@nestia/core` rejects the loader's `strict: false`.
|
|
1931
|
+
const args = [
|
|
1932
|
+
"--project",
|
|
1933
|
+
tsconfigPath,
|
|
1934
|
+
"--cwd",
|
|
1935
|
+
tempDir,
|
|
1936
|
+
"--no-plugins",
|
|
1937
|
+
loaderPath,
|
|
1938
|
+
];
|
|
1939
|
+
const tsgoBinary = resolveConfigTsgo(configPath, context);
|
|
1940
|
+
if (tsgoBinary) {
|
|
1941
|
+
args.unshift("--binary", tsgoBinary);
|
|
1942
|
+
}
|
|
1943
|
+
const env = {
|
|
1944
|
+
...nodeConfigLoaderEnv(configPath),
|
|
1945
|
+
};
|
|
1946
|
+
const command = ttsxThroughNodeIfNeeded(ttsxBinary, env, tempDir);
|
|
1947
|
+
const observation = (0, lintTrace_1.beginLintTrace)();
|
|
1948
|
+
const lower = observation ? new Date().toISOString() : undefined;
|
|
1949
|
+
observation?.record("process-attempt", {
|
|
1950
|
+
pid: 0,
|
|
1951
|
+
argv: [command.binary, ...command.prefix, ...args],
|
|
1952
|
+
cwd: tempDir,
|
|
1953
|
+
cwdInherited: false,
|
|
1954
|
+
startLowerBound: lower,
|
|
1955
|
+
owner: "lint-typescript-config-plugin-extractor",
|
|
1956
|
+
});
|
|
1957
|
+
const result = (() => {
|
|
1958
|
+
try {
|
|
1959
|
+
const actual = (0, node_child_process_1.spawnSync)(command.binary, [...command.prefix, ...args], {
|
|
1960
|
+
cwd: tempDir,
|
|
1961
|
+
env,
|
|
1962
|
+
// Both child streams are human output, and they go straight to this
|
|
1963
|
+
// process's stderr as they are written. Nothing is collected here: the
|
|
1964
|
+
// parent's stdout is reserved for compiler JSON and LSP frames, and
|
|
1965
|
+
// buffering the child only to replay it afterwards is what forced an
|
|
1966
|
+
// invented output ceiling and made a long evaluation print nothing at all.
|
|
1967
|
+
stdio: ["ignore", 2, 2],
|
|
1968
|
+
windowsHide: true,
|
|
1969
|
+
});
|
|
1970
|
+
observation?.record("process-result", {
|
|
1971
|
+
pid: actual.pid > 0 ? actual.pid : 0,
|
|
1972
|
+
started: actual.pid > 0,
|
|
1973
|
+
exitObserved: actual.status !== null || actual.signal !== null,
|
|
1974
|
+
status: actual.status,
|
|
1975
|
+
signal: actual.signal,
|
|
1976
|
+
error: actual.error?.message,
|
|
1977
|
+
argv: [command.binary, ...command.prefix, ...args],
|
|
1978
|
+
cwd: tempDir,
|
|
1979
|
+
cwdInherited: false,
|
|
1980
|
+
startLowerBound: lower,
|
|
1981
|
+
startUpperBound: new Date().toISOString(),
|
|
1982
|
+
owner: "lint-typescript-config-plugin-extractor",
|
|
1983
|
+
method: "spawnSync",
|
|
1984
|
+
});
|
|
1985
|
+
return actual;
|
|
1986
|
+
}
|
|
1987
|
+
catch (error) {
|
|
1988
|
+
observation?.record("process-result", {
|
|
1989
|
+
pid: 0,
|
|
1990
|
+
started: false,
|
|
1991
|
+
exitObserved: false,
|
|
1992
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1993
|
+
argv: [command.binary, ...command.prefix, ...args],
|
|
1994
|
+
cwd: tempDir,
|
|
1995
|
+
cwdInherited: false,
|
|
1996
|
+
startLowerBound: lower,
|
|
1997
|
+
startUpperBound: new Date().toISOString(),
|
|
1998
|
+
owner: "lint-typescript-config-plugin-extractor",
|
|
1999
|
+
method: "spawnSync",
|
|
2000
|
+
});
|
|
2001
|
+
throw error;
|
|
2002
|
+
}
|
|
2003
|
+
})();
|
|
2004
|
+
const processFailure = (0, configEvaluatorFailure_1.configEvaluatorProcessFailure)(result, configPath);
|
|
2005
|
+
if (processFailure) {
|
|
2006
|
+
// The evaluator's stack already reached the user's stderr as it ran. What
|
|
2007
|
+
// it could not put there is a reason a caller can act on, so that arrives
|
|
2008
|
+
// through the result file instead.
|
|
2009
|
+
const reason = (0, configEvaluatorFailure_1.configEvaluatorFailureReason)(outputPath);
|
|
2010
|
+
throw reason === ""
|
|
2011
|
+
? processFailure
|
|
2012
|
+
: new Error(`${processFailure.message}\n${reason}`);
|
|
2013
|
+
}
|
|
2014
|
+
let payload;
|
|
2015
|
+
try {
|
|
2016
|
+
payload = JSON.parse(node_fs_1.default.readFileSync(outputPath, "utf8"));
|
|
2017
|
+
}
|
|
2018
|
+
catch (error) {
|
|
2019
|
+
throw new Error(`@ttsc/lint: lint config ${configPath} evaluator returned invalid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
2020
|
+
}
|
|
2021
|
+
if (!Array.isArray(payload.entries)) {
|
|
2022
|
+
throw new Error(`@ttsc/lint: lint config ${configPath} evaluator omitted its plugin-entry array`);
|
|
2023
|
+
}
|
|
2024
|
+
const nestedDependencies = [];
|
|
2025
|
+
const entries = payload.entries.flatMap((entry) => {
|
|
2026
|
+
if (entry !== null &&
|
|
2027
|
+
typeof entry === "object" &&
|
|
2028
|
+
"configFile" in entry) {
|
|
2029
|
+
if (typeof entry.configFile !== "string" ||
|
|
2030
|
+
!node_path_1.default.isAbsolute(entry.configFile) ||
|
|
2031
|
+
!Array.isArray(entry.chain) ||
|
|
2032
|
+
entry.chain.length <= chain.length ||
|
|
2033
|
+
entry.chain.length > 32 ||
|
|
2034
|
+
entry.chain.some((location, index) => typeof location !== "string" ||
|
|
2035
|
+
(index < chain.length && location !== chain[index])) ||
|
|
2036
|
+
entry.chain.at(-1) !== entry.configFile ||
|
|
2037
|
+
new Set(entry.chain).size !== entry.chain.length)
|
|
2038
|
+
throw new Error(`@ttsc/lint: lint config ${configPath} evaluator returned a malformed base-config request`);
|
|
2039
|
+
const base = evaluateTtsxConfigPlugins(entry.configFile, context, entry.chain, evaluated);
|
|
2040
|
+
nestedDependencies.push(...base.dependencies);
|
|
2041
|
+
return base.entries;
|
|
2042
|
+
}
|
|
2043
|
+
// Contributor objects supply absolute source directories. Validate that
|
|
2044
|
+
// boundary without re-routing directories through module resolution.
|
|
2045
|
+
if (entry === null ||
|
|
2046
|
+
typeof entry !== "object" ||
|
|
2047
|
+
typeof entry.namespace !== "string") {
|
|
2048
|
+
throw new Error(`@ttsc/lint: lint config ${configPath} evaluator returned a malformed plugin entry`);
|
|
2049
|
+
}
|
|
2050
|
+
if (!NAMESPACE_PATTERN.test(entry.namespace)) {
|
|
2051
|
+
throw new Error(`@ttsc/lint: lint config ${configPath} namespace ${JSON.stringify(entry.namespace)} must match /^[a-z][a-z0-9_-]*$/`);
|
|
2052
|
+
}
|
|
2053
|
+
if (typeof entry.source !== "string" || entry.source.length === 0) {
|
|
2054
|
+
throw new Error(`@ttsc/lint: lint config ${configPath} plugin ${JSON.stringify(entry.namespace)} did not expose a "source" string`);
|
|
2055
|
+
}
|
|
2056
|
+
if (!node_path_1.default.isAbsolute(entry.source)) {
|
|
2057
|
+
throw new Error(`@ttsc/lint: lint config ${configPath} plugin ${JSON.stringify(entry.namespace)} "source" must be absolute; got ${JSON.stringify(entry.source)}`);
|
|
2058
|
+
}
|
|
2059
|
+
if (!node_fs_1.default.existsSync(entry.source) ||
|
|
2060
|
+
!node_fs_1.default.statSync(entry.source).isDirectory()) {
|
|
2061
|
+
throw new Error(`@ttsc/lint: lint config ${configPath} plugin ${JSON.stringify(entry.namespace)} "source" must be an existing directory: ${entry.source}`);
|
|
2062
|
+
}
|
|
2063
|
+
return [{ namespace: entry.namespace, source: entry.source }];
|
|
2064
|
+
});
|
|
2065
|
+
const dependencies = normalizeConfigDependencyFingerprints(payload.dependencies);
|
|
2066
|
+
if (dependencies === undefined) {
|
|
2067
|
+
throw new Error(`@ttsc/lint: lint config ${configPath} evaluator returned malformed dependency fingerprints`);
|
|
2068
|
+
}
|
|
2069
|
+
const merged = new Map();
|
|
2070
|
+
for (const dependency of [...dependencies, ...nestedDependencies]) {
|
|
2071
|
+
const key = dependency.kind + "\0" + dependency.path;
|
|
2072
|
+
const previous = merged.get(key);
|
|
2073
|
+
if (previous !== undefined &&
|
|
2074
|
+
(previous.digest !== dependency.digest ||
|
|
2075
|
+
previous.realpath !== dependency.realpath)) {
|
|
2076
|
+
throw new Error(`@ttsc/lint: config dependency changed between base evaluations: ${dependency.path}`);
|
|
2077
|
+
}
|
|
2078
|
+
merged.set(key, {
|
|
2079
|
+
...dependency,
|
|
2080
|
+
identityStable: dependency.identityStable && (previous?.identityStable ?? true),
|
|
2081
|
+
scope: dependency.scope === "watch" || previous?.scope === "watch"
|
|
2082
|
+
? "watch"
|
|
2083
|
+
: "cache",
|
|
2084
|
+
});
|
|
2085
|
+
}
|
|
2086
|
+
const evaluation = { dependencies: [...merged.values()], entries };
|
|
2087
|
+
evaluated.set(configPath, evaluation);
|
|
2088
|
+
return evaluation;
|
|
2089
|
+
}
|
|
2090
|
+
finally {
|
|
2091
|
+
removeEvaluationTempDir(tempDir);
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
2095
|
+
// Config cache (shared with the Go sidecar — packages/lint/linthost/config.go)
|
|
2096
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
2097
|
+
/** Create evaluator storage beneath a frozen physical parent. */
|
|
2098
|
+
function createCanonicalTempDirectory(prefix, parent) {
|
|
2099
|
+
const physicalParent = node_fs_1.default.realpathSync.native(parent);
|
|
2100
|
+
if (!node_fs_1.default.lstatSync(physicalParent).isDirectory()) {
|
|
2101
|
+
throw new Error(`@ttsc/lint: temporary directory parent is not a directory: ${physicalParent}`);
|
|
2102
|
+
}
|
|
2103
|
+
const directory = node_fs_1.default.mkdtempSync(node_path_1.default.join(physicalParent, prefix));
|
|
2104
|
+
if (!node_fs_1.default.lstatSync(directory).isDirectory()) {
|
|
2105
|
+
throw new Error(`@ttsc/lint: temporary directory postflight is not a directory: ${directory}`);
|
|
2106
|
+
}
|
|
2107
|
+
const physicalDirectory = node_fs_1.default.realpathSync.native(directory);
|
|
2108
|
+
if (node_path_1.default.dirname(physicalDirectory) !== physicalParent) {
|
|
2109
|
+
throw new Error(`@ttsc/lint: temporary directory escaped its physical parent: ${physicalDirectory}`);
|
|
2110
|
+
}
|
|
2111
|
+
return physicalDirectory;
|
|
2112
|
+
}
|
|
2113
|
+
/**
|
|
2114
|
+
* Namespaces the on-disk config cache. Kept in lockstep with the Go sidecar's
|
|
2115
|
+
* `configCacheVersion`; bump both when the shape or evaluator semantics
|
|
2116
|
+
* change.
|
|
2117
|
+
*/
|
|
2118
|
+
const CONFIG_CACHE_VERSION = "v12";
|
|
2119
|
+
/**
|
|
2120
|
+
* Directory shared by this factory and the Go sidecar for cached lint configs.
|
|
2121
|
+
* The two write different files (the `kind` segment of the cache key keeps
|
|
2122
|
+
* their namespaces apart), so they coexist without collision.
|
|
2123
|
+
*/
|
|
2124
|
+
function configCacheDir() {
|
|
2125
|
+
return node_path_1.default.join(node_os_1.default.tmpdir(), "ttsc-lint-config-cache");
|
|
2126
|
+
}
|
|
2127
|
+
/** Env opt-out, mirroring the Go sidecar's `TTSC_LINT_DISABLE_CONFIG_CACHE`. */
|
|
2128
|
+
function configCacheDisabled() {
|
|
2129
|
+
return Boolean(process.env.TTSC_LINT_DISABLE_CONFIG_CACHE);
|
|
2130
|
+
}
|
|
2131
|
+
/**
|
|
2132
|
+
* Content-addressed cache key for a lint config file. Mirrors the Go sidecar's
|
|
2133
|
+
* `configCacheKey`: a version tag, a namespace `kind`, the config's absolute
|
|
2134
|
+
* path, and its exact bytes. Returns "" — a "do not cache" signal — when the
|
|
2135
|
+
* file cannot be read or the env opt-out is set.
|
|
2136
|
+
*/
|
|
2137
|
+
function configCacheKey(kind, configPath) {
|
|
2138
|
+
if (configCacheDisabled())
|
|
2139
|
+
return "";
|
|
2140
|
+
let content;
|
|
2141
|
+
try {
|
|
2142
|
+
content = node_fs_1.default.readFileSync(configPath);
|
|
2143
|
+
}
|
|
2144
|
+
catch {
|
|
2145
|
+
return "";
|
|
2146
|
+
}
|
|
2147
|
+
return (0, node_crypto_1.createHash)("sha256")
|
|
2148
|
+
.update(CONFIG_CACHE_VERSION)
|
|
2149
|
+
.update("\0")
|
|
2150
|
+
.update(kind)
|
|
2151
|
+
.update("\0")
|
|
2152
|
+
.update(node_path_1.default.resolve(configPath))
|
|
2153
|
+
.update("\0")
|
|
2154
|
+
.update(content)
|
|
2155
|
+
.digest("hex");
|
|
2156
|
+
}
|
|
2157
|
+
/**
|
|
2158
|
+
* Returns the cached plugin-entry list for `cacheKey`, or undefined on any miss
|
|
2159
|
+
* — a missing file, an unreadable file, or a malformed evaluation envelope.
|
|
2160
|
+
* Every failure is a soft miss: the caller re-evaluates.
|
|
2161
|
+
*/
|
|
2162
|
+
function readConfigPluginCache(cacheKey) {
|
|
2163
|
+
let body;
|
|
2164
|
+
try {
|
|
2165
|
+
body = node_fs_1.default.readFileSync(node_path_1.default.join(configCacheDir(), `${cacheKey}.json`), "utf8");
|
|
2166
|
+
}
|
|
2167
|
+
catch {
|
|
2168
|
+
return undefined;
|
|
2169
|
+
}
|
|
2170
|
+
try {
|
|
2171
|
+
const parsed = JSON.parse(body);
|
|
2172
|
+
if (parsed === null ||
|
|
2173
|
+
typeof parsed !== "object" ||
|
|
2174
|
+
!Array.isArray(parsed.entries) ||
|
|
2175
|
+
!Array.isArray(parsed.dependencies)) {
|
|
2176
|
+
return undefined;
|
|
2177
|
+
}
|
|
2178
|
+
const dependencies = normalizeConfigDependencyFingerprints(parsed.dependencies);
|
|
2179
|
+
if (dependencies === undefined)
|
|
2180
|
+
return undefined;
|
|
2181
|
+
return {
|
|
2182
|
+
dependencies,
|
|
2183
|
+
entries: parsed.entries,
|
|
2184
|
+
};
|
|
2185
|
+
}
|
|
2186
|
+
catch {
|
|
2187
|
+
return undefined;
|
|
2188
|
+
}
|
|
2189
|
+
}
|
|
2190
|
+
/**
|
|
2191
|
+
* Writes `entries` to the config cache under `cacheKey`. Best-effort: any
|
|
2192
|
+
* failure leaves the cache cold rather than aborting plugin discovery. The
|
|
2193
|
+
* temp-file + rename keeps a concurrent reader in a sibling `ttsc` process from
|
|
2194
|
+
* observing a half-written file.
|
|
2195
|
+
*/
|
|
2196
|
+
function writeConfigPluginCache(cacheKey, evaluation) {
|
|
2197
|
+
try {
|
|
2198
|
+
const dir = configCacheDir();
|
|
2199
|
+
node_fs_1.default.mkdirSync(dir, { recursive: true });
|
|
2200
|
+
const tmp = node_path_1.default.join(dir, `${cacheKey}.${process.pid}.${(0, node_crypto_1.randomUUID)()}.tmp`);
|
|
2201
|
+
try {
|
|
2202
|
+
node_fs_1.default.writeFileSync(tmp, JSON.stringify(evaluation), "utf8");
|
|
2203
|
+
node_fs_1.default.renameSync(tmp, node_path_1.default.join(dir, `${cacheKey}.json`));
|
|
2204
|
+
}
|
|
2205
|
+
finally {
|
|
2206
|
+
try {
|
|
2207
|
+
node_fs_1.default.unlinkSync(tmp);
|
|
2208
|
+
}
|
|
2209
|
+
catch {
|
|
2210
|
+
// A successful rename already consumed the temporary path.
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
catch {
|
|
2215
|
+
// Cold cache on failure — the next invocation re-evaluates.
|
|
2216
|
+
}
|
|
2217
|
+
}
|
|
2218
|
+
function normalizeConfigDependencyFingerprints(value) {
|
|
2219
|
+
if (!Array.isArray(value) || value.length === 0)
|
|
2220
|
+
return undefined;
|
|
2221
|
+
const dependencies = new Map();
|
|
2222
|
+
for (const candidate of value) {
|
|
2223
|
+
if (candidate === null ||
|
|
2224
|
+
typeof candidate !== "object" ||
|
|
2225
|
+
typeof candidate.path !== "string" ||
|
|
2226
|
+
typeof candidate.digest !== "string" ||
|
|
2227
|
+
typeof candidate.identityStable !==
|
|
2228
|
+
"boolean" ||
|
|
2229
|
+
(candidate.realpath !== null &&
|
|
2230
|
+
(typeof candidate.realpath !==
|
|
2231
|
+
"string" ||
|
|
2232
|
+
!node_path_1.default.isAbsolute(candidate.realpath))) ||
|
|
2233
|
+
!["directory", "file", "optional-file"].includes(candidate.kind) ||
|
|
2234
|
+
!["cache", "watch"].includes(candidate.scope)) {
|
|
2235
|
+
return undefined;
|
|
2236
|
+
}
|
|
2237
|
+
const candidatePath = candidate.path;
|
|
2238
|
+
const digest = candidate.digest;
|
|
2239
|
+
const kind = candidate.kind;
|
|
2240
|
+
const identityStable = candidate
|
|
2241
|
+
.identityStable;
|
|
2242
|
+
const realpath = candidate.realpath;
|
|
2243
|
+
const scope = candidate.scope;
|
|
2244
|
+
if (!node_path_1.default.isAbsolute(candidatePath) ||
|
|
2245
|
+
(digest !== "" && !/^[0-9a-f]{64}$/.test(digest))) {
|
|
2246
|
+
return undefined;
|
|
2247
|
+
}
|
|
2248
|
+
const location = node_path_1.default.resolve(candidatePath);
|
|
2249
|
+
// The same lexical path can be both a traversed directory and an exact
|
|
2250
|
+
// file candidate. Those observations have different freshness contracts:
|
|
2251
|
+
// one fingerprints the listing, while the other fingerprints its entry
|
|
2252
|
+
// type. Preserve both, but still reject contradictory duplicates of one
|
|
2253
|
+
// kind.
|
|
2254
|
+
const key = kind + "\0" + location;
|
|
2255
|
+
const previous = dependencies.get(key);
|
|
2256
|
+
if (previous !== undefined &&
|
|
2257
|
+
(previous.digest !== digest ||
|
|
2258
|
+
previous.identityStable !== identityStable ||
|
|
2259
|
+
previous.kind !== kind ||
|
|
2260
|
+
previous.realpath !== realpath ||
|
|
2261
|
+
previous.scope !== scope)) {
|
|
2262
|
+
return undefined;
|
|
2263
|
+
}
|
|
2264
|
+
dependencies.set(key, {
|
|
2265
|
+
digest,
|
|
2266
|
+
identityStable,
|
|
2267
|
+
kind,
|
|
2268
|
+
path: location,
|
|
2269
|
+
realpath,
|
|
2270
|
+
scope,
|
|
2271
|
+
});
|
|
2272
|
+
}
|
|
2273
|
+
return [...dependencies.values()].sort((left, right) => left.path.localeCompare(right.path));
|
|
2274
|
+
}
|
|
2275
|
+
function configDependenciesAreCurrent(dependencies) {
|
|
2276
|
+
if (dependencies.length === 0)
|
|
2277
|
+
return false;
|
|
2278
|
+
return dependencies.every((dependency) => {
|
|
2279
|
+
if (!dependency.identityStable ||
|
|
2280
|
+
dependency.realpath !== hostInputRealpath(dependency.path)) {
|
|
2281
|
+
return false;
|
|
2282
|
+
}
|
|
2283
|
+
if (!/^[0-9a-f]{64}$/.test(dependency.digest))
|
|
2284
|
+
return false;
|
|
2285
|
+
try {
|
|
2286
|
+
const digest = dependency.kind === "directory"
|
|
2287
|
+
? configDirectoryDigest(dependency.path)
|
|
2288
|
+
: dependency.kind === "optional-file"
|
|
2289
|
+
? configOptionalFileDigest(dependency.path)
|
|
2290
|
+
: (0, node_crypto_1.createHash)("sha256")
|
|
2291
|
+
.update(node_fs_1.default.readFileSync(dependency.path))
|
|
2292
|
+
.digest("hex");
|
|
2293
|
+
return digest === dependency.digest;
|
|
2294
|
+
}
|
|
2295
|
+
catch {
|
|
2296
|
+
return false;
|
|
2297
|
+
}
|
|
2298
|
+
});
|
|
2299
|
+
}
|
|
2300
|
+
function configDirectoryDigest(location) {
|
|
2301
|
+
const entries = [];
|
|
2302
|
+
if (process.platform === "win32") {
|
|
2303
|
+
for (const entry of node_fs_1.default.readdirSync(location, { withFileTypes: true })) {
|
|
2304
|
+
let target = node_buffer_1.Buffer.alloc(0);
|
|
2305
|
+
if (entry.isSymbolicLink()) {
|
|
2306
|
+
try {
|
|
2307
|
+
target = node_buffer_1.Buffer.from(node_fs_1.default.readlinkSync(node_path_1.default.join(location, entry.name)), "utf8");
|
|
2308
|
+
}
|
|
2309
|
+
catch {
|
|
2310
|
+
target = node_buffer_1.Buffer.from("<unreadable>");
|
|
2311
|
+
}
|
|
2312
|
+
}
|
|
2313
|
+
entries.push(configDirectoryDigestRecord(node_buffer_1.Buffer.from(entry.name), entry, target));
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
else {
|
|
2317
|
+
for (const entry of node_fs_1.default.readdirSync(location, {
|
|
2318
|
+
encoding: "buffer",
|
|
2319
|
+
withFileTypes: true,
|
|
2320
|
+
})) {
|
|
2321
|
+
let target = node_buffer_1.Buffer.alloc(0);
|
|
2322
|
+
if (entry.isSymbolicLink()) {
|
|
2323
|
+
try {
|
|
2324
|
+
target = node_fs_1.default.readlinkSync(node_buffer_1.Buffer.concat([
|
|
2325
|
+
node_buffer_1.Buffer.from(location),
|
|
2326
|
+
node_buffer_1.Buffer.from(node_path_1.default.sep),
|
|
2327
|
+
entry.name,
|
|
2328
|
+
]), { encoding: "buffer" });
|
|
2329
|
+
}
|
|
2330
|
+
catch {
|
|
2331
|
+
target = node_buffer_1.Buffer.from("<unreadable>");
|
|
2332
|
+
}
|
|
2333
|
+
}
|
|
2334
|
+
entries.push(configDirectoryDigestRecord(entry.name, entry, target));
|
|
2335
|
+
}
|
|
2336
|
+
}
|
|
2337
|
+
entries.sort(node_buffer_1.Buffer.compare);
|
|
2338
|
+
const serialized = node_buffer_1.Buffer.concat(entries.flatMap((entry, index) => index === 0 ? [entry] : [node_buffer_1.Buffer.from([0]), entry]));
|
|
2339
|
+
return (0, node_crypto_1.createHash)("sha256").update(serialized).digest("hex");
|
|
2340
|
+
}
|
|
2341
|
+
function configDirectoryDigestRecord(name, entry, target) {
|
|
2342
|
+
const kind = entry.isDirectory()
|
|
2343
|
+
? "directory"
|
|
2344
|
+
: entry.isFile()
|
|
2345
|
+
? "file"
|
|
2346
|
+
: entry.isSymbolicLink()
|
|
2347
|
+
? "symlink"
|
|
2348
|
+
: "other";
|
|
2349
|
+
return node_buffer_1.Buffer.concat([name, node_buffer_1.Buffer.from("\0" + kind + "\0"), target]);
|
|
2350
|
+
}
|
|
2351
|
+
function configOptionalFileDigest(location) {
|
|
2352
|
+
try {
|
|
2353
|
+
const entry = node_fs_1.default.statSync(location);
|
|
2354
|
+
if (entry.isFile()) {
|
|
2355
|
+
return (0, node_crypto_1.createHash)("sha256")
|
|
2356
|
+
.update(node_buffer_1.Buffer.concat([node_buffer_1.Buffer.from("file\0"), node_fs_1.default.readFileSync(location)]))
|
|
2357
|
+
.digest("hex");
|
|
2358
|
+
}
|
|
2359
|
+
if (entry.isDirectory()) {
|
|
2360
|
+
return (0, node_crypto_1.createHash)("sha256")
|
|
2361
|
+
.update("ttsc:host-input:directory\0")
|
|
2362
|
+
.digest("hex");
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2365
|
+
catch {
|
|
2366
|
+
// Missing and unreadable candidates share the absent state.
|
|
2367
|
+
}
|
|
2368
|
+
return (0, node_crypto_1.createHash)("sha256").update("missing\0").digest("hex");
|
|
2369
|
+
}
|
|
2370
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
2371
|
+
// Shared helpers
|
|
2372
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
2373
|
+
function findNearestNodeModules(start) {
|
|
2374
|
+
let dir = node_path_1.default.resolve(start);
|
|
2375
|
+
while (true) {
|
|
2376
|
+
const candidate = node_path_1.default.join(dir, "node_modules");
|
|
2377
|
+
if (node_fs_1.default.existsSync(candidate) && node_fs_1.default.statSync(candidate).isDirectory()) {
|
|
2378
|
+
return candidate;
|
|
2379
|
+
}
|
|
2380
|
+
const parent = node_path_1.default.dirname(dir);
|
|
2381
|
+
if (parent === dir)
|
|
2382
|
+
return undefined;
|
|
2383
|
+
dir = parent;
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
/**
|
|
2387
|
+
* The loader tsconfig's `module` for a given config file: the module kind Node
|
|
2388
|
+
* would give the file itself.
|
|
2389
|
+
*
|
|
2390
|
+
* An explicit `.cts`/`.cjs` or `.mts`/`.mjs` extension already decides the emit
|
|
2391
|
+
* format on its own, so those keep the ES-module setting and let the extension
|
|
2392
|
+
* win — the same precedence tsgo applies. Everything ambiguous walks up for the
|
|
2393
|
+
* nearest `package.json` `type`, exactly as Node does when it loads the file.
|
|
2394
|
+
*/
|
|
2395
|
+
function configModuleOption(configPath) {
|
|
2396
|
+
const extension = node_path_1.default.extname(configPath).toLowerCase();
|
|
2397
|
+
if (extension !== ".ts" && extension !== ".tsx" && extension !== ".js") {
|
|
2398
|
+
return "ESNext";
|
|
2399
|
+
}
|
|
2400
|
+
return nearestPackageType(configPath) === "commonjs" ? "CommonJS" : "ESNext";
|
|
2401
|
+
}
|
|
2402
|
+
/**
|
|
2403
|
+
* Nearest `package.json` `"type"` at or above `configPath`, mirroring Node's
|
|
2404
|
+
* package-scope lookup: the walk stops at the **first** manifest it finds, and
|
|
2405
|
+
* a manifest that declares no `"type"` means CommonJS rather than a reason to
|
|
2406
|
+
* keep climbing. Reaching the filesystem root without any manifest also means
|
|
2407
|
+
* CommonJS.
|
|
2408
|
+
*/
|
|
2409
|
+
function nearestPackageType(configPath) {
|
|
2410
|
+
let dir = node_path_1.default.dirname(node_path_1.default.resolve(configPath));
|
|
2411
|
+
for (;;) {
|
|
2412
|
+
// One read rather than a stat-then-read: an unreadable entry and a missing
|
|
2413
|
+
// one are the same answer here — keep walking — and the Go loaders resolve
|
|
2414
|
+
// it the same way, so the four implementations of this rule cannot drift.
|
|
2415
|
+
let raw;
|
|
2416
|
+
try {
|
|
2417
|
+
raw = node_fs_1.default.readFileSync(node_path_1.default.join(dir, "package.json"), "utf8");
|
|
2418
|
+
}
|
|
2419
|
+
catch {
|
|
2420
|
+
raw = undefined;
|
|
2421
|
+
}
|
|
2422
|
+
if (raw !== undefined) {
|
|
2423
|
+
try {
|
|
2424
|
+
const manifest = JSON.parse(raw);
|
|
2425
|
+
const type = typeof manifest === "object" && manifest !== null
|
|
2426
|
+
? manifest.type
|
|
2427
|
+
: undefined;
|
|
2428
|
+
return type === "module" ? "module" : "commonjs";
|
|
2429
|
+
}
|
|
2430
|
+
catch {
|
|
2431
|
+
// A manifest that does not parse still bounds the package scope; Node
|
|
2432
|
+
// refuses to look past it, and CommonJS is the format it defaults to.
|
|
2433
|
+
return "commonjs";
|
|
2434
|
+
}
|
|
2435
|
+
}
|
|
2436
|
+
const parent = node_path_1.default.dirname(dir);
|
|
2437
|
+
if (parent === dir) {
|
|
2438
|
+
return "commonjs";
|
|
2439
|
+
}
|
|
2440
|
+
dir = parent;
|
|
2441
|
+
}
|
|
2442
|
+
}
|
|
2443
|
+
function linkNearestNodeModules(tempDir, sourceDir) {
|
|
2444
|
+
const nodeModules = findNearestNodeModules(sourceDir);
|
|
2445
|
+
if (!nodeModules)
|
|
2446
|
+
return;
|
|
2447
|
+
const link = node_path_1.default.join(tempDir, "node_modules");
|
|
2448
|
+
try {
|
|
2449
|
+
node_fs_1.default.symlinkSync(nodeModules, link, "junction");
|
|
2450
|
+
}
|
|
2451
|
+
catch (error) {
|
|
2452
|
+
const code = error.code;
|
|
2453
|
+
if (code !== "EEXIST") {
|
|
2454
|
+
throw new Error(`@ttsc/lint: failed to link node_modules from ${nodeModules}: ${error instanceof Error ? error.message : String(error)}`);
|
|
2455
|
+
}
|
|
2456
|
+
}
|
|
2457
|
+
}
|
|
2458
|
+
/**
|
|
2459
|
+
* Picks the parent directory for the ephemeral config-loader tree. The system
|
|
2460
|
+
* temp dir is the default, but when it sits on a different volume than the
|
|
2461
|
+
* config file (Windows: TEMP on `C:`, project on `D:`) the loader cannot work
|
|
2462
|
+
* from there — no single tsconfig `rootDir` spans two volumes and
|
|
2463
|
+
* `path.relative` cannot produce a relative import across drives (#305) — so
|
|
2464
|
+
* the tree is created under the config's nearest `node_modules/.cache` instead,
|
|
2465
|
+
* falling back to the config's own directory when no `node_modules` exists (or
|
|
2466
|
+
* its `.cache` cannot be created): any location on the config's volume beats
|
|
2467
|
+
* the system temp dir, which is guaranteed to fail. Keeps the system temp dir
|
|
2468
|
+
* when the volumes already match.
|
|
2469
|
+
*/
|
|
2470
|
+
function loaderTempBase(configPath) {
|
|
2471
|
+
const systemTemp = node_os_1.default.tmpdir();
|
|
2472
|
+
const systemRoot = node_path_1.default.parse(systemTemp).root;
|
|
2473
|
+
const configRoot = node_path_1.default.parse(configPath).root;
|
|
2474
|
+
// A relative config path has no root; "" must not be read as "a volume
|
|
2475
|
+
// other than the system temp's" — it keeps the historical default.
|
|
2476
|
+
if (configRoot === "" ||
|
|
2477
|
+
systemRoot.toLowerCase() === configRoot.toLowerCase()) {
|
|
2478
|
+
return systemTemp;
|
|
2479
|
+
}
|
|
2480
|
+
const nodeModules = findNearestNodeModules(node_path_1.default.dirname(configPath));
|
|
2481
|
+
if (!nodeModules)
|
|
2482
|
+
return node_path_1.default.dirname(configPath);
|
|
2483
|
+
const base = node_path_1.default.join(nodeModules, ".cache");
|
|
2484
|
+
try {
|
|
2485
|
+
node_fs_1.default.mkdirSync(base, { recursive: true });
|
|
2486
|
+
// Resolve symlinks/junctions now (a linked node_modules is common):
|
|
2487
|
+
// Node's ESM loader realpaths the loader module at import time, and a
|
|
2488
|
+
// relative config specifier computed from the link-form path would
|
|
2489
|
+
// resolve against the wrong directory. Realpathing may also land on
|
|
2490
|
+
// another volume, which defeats the whole point — fall through then.
|
|
2491
|
+
const real = node_fs_1.default.realpathSync(base);
|
|
2492
|
+
if (node_path_1.default.parse(real).root.toLowerCase() === configRoot.toLowerCase()) {
|
|
2493
|
+
return real;
|
|
2494
|
+
}
|
|
2495
|
+
}
|
|
2496
|
+
catch {
|
|
2497
|
+
// fall through to the config's own directory
|
|
2498
|
+
}
|
|
2499
|
+
return node_path_1.default.dirname(configPath);
|
|
2500
|
+
}
|
|
2501
|
+
function nodeConfigLoaderEnv(configPath) {
|
|
2502
|
+
const env = { ...process.env };
|
|
2503
|
+
// This child reports the config's actual dependency graph through its own
|
|
2504
|
+
// result envelope. An inherited descriptor channel would also record this
|
|
2505
|
+
// evaluator's disposable bootstrap and its ambient package-scope probes.
|
|
2506
|
+
env.TTSC_PLUGIN_DESCRIPTOR_INPUTS_ACTIVE = "0";
|
|
2507
|
+
const parts = [];
|
|
2508
|
+
const nodeModules = findNearestNodeModules(node_path_1.default.dirname(configPath));
|
|
2509
|
+
if (nodeModules)
|
|
2510
|
+
parts.push(nodeModules);
|
|
2511
|
+
if (env.NODE_PATH)
|
|
2512
|
+
parts.push(env.NODE_PATH);
|
|
2513
|
+
if (parts.length > 0) {
|
|
2514
|
+
env.NODE_PATH = parts.join(node_path_1.default.delimiter);
|
|
2515
|
+
}
|
|
2516
|
+
return env;
|
|
2517
|
+
}
|
|
2518
|
+
/**
|
|
2519
|
+
* The native TypeScript compiler the config evaluator must run.
|
|
2520
|
+
*
|
|
2521
|
+
* The evaluator builds the loader in an ephemeral directory, so the child it
|
|
2522
|
+
* spawns cannot discover `typescript` the way an ordinary invocation does: the
|
|
2523
|
+
* directory is not in the project, and `linkNearestNodeModules` is the only
|
|
2524
|
+
* thing that puts the project's modules within reach of it. Leaving the child
|
|
2525
|
+
* to re-derive the compiler from there made this work by inheritance —
|
|
2526
|
+
* `TTSC_TSGO_BINARY` is exported by `ttsx` to its own descendants, so a build
|
|
2527
|
+
* launched under `ttsx` passed a binary down and a build launched any other way
|
|
2528
|
+
* did not. A published consumer exports no such variable, and neither does a
|
|
2529
|
+
* process that deliberately sheds the launcher's runtime state, and for those
|
|
2530
|
+
* the evaluator failed with `ttsc: typescript is required` before it read a
|
|
2531
|
+
* line of the config.
|
|
2532
|
+
*
|
|
2533
|
+
* The host has already resolved a compiler for the project it is linting, so
|
|
2534
|
+
* the answer is asked of the project rather than of the environment. The config
|
|
2535
|
+
* comes first and the descriptor's own location second, the same order and for
|
|
2536
|
+
* the same reason as {@link resolveTtsxLauncher}. An explicit `TTSC_TSGO_BINARY`
|
|
2537
|
+
* still wins, so an embedder that pins a compiler keeps pinning it.
|
|
2538
|
+
*
|
|
2539
|
+
* Returning `undefined` leaves the child to resolve for itself, which is what
|
|
2540
|
+
* it did before: a project that cannot answer here could not answer there
|
|
2541
|
+
* either, and the child's own diagnostic is the one that names the missing
|
|
2542
|
+
* package.
|
|
2543
|
+
*/
|
|
2544
|
+
function resolveConfigTsgo(configPath, context) {
|
|
2545
|
+
const explicit = process.env.TTSC_TSGO_BINARY?.trim();
|
|
2546
|
+
if (explicit)
|
|
2547
|
+
return explicit;
|
|
2548
|
+
const anchors = [
|
|
2549
|
+
configPath,
|
|
2550
|
+
node_path_1.default.join(context.projectRoot, "package.json"),
|
|
2551
|
+
context.dirname,
|
|
2552
|
+
];
|
|
2553
|
+
for (const anchor of anchors) {
|
|
2554
|
+
const binary = tsgoBinaryFrom(anchor);
|
|
2555
|
+
if (binary !== undefined)
|
|
2556
|
+
return binary;
|
|
2557
|
+
}
|
|
2558
|
+
return undefined;
|
|
2559
|
+
}
|
|
2560
|
+
/**
|
|
2561
|
+
* The platform compiler binary of the `typescript` install `anchor` can see, or
|
|
2562
|
+
* `undefined` when this anchor reaches neither the package nor its platform
|
|
2563
|
+
* dependency. Mirrors ttsc's own resolution order so both name one file.
|
|
2564
|
+
*/
|
|
2565
|
+
function tsgoBinaryFrom(anchor) {
|
|
2566
|
+
try {
|
|
2567
|
+
const manifest = (0, node_module_1.createRequire)(anchor).resolve("typescript/package.json");
|
|
2568
|
+
const platform = (0, node_module_1.createRequire)(manifest).resolve(`@typescript/typescript-${process.platform}-${process.arch}/package.json`);
|
|
2569
|
+
const binary = node_path_1.default.join(node_path_1.default.dirname(platform), "lib", process.platform === "win32" ? "tsc.exe" : "tsc");
|
|
2570
|
+
return node_fs_1.default.existsSync(binary) ? binary : undefined;
|
|
2571
|
+
}
|
|
2572
|
+
catch {
|
|
2573
|
+
// This anchor cannot see the compiler; the caller tries the next one.
|
|
2574
|
+
return undefined;
|
|
2575
|
+
}
|
|
2576
|
+
}
|
|
2577
|
+
/**
|
|
2578
|
+
* Resolves the isolated config evaluator launcher from the supplied anchors.
|
|
2579
|
+
*
|
|
2580
|
+
* An explicit override wins. Otherwise package-manifest resolution locates a
|
|
2581
|
+
* ttsc installation the anchors can see. The bare `ttsx` command is the final
|
|
2582
|
+
* fallback and requires a launcher available on PATH.
|
|
2583
|
+
*/
|
|
2584
|
+
function resolveTtsxLauncher(anchors) {
|
|
2585
|
+
const explicit = process.env.TTSC_TTSX_BINARY?.trim();
|
|
2586
|
+
if (explicit)
|
|
2587
|
+
return explicit;
|
|
2588
|
+
for (const anchor of anchors) {
|
|
2589
|
+
const launcher = ttsxLauncherFrom(anchor);
|
|
2590
|
+
if (launcher !== undefined)
|
|
2591
|
+
return launcher;
|
|
2592
|
+
}
|
|
2593
|
+
return "ttsx";
|
|
2594
|
+
}
|
|
2595
|
+
function ttsxLauncherFrom(anchor) {
|
|
2596
|
+
try {
|
|
2597
|
+
// Only the manifest is exported, so the launcher is derived from where the
|
|
2598
|
+
// manifest resolved rather than requested as a subpath. Resolution is
|
|
2599
|
+
// anchored on the config being evaluated, which is how every other
|
|
2600
|
+
// resolution in this descriptor is anchored and picks the ttsc the project
|
|
2601
|
+
// actually installed.
|
|
2602
|
+
const manifest = (0, node_module_1.createRequire)(anchor).resolve("ttsc/package.json");
|
|
2603
|
+
const launcher = node_path_1.default.join(node_path_1.default.dirname(manifest), "lib", "launcher", "ttsx.js");
|
|
2604
|
+
if (node_fs_1.default.existsSync(launcher))
|
|
2605
|
+
return launcher;
|
|
2606
|
+
}
|
|
2607
|
+
catch {
|
|
2608
|
+
// This anchor cannot see ttsc; the caller tries the next one.
|
|
2609
|
+
}
|
|
2610
|
+
return undefined;
|
|
2611
|
+
}
|
|
2612
|
+
/**
|
|
2613
|
+
* Select the Node interpreter required by the isolated checked evaluator.
|
|
2614
|
+
*
|
|
2615
|
+
* A descriptor can run under Bun, while a JavaScript ttsx launcher requires
|
|
2616
|
+
* Node's synchronous module hooks. Probe candidates in the evaluator's actual
|
|
2617
|
+
* environment and directory; a host executable or a command name alone does not
|
|
2618
|
+
* prove that capability. Native launcher overrides retain their own entry.
|
|
2619
|
+
* Candidate observations are invocation-local, without stale runtime caching.
|
|
2620
|
+
*/
|
|
2621
|
+
function ttsxThroughNodeIfNeeded(binary, env, cwd) {
|
|
2622
|
+
const ext = node_path_1.default.extname(binary).toLowerCase();
|
|
2623
|
+
if (![".js", ".cjs", ".mjs", ".ts", ".cts", ".mts"].includes(ext)) {
|
|
2624
|
+
return { binary, prefix: [] };
|
|
2625
|
+
}
|
|
2626
|
+
const explicit = process.platform === "win32"
|
|
2627
|
+
? Object.entries(env).find(([key]) => key.toUpperCase() === "TTSC_NODE_BINARY")?.[1]
|
|
2628
|
+
: env.TTSC_NODE_BINARY;
|
|
2629
|
+
const seen = new Set();
|
|
2630
|
+
const args = [
|
|
2631
|
+
"-e",
|
|
2632
|
+
'process.stdout.write(JSON.stringify({bun:typeof globalThis.Bun === "object",registerHooks:typeof require("node:module").registerHooks === "function",executable:process.execPath}))',
|
|
2633
|
+
];
|
|
2634
|
+
for (const candidate of [explicit, process.execPath, "node"]) {
|
|
2635
|
+
if (!candidate?.trim() || seen.has(candidate))
|
|
2636
|
+
continue;
|
|
2637
|
+
seen.add(candidate);
|
|
2638
|
+
const observation = (0, lintTrace_1.beginLintTrace)();
|
|
2639
|
+
const lower = observation ? new Date().toISOString() : undefined;
|
|
2640
|
+
observation?.record("process-attempt", {
|
|
2641
|
+
pid: 0,
|
|
2642
|
+
argv: [candidate, ...args],
|
|
2643
|
+
cwd,
|
|
2644
|
+
cwdInherited: false,
|
|
2645
|
+
startLowerBound: lower,
|
|
2646
|
+
owner: "lint-config-node-runtime-probe",
|
|
2647
|
+
});
|
|
2648
|
+
const result = (0, node_child_process_1.spawnSync)(candidate, args, {
|
|
2649
|
+
cwd,
|
|
2650
|
+
env,
|
|
2651
|
+
encoding: "utf8",
|
|
2652
|
+
timeout: 30_000,
|
|
2653
|
+
maxBuffer: 64 * 1024,
|
|
2654
|
+
windowsHide: true,
|
|
2655
|
+
});
|
|
2656
|
+
observation?.record("process-result", {
|
|
2657
|
+
pid: result.pid > 0 ? result.pid : 0,
|
|
2658
|
+
started: result.pid > 0,
|
|
2659
|
+
exitObserved: result.status !== null || result.signal !== null,
|
|
2660
|
+
status: result.status,
|
|
2661
|
+
signal: result.signal,
|
|
2662
|
+
error: result.error?.message,
|
|
2663
|
+
argv: [candidate, ...args],
|
|
2664
|
+
cwd,
|
|
2665
|
+
cwdInherited: false,
|
|
2666
|
+
startLowerBound: lower,
|
|
2667
|
+
startUpperBound: new Date().toISOString(),
|
|
2668
|
+
owner: "lint-config-node-runtime-probe",
|
|
2669
|
+
method: "spawnSync",
|
|
2670
|
+
});
|
|
2671
|
+
if (result.status !== 0)
|
|
2672
|
+
continue;
|
|
2673
|
+
try {
|
|
2674
|
+
const actual = JSON.parse(result.stdout);
|
|
2675
|
+
if (actual.bun === false &&
|
|
2676
|
+
actual.registerHooks === true &&
|
|
2677
|
+
typeof actual.executable === "string" &&
|
|
2678
|
+
node_path_1.default.isAbsolute(actual.executable)) {
|
|
2679
|
+
return { binary: actual.executable, prefix: [binary] };
|
|
2680
|
+
}
|
|
2681
|
+
}
|
|
2682
|
+
catch {
|
|
2683
|
+
// An incompatible candidate did not report the required Node capability.
|
|
2684
|
+
}
|
|
2685
|
+
}
|
|
2686
|
+
throw new Error("@ttsc/lint: isolated config evaluation requires Node.js with module.registerHooks; no compatible interpreter was found");
|
|
2687
|
+
}
|
|
2688
|
+
/**
|
|
2689
|
+
* Remove an evaluation temp directory without letting cleanup replace a result.
|
|
2690
|
+
*
|
|
2691
|
+
* This runs from a `finally`, so a throw here would surface instead of the
|
|
2692
|
+
* evaluation's own outcome — and on Windows a grandchild that inherited a
|
|
2693
|
+
* handle, or a scanner holding the file, can make removal fail. Leaving bytes
|
|
2694
|
+
* in the system temp directory is by far the lesser outcome.
|
|
2695
|
+
*/
|
|
2696
|
+
function removeEvaluationTempDir(directory) {
|
|
2697
|
+
try {
|
|
2698
|
+
node_fs_1.default.rmSync(directory, { force: true, recursive: true });
|
|
2699
|
+
}
|
|
2700
|
+
catch {
|
|
2701
|
+
// Best effort.
|
|
2702
|
+
}
|
|
2703
|
+
}
|
|
2704
|
+
//# sourceMappingURL=createTtscPlugin.js.map
|