@ttsc/lint 0.13.0 → 0.14.0-dev.20260528
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 +948 -69
- package/lib/defaultFormat.d.ts +9 -6
- package/lib/defaultFormat.js +9 -6
- package/lib/defaultFormat.js.map +1 -1
- package/lib/index.d.ts +46 -0
- package/lib/index.js +60 -37
- package/lib/index.js.map +1 -1
- package/lib/structures/ITtscLintConfig.d.ts +12 -6
- package/lib/structures/{ITtscLintFormatConfig.d.ts → ITtscLintFormat.d.ts} +2 -2
- package/lib/structures/{TtscLintRuleMap.js → ITtscLintFormat.js} +1 -1
- package/lib/structures/ITtscLintFormat.js.map +1 -0
- package/lib/structures/TtscLintRuleSetting.d.ts +49 -0
- package/lib/structures/{TtscLintRuleOptions.js → TtscLintRuleSetting.js} +1 -1
- package/lib/structures/TtscLintRuleSetting.js.map +1 -0
- package/lib/structures/index.d.ts +3 -4
- package/lib/structures/index.js +3 -4
- package/lib/structures/index.js.map +1 -1
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.d.ts +104 -0
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js +14 -0
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintBoundariesRules.d.ts +79 -0
- package/lib/structures/rules/ITtscLintBoundariesRules.js +3 -0
- package/lib/structures/rules/ITtscLintBoundariesRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintContributorRules.d.ts +17 -0
- package/lib/structures/rules/ITtscLintContributorRules.js +3 -0
- package/lib/structures/rules/ITtscLintContributorRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintCoreRules.d.ts +1257 -0
- package/lib/structures/{ITtscLintFormatConfig.js → rules/ITtscLintCoreRules.js} +1 -1
- package/lib/structures/rules/ITtscLintCoreRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintCypressRuleOptions.d.ts +17 -0
- package/lib/structures/rules/ITtscLintCypressRuleOptions.js +10 -0
- package/lib/structures/rules/ITtscLintCypressRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintCypressRules.d.ts +129 -0
- package/lib/structures/rules/ITtscLintCypressRules.js +3 -0
- package/lib/structures/rules/ITtscLintCypressRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintFunctionalRuleOptions.d.ts +157 -0
- package/lib/structures/rules/ITtscLintFunctionalRuleOptions.js +13 -0
- package/lib/structures/rules/ITtscLintFunctionalRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintFunctionalRules.d.ts +167 -0
- package/lib/structures/rules/ITtscLintFunctionalRules.js +3 -0
- package/lib/structures/rules/ITtscLintFunctionalRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintJestRules.d.ts +201 -0
- package/lib/structures/rules/ITtscLintJestRules.js +3 -0
- package/lib/structures/rules/ITtscLintJestRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintJsdocRules.d.ts +140 -0
- package/lib/structures/rules/ITtscLintJsdocRules.js +3 -0
- package/lib/structures/rules/ITtscLintJsdocRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintJsxA11yRules.d.ts +302 -0
- package/lib/structures/rules/ITtscLintJsxA11yRules.js +3 -0
- package/lib/structures/rules/ITtscLintJsxA11yRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintNextjsRules.d.ts +185 -0
- package/lib/structures/rules/ITtscLintNextjsRules.js +3 -0
- package/lib/structures/rules/ITtscLintNextjsRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintPlaywrightRules.d.ts +330 -0
- package/lib/structures/rules/ITtscLintPlaywrightRules.js +3 -0
- package/lib/structures/rules/ITtscLintPlaywrightRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintPromiseRules.d.ts +188 -0
- package/lib/structures/rules/ITtscLintPromiseRules.js +3 -0
- package/lib/structures/rules/ITtscLintPromiseRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintReactPerfRuleOptions.d.ts +18 -0
- package/lib/structures/rules/ITtscLintReactPerfRuleOptions.js +8 -0
- package/lib/structures/rules/ITtscLintReactPerfRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintReactPerfRules.d.ts +51 -0
- package/lib/structures/rules/ITtscLintReactPerfRules.js +3 -0
- package/lib/structures/rules/ITtscLintReactPerfRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintReactRuleOptions.d.ts +39 -0
- package/lib/structures/rules/ITtscLintReactRuleOptions.js +12 -0
- package/lib/structures/rules/ITtscLintReactRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintReactRules.d.ts +289 -0
- package/lib/structures/rules/ITtscLintReactRules.js +3 -0
- package/lib/structures/rules/ITtscLintReactRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintRegexpRules.d.ts +190 -0
- package/lib/structures/rules/ITtscLintRegexpRules.js +3 -0
- package/lib/structures/rules/ITtscLintRegexpRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintRuleOptionsMap.d.ts +66 -0
- package/lib/structures/rules/ITtscLintRuleOptionsMap.js +3 -0
- package/lib/structures/rules/ITtscLintRuleOptionsMap.js.map +1 -0
- package/lib/structures/rules/ITtscLintRules.d.ts +55 -0
- package/lib/structures/{TtscLintRule.js → rules/ITtscLintRules.js} +1 -1
- package/lib/structures/rules/ITtscLintRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintSecurityRules.d.ts +148 -0
- package/lib/structures/rules/ITtscLintSecurityRules.js +3 -0
- package/lib/structures/rules/ITtscLintSecurityRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintSolidRules.d.ts +181 -0
- package/lib/structures/rules/ITtscLintSolidRules.js +3 -0
- package/lib/structures/rules/ITtscLintSolidRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintStorybookRuleOptions.d.ts +21 -0
- package/lib/structures/rules/ITtscLintStorybookRuleOptions.js +9 -0
- package/lib/structures/rules/ITtscLintStorybookRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintStorybookRules.d.ts +174 -0
- package/lib/structures/rules/ITtscLintStorybookRules.js +3 -0
- package/lib/structures/rules/ITtscLintStorybookRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintTanstackQueryRules.d.ts +94 -0
- package/lib/structures/rules/ITtscLintTanstackQueryRules.js +3 -0
- package/lib/structures/rules/ITtscLintTanstackQueryRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.d.ts +22 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.js +10 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRules.d.ts +310 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRules.js +3 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintTypeScriptRules.d.ts +1132 -0
- package/lib/structures/rules/ITtscLintTypeScriptRules.js +3 -0
- package/lib/structures/rules/ITtscLintTypeScriptRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintUnicornRules.d.ts +997 -0
- package/lib/structures/rules/ITtscLintUnicornRules.js +3 -0
- package/lib/structures/rules/ITtscLintUnicornRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintVitestRules.d.ts +141 -0
- package/lib/structures/rules/ITtscLintVitestRules.js +3 -0
- package/lib/structures/rules/ITtscLintVitestRules.js.map +1 -0
- package/lib/structures/rules/index.d.ts +31 -0
- package/lib/structures/rules/index.js +48 -0
- package/lib/structures/rules/index.js.map +1 -0
- package/linthost/ast_helpers.go +30 -5
- package/linthost/compile.go +33 -2
- package/linthost/config.go +48 -17
- package/linthost/config_format.go +9 -9
- package/linthost/directives.go +67 -25
- package/linthost/dispatch.go +14 -3
- package/linthost/engine.go +160 -40
- package/linthost/fix.go +2 -2
- package/linthost/flags_gen.go +17 -15
- package/linthost/host.go +40 -3
- package/linthost/lsp.go +747 -0
- package/linthost/print_dispatch.go +2 -2
- package/linthost/print_nodes_function.go +2 -2
- package/linthost/print_nodes_object.go +1 -1
- package/linthost/rule_names.go +14 -0
- package/linthost/rules_arrays.go +2 -2
- package/linthost/rules_boundaries.go +532 -0
- package/linthost/rules_camelcase.go +133 -0
- package/linthost/rules_complexity.go +94 -0
- package/linthost/rules_consistent_return.go +130 -0
- package/linthost/rules_console.go +1 -1
- package/linthost/rules_core_extra.go +739 -0
- package/linthost/rules_curly.go +70 -0
- package/linthost/rules_cypress.go +608 -0
- package/linthost/rules_debugger.go +2 -2
- package/linthost/rules_default_case.go +39 -0
- package/linthost/rules_default_case_last.go +46 -0
- package/linthost/rules_dupes.go +3 -3
- package/linthost/rules_empty.go +3 -3
- package/linthost/rules_escape.go +44 -24
- package/linthost/rules_eval.go +2 -2
- package/linthost/rules_finally.go +2 -2
- package/linthost/rules_format_jsdoc.go +1 -1
- package/linthost/rules_format_print_width.go +9 -9
- package/linthost/rules_format_quotes.go +1 -1
- package/linthost/rules_format_semi.go +1 -1
- package/linthost/rules_format_sort_imports.go +1 -1
- package/linthost/rules_format_trailing_comma.go +1 -1
- package/linthost/rules_functional.go +967 -0
- package/linthost/rules_gap.go +24 -45
- package/linthost/rules_grouped_accessor_pairs.go +87 -0
- package/linthost/rules_guard_for_in.go +198 -0
- package/linthost/rules_id_length.go +77 -0
- package/linthost/rules_imports.go +70 -2
- package/linthost/rules_init_declarations.go +53 -0
- package/linthost/rules_jest.go +618 -0
- package/linthost/rules_jsdoc.go +502 -0
- package/linthost/rules_jsx_a11y.go +1264 -0
- package/linthost/rules_logic.go +12 -12
- package/linthost/rules_loops.go +1 -1
- package/linthost/rules_max_classes_per_file.go +58 -0
- package/linthost/rules_max_depth.go +83 -0
- package/linthost/rules_max_lines.go +101 -0
- package/linthost/rules_max_lines_per_function.go +57 -0
- package/linthost/rules_max_nested_callbacks.go +61 -0
- package/linthost/rules_max_params.go +49 -0
- package/linthost/rules_max_statements.go +59 -0
- package/linthost/rules_misc.go +1 -1
- package/linthost/rules_nextjs.go +697 -0
- package/linthost/rules_no_else_return.go +75 -0
- package/linthost/rules_no_empty_named_blocks.go +91 -0
- package/linthost/rules_no_extend_native.go +51 -0
- package/linthost/rules_no_import_assign.go +140 -0
- package/linthost/rules_no_invalid_this.go +52 -0
- package/linthost/rules_no_loop_func.go +85 -0
- package/linthost/rules_no_magic_numbers.go +123 -0
- package/linthost/rules_no_mixed_operators.go +80 -0
- package/linthost/rules_no_param_reassign.go +98 -0
- package/linthost/rules_no_redeclare.go +270 -0
- package/linthost/rules_no_restricted_imports.go +105 -0
- package/linthost/rules_no_restricted_syntax.go +49 -0
- package/linthost/rules_no_shadow.go +147 -0
- package/linthost/rules_no_unreachable.go +77 -0
- package/linthost/rules_no_useless_assignment.go +120 -0
- package/linthost/rules_no_useless_constructor.go +245 -0
- package/linthost/rules_no_useless_return.go +51 -0
- package/linthost/rules_params.go +1 -1
- package/linthost/rules_playwright.go +788 -0
- package/linthost/rules_prefer_arrow_callback.go +124 -0
- package/linthost/rules_prefer_destructuring.go +98 -0
- package/linthost/rules_prefer_named_capture_group.go +129 -0
- package/linthost/rules_prefer_rest_params.go +94 -0
- package/linthost/rules_problems.go +41 -30
- package/linthost/rules_promise.go +1128 -73
- package/linthost/rules_protos.go +2 -2
- package/linthost/rules_react.go +773 -0
- package/linthost/rules_react_extras.go +227 -0
- package/linthost/rules_react_hooks.go +848 -0
- package/linthost/rules_react_perf.go +293 -0
- package/linthost/rules_react_refresh.go +583 -0
- package/linthost/rules_regexp.go +410 -0
- package/linthost/rules_security.go +830 -0
- package/linthost/rules_self.go +2 -2
- package/linthost/rules_solid.go +1073 -0
- package/linthost/rules_sort_imports.go +69 -0
- package/linthost/rules_sort_keys.go +134 -0
- package/linthost/rules_storybook.go +1176 -0
- package/linthost/rules_strings.go +4 -4
- package/linthost/rules_suggestions.go +38 -38
- package/linthost/rules_tanstack_query.go +844 -0
- package/linthost/rules_testing_library.go +1204 -0
- package/linthost/rules_throw.go +1 -1
- package/linthost/rules_ts.go +19 -19
- package/linthost/rules_ts_async.go +399 -0
- package/linthost/rules_ts_class_literal_property_style.go +115 -0
- package/linthost/rules_ts_consistent_type_exports.go +256 -0
- package/linthost/rules_ts_explicit_function_return_type.go +67 -0
- package/linthost/rules_ts_extra.go +155 -36
- package/linthost/rules_ts_no_base_to_string.go +218 -0
- package/linthost/rules_ts_no_confusing_void.go +72 -0
- package/linthost/rules_ts_no_deprecated.go +195 -0
- package/linthost/rules_ts_no_for_in_array.go +84 -0
- package/linthost/rules_ts_no_magic_numbers.go +124 -0
- package/linthost/rules_ts_no_meaningless_void_operator.go +84 -0
- package/linthost/rules_ts_no_misused_spread.go +104 -0
- package/linthost/rules_ts_no_redundant_type_constituents.go +113 -0
- package/linthost/rules_ts_no_restricted_types.go +62 -0
- package/linthost/rules_ts_no_unnecessary_boolean_literal_compare.go +129 -0
- package/linthost/rules_ts_no_unnecessary_condition.go +250 -0
- package/linthost/rules_ts_no_unnecessary_qualifier.go +118 -0
- package/linthost/rules_ts_no_unnecessary_template_expression.go +178 -0
- package/linthost/rules_ts_no_unnecessary_type_arguments.go +234 -0
- package/linthost/rules_ts_no_unnecessary_type_assertion.go +157 -0
- package/linthost/rules_ts_no_unsafe_argument.go +82 -0
- package/linthost/rules_ts_no_unsafe_assignment.go +102 -0
- package/linthost/rules_ts_no_unsafe_call.go +82 -0
- package/linthost/rules_ts_no_unsafe_enum_comparison.go +235 -0
- package/linthost/rules_ts_no_unsafe_member_access.go +58 -0
- package/linthost/rules_ts_no_unsafe_return.go +126 -0
- package/linthost/rules_ts_no_unsafe_unary_minus.go +81 -0
- package/linthost/rules_ts_no_useless_constructor.go +52 -0
- package/linthost/rules_ts_non_nullable_type_assertion_style.go +108 -0
- package/linthost/rules_ts_parameter_properties.go +38 -0
- package/linthost/rules_ts_prefer_find.go +178 -0
- package/linthost/rules_ts_prefer_includes.go +255 -0
- package/linthost/rules_ts_prefer_nullish_coalescing.go +104 -0
- package/linthost/rules_ts_prefer_optional_chain.go +228 -0
- package/linthost/rules_ts_prefer_promise_reject_errors.go +176 -0
- package/linthost/rules_ts_prefer_readonly.go +73 -0
- package/linthost/rules_ts_prefer_reduce_type_parameter.go +116 -0
- package/linthost/rules_ts_prefer_regexp_exec.go +122 -0
- package/linthost/rules_ts_prefer_return_this_type.go +135 -0
- package/linthost/rules_ts_prefer_string_starts_ends_with.go +360 -0
- package/linthost/rules_ts_promise_function_async.go +77 -0
- package/linthost/rules_ts_related_getter_setter_pairs.go +113 -0
- package/linthost/rules_ts_require_array_sort_compare.go +96 -0
- package/linthost/rules_ts_restrict_plus_operands.go +127 -0
- package/linthost/rules_ts_restrict_template_expressions.go +95 -0
- package/linthost/rules_ts_simple.go +387 -0
- package/linthost/rules_ts_sort_type_constituents.go +144 -0
- package/linthost/rules_ts_strict_boolean_expressions.go +157 -0
- package/linthost/rules_ts_switch_exhaustiveness_check.go +147 -0
- package/linthost/rules_ts_unbound_method.go +126 -0
- package/linthost/rules_tsdoc.go +136 -0
- package/linthost/rules_unicorn_better_regex.go +27 -0
- package/linthost/rules_unicorn_catch_error_name.go +46 -0
- package/linthost/rules_unicorn_consistent_assert.go +47 -0
- package/linthost/rules_unicorn_consistent_date_clone.go +54 -0
- package/linthost/rules_unicorn_consistent_destructuring.go +25 -0
- package/linthost/rules_unicorn_consistent_empty_array_spread.go +62 -0
- package/linthost/rules_unicorn_consistent_existence_index_check.go +80 -0
- package/linthost/rules_unicorn_consistent_function_scoping.go +25 -0
- package/linthost/rules_unicorn_consistent_template_literal_escape.go +25 -0
- package/linthost/rules_unicorn_custom_error_definition.go +138 -0
- package/linthost/rules_unicorn_empty_brace_spaces.go +73 -0
- package/linthost/rules_unicorn_error_message.go +64 -0
- package/linthost/rules_unicorn_escape_case.go +51 -0
- package/linthost/rules_unicorn_expiring_todo_comments.go +78 -0
- package/linthost/rules_unicorn_explicit_length_check.go +88 -0
- package/linthost/rules_unicorn_filename_case.go +29 -0
- package/linthost/rules_unicorn_import_style.go +28 -0
- package/linthost/rules_unicorn_isolated_functions.go +29 -0
- package/linthost/rules_unicorn_new_for_builtins.go +87 -0
- package/linthost/rules_unicorn_no_abusive_eslint_disable.go +63 -0
- package/linthost/rules_unicorn_no_accessor_recursion.go +115 -0
- package/linthost/rules_unicorn_no_anonymous_default_export.go +74 -0
- package/linthost/rules_unicorn_no_array_callback_reference.go +65 -0
- package/linthost/rules_unicorn_no_array_for_each.go +40 -0
- package/linthost/rules_unicorn_no_array_method_this_argument.go +61 -0
- package/linthost/rules_unicorn_no_array_reduce.go +41 -0
- package/linthost/rules_unicorn_no_array_reverse.go +44 -0
- package/linthost/rules_unicorn_no_array_sort.go +43 -0
- package/linthost/rules_unicorn_no_await_expression_member.go +40 -0
- package/linthost/rules_unicorn_no_await_in_promise_methods.go +69 -0
- package/linthost/rules_unicorn_no_console_spaces.go +61 -0
- package/linthost/rules_unicorn_no_document_cookie.go +41 -0
- package/linthost/rules_unicorn_no_empty_file.go +44 -0
- package/linthost/rules_unicorn_no_for_loop.go +102 -0
- package/linthost/rules_unicorn_no_hex_escape.go +42 -0
- package/linthost/rules_unicorn_no_immediate_mutation.go +90 -0
- package/linthost/rules_unicorn_no_instanceof_builtins.go +66 -0
- package/linthost/rules_unicorn_no_invalid_fetch_options.go +79 -0
- package/linthost/rules_unicorn_no_invalid_remove_event_listener.go +51 -0
- package/linthost/rules_unicorn_no_keyword_prefix.go +101 -0
- package/linthost/rules_unicorn_no_lonely_if.go +44 -0
- package/linthost/rules_unicorn_no_magic_array_flat_depth.go +51 -0
- package/linthost/rules_unicorn_no_named_default.go +54 -0
- package/linthost/rules_unicorn_no_negated_condition.go +85 -0
- package/linthost/rules_unicorn_no_negation_in_equality_check.go +50 -0
- package/linthost/rules_unicorn_no_nested_ternary.go +43 -0
- package/linthost/rules_unicorn_no_new_array.go +30 -0
- package/linthost/rules_unicorn_no_new_buffer.go +31 -0
- package/linthost/rules_unicorn_no_null.go +24 -0
- package/linthost/rules_unicorn_no_object_as_default_parameter.go +48 -0
- package/linthost/rules_unicorn_no_process_exit.go +43 -0
- package/linthost/rules_unicorn_no_single_promise_in_promise_methods.go +59 -0
- package/linthost/rules_unicorn_no_static_only_class.go +56 -0
- package/linthost/rules_unicorn_no_thenable.go +74 -0
- package/linthost/rules_unicorn_no_this_assignment.go +35 -0
- package/linthost/rules_unicorn_no_typeof_undefined.go +58 -0
- package/linthost/rules_unicorn_no_unnecessary_array_flat_depth.go +49 -0
- package/linthost/rules_unicorn_no_unnecessary_array_splice_count.go +70 -0
- package/linthost/rules_unicorn_no_unnecessary_await.go +51 -0
- package/linthost/rules_unicorn_no_unnecessary_polyfills.go +32 -0
- package/linthost/rules_unicorn_no_unnecessary_slice_end.go +48 -0
- package/linthost/rules_unicorn_no_unreadable_array_destructuring.go +115 -0
- package/linthost/rules_unicorn_no_unreadable_iife.go +50 -0
- package/linthost/rules_unicorn_no_unused_properties.go +30 -0
- package/linthost/rules_unicorn_no_useless_collection_argument.go +63 -0
- package/linthost/rules_unicorn_no_useless_error_capture_stack_trace.go +46 -0
- package/linthost/rules_unicorn_no_useless_fallback_in_spread.go +81 -0
- package/linthost/rules_unicorn_no_useless_iterator_to_array.go +72 -0
- package/linthost/rules_unicorn_no_useless_length_check.go +144 -0
- package/linthost/rules_unicorn_no_useless_promise_resolve_reject.go +81 -0
- package/linthost/rules_unicorn_no_useless_spread.go +67 -0
- package/linthost/rules_unicorn_no_useless_switch_case.go +55 -0
- package/linthost/rules_unicorn_no_useless_undefined.go +55 -0
- package/linthost/rules_unicorn_no_zero_fractions.go +52 -0
- package/linthost/rules_unicorn_number_literal_case.go +69 -0
- package/linthost/rules_unicorn_numeric_separators_style.go +75 -0
- package/linthost/rules_unicorn_prefer_add_event_listener.go +66 -0
- package/linthost/rules_unicorn_prefer_array_find.go +51 -0
- package/linthost/rules_unicorn_prefer_array_flat.go +52 -0
- package/linthost/rules_unicorn_prefer_array_flat_map.go +63 -0
- package/linthost/rules_unicorn_prefer_array_index_of.go +147 -0
- package/linthost/rules_unicorn_prefer_array_some.go +67 -0
- package/linthost/rules_unicorn_prefer_at.go +77 -0
- package/linthost/rules_unicorn_prefer_bigint_literals.go +77 -0
- package/linthost/rules_unicorn_prefer_blob_reading_methods.go +44 -0
- package/linthost/rules_unicorn_prefer_class_fields.go +93 -0
- package/linthost/rules_unicorn_prefer_classlist_toggle.go +120 -0
- package/linthost/rules_unicorn_prefer_code_point.go +49 -0
- package/linthost/rules_unicorn_prefer_date_now.go +78 -0
- package/linthost/rules_unicorn_prefer_default_parameters.go +144 -0
- package/linthost/rules_unicorn_prefer_dom_node_append.go +40 -0
- package/linthost/rules_unicorn_prefer_dom_node_dataset.go +55 -0
- package/linthost/rules_unicorn_prefer_dom_node_remove.go +41 -0
- package/linthost/rules_unicorn_prefer_dom_node_text_content.go +37 -0
- package/linthost/rules_unicorn_prefer_event_target.go +36 -0
- package/linthost/rules_unicorn_prefer_export_from.go +129 -0
- package/linthost/rules_unicorn_prefer_global_this.go +127 -0
- package/linthost/rules_unicorn_prefer_import_meta_properties.go +66 -0
- package/linthost/rules_unicorn_prefer_includes.go +149 -0
- package/linthost/rules_unicorn_prefer_json_parse_buffer.go +65 -0
- package/linthost/rules_unicorn_prefer_keyboard_event_key.go +38 -0
- package/linthost/rules_unicorn_prefer_logical_operator_over_ternary.go +48 -0
- package/linthost/rules_unicorn_prefer_math_min_max.go +60 -0
- package/linthost/rules_unicorn_prefer_math_trunc.go +62 -0
- package/linthost/rules_unicorn_prefer_modern_dom_apis.go +47 -0
- package/linthost/rules_unicorn_prefer_modern_math_apis.go +70 -0
- package/linthost/rules_unicorn_prefer_module.go +50 -0
- package/linthost/rules_unicorn_prefer_native_coercion_functions.go +114 -0
- package/linthost/rules_unicorn_prefer_negative_index.go +74 -0
- package/linthost/rules_unicorn_prefer_node_protocol.go +122 -0
- package/linthost/rules_unicorn_prefer_number_properties.go +88 -0
- package/linthost/rules_unicorn_prefer_object_from_entries.go +55 -0
- package/linthost/rules_unicorn_prefer_optional_catch_binding.go +62 -0
- package/linthost/rules_unicorn_prefer_prototype_methods.go +54 -0
- package/linthost/rules_unicorn_prefer_query_selector.go +56 -0
- package/linthost/rules_unicorn_prefer_reflect_apply.go +36 -0
- package/linthost/rules_unicorn_prefer_regexp_test_rule.go +80 -0
- package/linthost/rules_unicorn_prefer_response_static_json.go +53 -0
- package/linthost/rules_unicorn_prefer_set_has.go +42 -0
- package/linthost/rules_unicorn_prefer_set_size.go +48 -0
- package/linthost/rules_unicorn_prefer_simple_condition_first.go +34 -0
- package/linthost/rules_unicorn_prefer_single_call.go +96 -0
- package/linthost/rules_unicorn_prefer_spread.go +51 -0
- package/linthost/rules_unicorn_prefer_string_raw.go +43 -0
- package/linthost/rules_unicorn_prefer_string_replace_all.go +95 -0
- package/linthost/rules_unicorn_prefer_string_slice.go +43 -0
- package/linthost/rules_unicorn_prefer_string_starts_ends_with.go +148 -0
- package/linthost/rules_unicorn_prefer_string_trim_start_end.go +48 -0
- package/linthost/rules_unicorn_prefer_structured_clone.go +71 -0
- package/linthost/rules_unicorn_prefer_switch.go +103 -0
- package/linthost/rules_unicorn_prefer_ternary.go +71 -0
- package/linthost/rules_unicorn_prefer_top_level_await.go +72 -0
- package/linthost/rules_unicorn_prefer_type_error.go +127 -0
- package/linthost/rules_unicorn_prevent_abbreviations.go +127 -0
- package/linthost/rules_unicorn_relative_url_style.go +49 -0
- package/linthost/rules_unicorn_require_array_join_separator.go +45 -0
- package/linthost/rules_unicorn_require_module_attributes.go +54 -0
- package/linthost/rules_unicorn_require_module_specifiers.go +55 -0
- package/linthost/rules_unicorn_require_number_to_fixed_digits_argument.go +43 -0
- package/linthost/rules_unicorn_require_post_message_target_origin.go +44 -0
- package/linthost/rules_unicorn_string_content.go +27 -0
- package/linthost/rules_unicorn_switch_case_braces.go +42 -0
- package/linthost/rules_unicorn_switch_case_break_position.go +31 -0
- package/linthost/rules_unicorn_template_indent.go +28 -0
- package/linthost/rules_unicorn_text_encoding_identifier_case.go +72 -0
- package/linthost/rules_unicorn_throw_new_error.go +61 -0
- package/linthost/rules_var.go +10 -4
- package/linthost/rules_vitest.go +568 -0
- package/package.json +3 -3
- package/plugin/main.go +49 -3
- package/rule/astutil/astutil.go +10 -3
- package/rule/rule.go +12 -10
- package/src/defaultFormat.ts +11 -8
- package/src/index.ts +65 -43
- package/src/structures/ITtscLintConfig.ts +12 -6
- package/src/structures/{ITtscLintFormatConfig.ts → ITtscLintFormat.ts} +2 -2
- package/src/structures/TtscLintRuleSetting.ts +55 -0
- package/src/structures/index.ts +3 -4
- package/src/structures/rules/ITtscLintBoundariesRuleOptions.ts +128 -0
- package/src/structures/rules/ITtscLintBoundariesRules.ts +95 -0
- package/src/structures/rules/ITtscLintContributorRules.ts +21 -0
- package/src/structures/rules/ITtscLintCoreRules.ts +1406 -0
- package/src/structures/rules/ITtscLintCypressRuleOptions.ts +18 -0
- package/src/structures/rules/ITtscLintCypressRules.ts +145 -0
- package/src/structures/rules/ITtscLintFunctionalRuleOptions.ts +213 -0
- package/src/structures/rules/ITtscLintFunctionalRules.ts +202 -0
- package/src/structures/rules/ITtscLintJestRules.ts +220 -0
- package/src/structures/rules/ITtscLintJsdocRules.ts +153 -0
- package/src/structures/rules/ITtscLintJsxA11yRules.ts +339 -0
- package/src/structures/rules/ITtscLintNextjsRules.ts +206 -0
- package/src/structures/rules/ITtscLintPlaywrightRules.ts +361 -0
- package/src/structures/rules/ITtscLintPromiseRules.ts +205 -0
- package/src/structures/rules/ITtscLintReactPerfRuleOptions.ts +19 -0
- package/src/structures/rules/ITtscLintReactPerfRules.ts +55 -0
- package/src/structures/rules/ITtscLintReactRuleOptions.ts +43 -0
- package/src/structures/rules/ITtscLintReactRules.ts +321 -0
- package/src/structures/rules/ITtscLintRegexpRules.ts +212 -0
- package/src/structures/rules/ITtscLintRuleOptionsMap.ts +89 -0
- package/src/structures/rules/ITtscLintRules.ts +77 -0
- package/src/structures/rules/ITtscLintSecurityRules.ts +162 -0
- package/src/structures/rules/ITtscLintSolidRules.ts +202 -0
- package/src/structures/rules/ITtscLintStorybookRuleOptions.ts +23 -0
- package/src/structures/rules/ITtscLintStorybookRules.ts +193 -0
- package/src/structures/rules/ITtscLintTanstackQueryRules.ts +102 -0
- package/src/structures/rules/ITtscLintTestingLibraryRuleOptions.ts +24 -0
- package/src/structures/rules/ITtscLintTestingLibraryRules.ts +342 -0
- package/src/structures/rules/ITtscLintTypeScriptRules.ts +1230 -0
- package/src/structures/rules/ITtscLintUnicornRules.ts +1143 -0
- package/src/structures/rules/ITtscLintVitestRules.ts +154 -0
- package/src/structures/rules/index.ts +31 -0
- package/lib/structures/ITtscLintFormatConfig.js.map +0 -1
- package/lib/structures/TtscLintRule.d.ts +0 -17
- package/lib/structures/TtscLintRule.js.map +0 -1
- package/lib/structures/TtscLintRuleMap.d.ts +0 -46
- package/lib/structures/TtscLintRuleMap.js.map +0 -1
- package/lib/structures/TtscLintRuleOptions.d.ts +0 -137
- package/lib/structures/TtscLintRuleOptions.js.map +0 -1
- package/src/structures/TtscLintRule.ts +0 -160
- package/src/structures/TtscLintRuleMap.ts +0 -55
- package/src/structures/TtscLintRuleOptions.ts +0 -151
|
@@ -28,7 +28,7 @@ import (
|
|
|
28
28
|
// indented, corrupt output. To prevent that, every printer reports a
|
|
29
29
|
// `covered` boolean alongside its Doc: `true` means the whole printed
|
|
30
30
|
// subtree is reflow-safe (no multi-line verbatim node), `false` means a
|
|
31
|
-
// multi-line verbatim node is buried inside. The
|
|
31
|
+
// multi-line verbatim node is buried inside. The formatPrintWidth
|
|
32
32
|
// rule abstains entirely when `covered` is false, so `ttsc format`
|
|
33
33
|
// either reflows correctly or leaves the bytes untouched — it never
|
|
34
34
|
// emits the half-reflowed shape. Single-line verbatim is always safe:
|
|
@@ -59,7 +59,7 @@ func NewPrintContext(file *shimast.SourceFile, opts PrintOptions) *PrintContext
|
|
|
59
59
|
// boolean: `true` when the whole printed subtree is reflow-safe,
|
|
60
60
|
// `false` when a multi-line verbatim node is buried inside it.
|
|
61
61
|
//
|
|
62
|
-
// The
|
|
62
|
+
// The formatPrintWidth rule consults `covered` to decide whether to
|
|
63
63
|
// emit an edit at all — see the coverage-signal note at the top of this
|
|
64
64
|
// file. A `false` reading is a hard abstain, not a soft hint.
|
|
65
65
|
func PrintNode(ctx *PrintContext, node *shimast.Node) (Doc, bool) {
|
|
@@ -25,7 +25,7 @@ import (
|
|
|
25
25
|
// the newlines live, so the body is dispatched through PrintNode and
|
|
26
26
|
// re-indented by the Doc engine. Each printer ANDs the body's `covered`
|
|
27
27
|
// flag into its own result: a body the dispatcher cannot fully control
|
|
28
|
-
// taints the whole subtree and the
|
|
28
|
+
// taints the whole subtree and the formatPrintWidth rule abstains.
|
|
29
29
|
//
|
|
30
30
|
// The expression- and return-statement printers carry the same
|
|
31
31
|
// discipline one level deeper: a callback body whose statements are
|
|
@@ -224,7 +224,7 @@ func blankLineBetweenStatements(src string, prevEnd, nextPos int) bool {
|
|
|
224
224
|
// printer joins statements with bare Hardlines that have no slot for
|
|
225
225
|
// inter-statement trivia, so a stray comment would be dropped by a
|
|
226
226
|
// reflow. Detecting it lets printBlock report the block uncovered and
|
|
227
|
-
// the
|
|
227
|
+
// the formatPrintWidth rule abstain.
|
|
228
228
|
//
|
|
229
229
|
// The scan mirrors rules_format_print_width.go::hasNonChildComments:
|
|
230
230
|
// comment-shaped bytes inside a complete statement token range (string
|
|
@@ -74,7 +74,7 @@ func printObjectLiteral(ctx *PrintContext, node *shimast.Node) (Doc, bool) {
|
|
|
74
74
|
//
|
|
75
75
|
// Prettier's objectWrap:"preserve" default keeps such an object
|
|
76
76
|
// expanded even when it would fit flat, treating the author's line
|
|
77
|
-
// break as intentional structure.
|
|
77
|
+
// break as intentional structure. formatPrintWidth mirrors that:
|
|
78
78
|
// without it a deliberately multi-line object that happens to fit
|
|
79
79
|
// would be silently collapsed onto one line, which Prettier never
|
|
80
80
|
// does.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
package linthost
|
|
2
|
+
|
|
3
|
+
import "strings"
|
|
4
|
+
|
|
5
|
+
// normalizeBuiltinRuleName strips the optional `eslint/` namespace prefix
|
|
6
|
+
// so users may write either the bare rule id or the explicit `eslint/<id>`
|
|
7
|
+
// form. `@ttsc/lint` deliberately rejects the legacy `@typescript-eslint/`
|
|
8
|
+
// and `typescript-eslint/` prefixes — TypeScript-only rules live under
|
|
9
|
+
// the canonical `typescript/<id>` namespace.
|
|
10
|
+
func normalizeBuiltinRuleName(name string) string {
|
|
11
|
+
name = strings.TrimSpace(name)
|
|
12
|
+
name = strings.TrimPrefix(name, "eslint/")
|
|
13
|
+
return name
|
|
14
|
+
}
|
package/linthost/rules_arrays.go
CHANGED
|
@@ -2,7 +2,7 @@ package linthost
|
|
|
2
2
|
|
|
3
3
|
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
4
4
|
|
|
5
|
-
//
|
|
5
|
+
// noSparseArrays: `[1, , 2]` — the implied undefined slot is almost
|
|
6
6
|
// always a typo.
|
|
7
7
|
// https://eslint.org/docs/latest/rules/no-sparse-arrays
|
|
8
8
|
type noSparseArrays struct{}
|
|
@@ -24,7 +24,7 @@ func (noSparseArrays) Check(ctx *Context, node *shimast.Node) {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
//
|
|
27
|
+
// noArrayConstructor: forbid `new Array(0)` / `Array(1, 2, 3)` (use
|
|
28
28
|
// array literals). The single-argument form is intentionally excluded from
|
|
29
29
|
// the ban: `Array(n)` is commonly used to pre-allocate a sparse array by
|
|
30
30
|
// length, and banning it would generate noise on existing idiomatic code.
|
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
package linthost
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"encoding/json"
|
|
5
|
+
"fmt"
|
|
6
|
+
"os"
|
|
7
|
+
"path/filepath"
|
|
8
|
+
"regexp"
|
|
9
|
+
"sort"
|
|
10
|
+
"strings"
|
|
11
|
+
|
|
12
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
type boundariesElementTypes struct{}
|
|
16
|
+
type boundariesExternal struct{}
|
|
17
|
+
type boundariesEntryPoint struct{}
|
|
18
|
+
type boundariesNoPrivate struct{}
|
|
19
|
+
type boundariesNoUnknown struct{}
|
|
20
|
+
|
|
21
|
+
// boundariesDependencies is a v1 stub for the upstream unified
|
|
22
|
+
// `boundaries/dependencies` rule, which replaces the legacy
|
|
23
|
+
// `element-types` / `entry-point` / `external` / `no-private` /
|
|
24
|
+
// `no-unknown` rules with a single direction-aware policy block.
|
|
25
|
+
//
|
|
26
|
+
// The native engine accepts the same `elements` + `rules` config shape so
|
|
27
|
+
// projects can claim the rule id today, but the full direction
|
|
28
|
+
// validation is deferred. Until then this rule registers, decodes
|
|
29
|
+
// options without crashing, and emits no diagnostics.
|
|
30
|
+
type boundariesDependencies struct{}
|
|
31
|
+
|
|
32
|
+
func (boundariesElementTypes) Name() string { return "boundaries/element-types" }
|
|
33
|
+
func (boundariesExternal) Name() string { return "boundaries/external" }
|
|
34
|
+
func (boundariesEntryPoint) Name() string { return "boundaries/entry-point" }
|
|
35
|
+
func (boundariesNoPrivate) Name() string { return "boundaries/no-private" }
|
|
36
|
+
func (boundariesNoUnknown) Name() string { return "boundaries/no-unknown" }
|
|
37
|
+
func (boundariesDependencies) Name() string { return "boundaries/dependencies" }
|
|
38
|
+
|
|
39
|
+
func (boundariesElementTypes) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindSourceFile} }
|
|
40
|
+
func (boundariesExternal) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindSourceFile} }
|
|
41
|
+
func (boundariesEntryPoint) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindSourceFile} }
|
|
42
|
+
func (boundariesNoPrivate) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindSourceFile} }
|
|
43
|
+
func (boundariesNoUnknown) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindSourceFile} }
|
|
44
|
+
func (boundariesDependencies) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindSourceFile} }
|
|
45
|
+
|
|
46
|
+
// Check is intentionally a no-op for the v1 stub. The rule accepts the
|
|
47
|
+
// upstream config shape via the shared `boundariesOptions` decoder so
|
|
48
|
+
// downstream configs type-check and load, then exits without reporting
|
|
49
|
+
// findings. Replace this body when the unified direction validation
|
|
50
|
+
// lands.
|
|
51
|
+
func (boundariesDependencies) Check(ctx *Context, node *shimast.Node) {
|
|
52
|
+
_ = decodeBoundariesOptions(ctx)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
func (boundariesElementTypes) Check(ctx *Context, node *shimast.Node) {
|
|
56
|
+
opts := decodeBoundariesOptions(ctx)
|
|
57
|
+
if len(opts.Elements) == 0 {
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
source := classifyBoundaryFile(ctx.File.FileName(), opts.Elements)
|
|
61
|
+
if source == nil {
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
for _, dep := range collectBoundaryDependencies(node) {
|
|
65
|
+
if !dep.relative {
|
|
66
|
+
continue
|
|
67
|
+
}
|
|
68
|
+
targetPath, ok := resolveBoundaryImport(ctx.File.FileName(), dep.specifier)
|
|
69
|
+
if !ok {
|
|
70
|
+
continue
|
|
71
|
+
}
|
|
72
|
+
target := classifyBoundaryFile(targetPath, opts.Elements)
|
|
73
|
+
if target == nil {
|
|
74
|
+
continue
|
|
75
|
+
}
|
|
76
|
+
policy, rule := evaluateBoundaryPolicy(opts, source.Type, target.Type)
|
|
77
|
+
if policy != "disallow" {
|
|
78
|
+
continue
|
|
79
|
+
}
|
|
80
|
+
message := fmt.Sprintf("Import from boundary element %q is not allowed in %q.", target.Type, source.Type)
|
|
81
|
+
if rule != nil && rule.Message != "" {
|
|
82
|
+
message = rule.Message
|
|
83
|
+
}
|
|
84
|
+
reportBoundaryDependency(ctx, dep, message)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
func (boundariesExternal) Check(ctx *Context, node *shimast.Node) {
|
|
89
|
+
opts := decodeBoundariesOptions(ctx)
|
|
90
|
+
for _, dep := range collectBoundaryDependencies(node) {
|
|
91
|
+
if dep.relative {
|
|
92
|
+
continue
|
|
93
|
+
}
|
|
94
|
+
name := boundaryPackageName(dep.specifier)
|
|
95
|
+
disallowed := matchAnyBoundaryPattern(opts.Disallow, dep.specifier, name)
|
|
96
|
+
allowed := len(opts.Allow) == 0 || matchAnyBoundaryPattern(opts.Allow, dep.specifier, name)
|
|
97
|
+
if !disallowed && allowed {
|
|
98
|
+
continue
|
|
99
|
+
}
|
|
100
|
+
message := fmt.Sprintf("External dependency %q is not allowed.", dep.specifier)
|
|
101
|
+
if opts.Message != "" {
|
|
102
|
+
message = opts.Message
|
|
103
|
+
}
|
|
104
|
+
reportBoundaryDependency(ctx, dep, message)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
func (boundariesEntryPoint) Check(ctx *Context, node *shimast.Node) {
|
|
109
|
+
opts := decodeBoundariesOptions(ctx)
|
|
110
|
+
if len(opts.Elements) == 0 {
|
|
111
|
+
return
|
|
112
|
+
}
|
|
113
|
+
source := classifyBoundaryFile(ctx.File.FileName(), opts.Elements)
|
|
114
|
+
for _, dep := range collectBoundaryDependencies(node) {
|
|
115
|
+
if !dep.relative {
|
|
116
|
+
continue
|
|
117
|
+
}
|
|
118
|
+
targetPath, ok := resolveBoundaryImport(ctx.File.FileName(), dep.specifier)
|
|
119
|
+
if !ok {
|
|
120
|
+
continue
|
|
121
|
+
}
|
|
122
|
+
target := classifyBoundaryFile(targetPath, opts.Elements)
|
|
123
|
+
if target == nil || len(target.Entry) == 0 {
|
|
124
|
+
continue
|
|
125
|
+
}
|
|
126
|
+
if source != nil && source.RootPath == target.RootPath {
|
|
127
|
+
continue
|
|
128
|
+
}
|
|
129
|
+
if matchBoundaryElementLocalPattern(target.Entry, target) {
|
|
130
|
+
continue
|
|
131
|
+
}
|
|
132
|
+
reportBoundaryDependency(ctx, dep, fmt.Sprintf("Import %q through an allowed boundary entry point.", target.RelativePath))
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
func (boundariesNoPrivate) Check(ctx *Context, node *shimast.Node) {
|
|
137
|
+
opts := decodeBoundariesOptions(ctx)
|
|
138
|
+
if len(opts.Elements) == 0 {
|
|
139
|
+
return
|
|
140
|
+
}
|
|
141
|
+
source := classifyBoundaryFile(ctx.File.FileName(), opts.Elements)
|
|
142
|
+
if source == nil {
|
|
143
|
+
return
|
|
144
|
+
}
|
|
145
|
+
for _, dep := range collectBoundaryDependencies(node) {
|
|
146
|
+
if !dep.relative {
|
|
147
|
+
continue
|
|
148
|
+
}
|
|
149
|
+
targetPath, ok := resolveBoundaryImport(ctx.File.FileName(), dep.specifier)
|
|
150
|
+
if !ok {
|
|
151
|
+
continue
|
|
152
|
+
}
|
|
153
|
+
target := classifyBoundaryFile(targetPath, opts.Elements)
|
|
154
|
+
if target == nil || len(target.Private) == 0 {
|
|
155
|
+
continue
|
|
156
|
+
}
|
|
157
|
+
if source.RootPath == target.RootPath || !matchBoundaryElementLocalPattern(target.Private, target) {
|
|
158
|
+
continue
|
|
159
|
+
}
|
|
160
|
+
reportBoundaryDependency(ctx, dep, fmt.Sprintf("Do not import private boundary file %q from another element.", target.RelativePath))
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
func (boundariesNoUnknown) Check(ctx *Context, node *shimast.Node) {
|
|
165
|
+
opts := decodeBoundariesOptions(ctx)
|
|
166
|
+
if len(opts.Elements) == 0 {
|
|
167
|
+
return
|
|
168
|
+
}
|
|
169
|
+
for _, dep := range collectBoundaryDependencies(node) {
|
|
170
|
+
if !dep.relative {
|
|
171
|
+
continue
|
|
172
|
+
}
|
|
173
|
+
targetPath, ok := resolveBoundaryImport(ctx.File.FileName(), dep.specifier)
|
|
174
|
+
if !ok {
|
|
175
|
+
continue
|
|
176
|
+
}
|
|
177
|
+
if classifyBoundaryFile(targetPath, opts.Elements) != nil {
|
|
178
|
+
continue
|
|
179
|
+
}
|
|
180
|
+
reportBoundaryDependency(ctx, dep, fmt.Sprintf("Imported file %q does not match any configured boundary element.", boundaryDisplayPath(targetPath)))
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
type boundaryStringList []string
|
|
185
|
+
|
|
186
|
+
func (l *boundaryStringList) UnmarshalJSON(data []byte) error {
|
|
187
|
+
if string(data) == "null" {
|
|
188
|
+
*l = nil
|
|
189
|
+
return nil
|
|
190
|
+
}
|
|
191
|
+
var single string
|
|
192
|
+
if err := json.Unmarshal(data, &single); err == nil {
|
|
193
|
+
*l = boundaryStringList{single}
|
|
194
|
+
return nil
|
|
195
|
+
}
|
|
196
|
+
var many []string
|
|
197
|
+
if err := json.Unmarshal(data, &many); err != nil {
|
|
198
|
+
return err
|
|
199
|
+
}
|
|
200
|
+
*l = boundaryStringList(many)
|
|
201
|
+
return nil
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
type boundariesOptions struct {
|
|
205
|
+
Elements []boundaryElement `json:"elements"`
|
|
206
|
+
Rules []boundaryPolicyRule `json:"rules"`
|
|
207
|
+
Default string `json:"default"`
|
|
208
|
+
Allow boundaryStringList `json:"allow"`
|
|
209
|
+
Disallow boundaryStringList `json:"disallow"`
|
|
210
|
+
Message string `json:"message"`
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
type boundaryElement struct {
|
|
214
|
+
Type string `json:"type"`
|
|
215
|
+
Pattern string `json:"pattern"`
|
|
216
|
+
Entry boundaryStringList `json:"entry"`
|
|
217
|
+
Private boundaryStringList `json:"private"`
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
type boundaryPolicyRule struct {
|
|
221
|
+
From boundaryStringList `json:"from"`
|
|
222
|
+
Allow boundaryStringList `json:"allow"`
|
|
223
|
+
Disallow boundaryStringList `json:"disallow"`
|
|
224
|
+
Message string `json:"message"`
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
type boundaryFile struct {
|
|
228
|
+
Element boundaryElement
|
|
229
|
+
Type string
|
|
230
|
+
Path string
|
|
231
|
+
RelativePath string
|
|
232
|
+
RootPath string
|
|
233
|
+
LocalPath string
|
|
234
|
+
Entry boundaryStringList
|
|
235
|
+
Private boundaryStringList
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
type boundaryDependency struct {
|
|
239
|
+
node *shimast.Node
|
|
240
|
+
specifier string
|
|
241
|
+
relative bool
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
func decodeBoundariesOptions(ctx *Context) boundariesOptions {
|
|
245
|
+
var opts boundariesOptions
|
|
246
|
+
if ctx != nil {
|
|
247
|
+
_ = ctx.DecodeOptions(&opts)
|
|
248
|
+
}
|
|
249
|
+
return opts
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
func collectBoundaryDependencies(node *shimast.Node) []boundaryDependency {
|
|
253
|
+
out := []boundaryDependency{}
|
|
254
|
+
var walk func(*shimast.Node)
|
|
255
|
+
walk = func(n *shimast.Node) {
|
|
256
|
+
if n == nil {
|
|
257
|
+
return
|
|
258
|
+
}
|
|
259
|
+
switch n.Kind {
|
|
260
|
+
case shimast.KindImportDeclaration:
|
|
261
|
+
if imp := n.AsImportDeclaration(); imp != nil && imp.ModuleSpecifier != nil {
|
|
262
|
+
specifier := stringLiteralText(imp.ModuleSpecifier)
|
|
263
|
+
if specifier != "" {
|
|
264
|
+
out = append(out, boundaryDependency{
|
|
265
|
+
node: imp.ModuleSpecifier,
|
|
266
|
+
specifier: specifier,
|
|
267
|
+
relative: isRelativeBoundarySpecifier(specifier),
|
|
268
|
+
})
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
case shimast.KindExportDeclaration:
|
|
272
|
+
if exp := n.AsExportDeclaration(); exp != nil && exp.ModuleSpecifier != nil {
|
|
273
|
+
specifier := stringLiteralText(exp.ModuleSpecifier)
|
|
274
|
+
if specifier != "" {
|
|
275
|
+
out = append(out, boundaryDependency{
|
|
276
|
+
node: exp.ModuleSpecifier,
|
|
277
|
+
specifier: specifier,
|
|
278
|
+
relative: isRelativeBoundarySpecifier(specifier),
|
|
279
|
+
})
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
n.ForEachChild(func(child *shimast.Node) bool {
|
|
284
|
+
walk(child)
|
|
285
|
+
return false
|
|
286
|
+
})
|
|
287
|
+
}
|
|
288
|
+
walk(node)
|
|
289
|
+
return out
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
func classifyBoundaryFile(fileName string, elements []boundaryElement) *boundaryFile {
|
|
293
|
+
normalized := normalizeBoundaryPath(fileName)
|
|
294
|
+
matches := []boundaryFile{}
|
|
295
|
+
for _, elem := range elements {
|
|
296
|
+
if elem.Type == "" || elem.Pattern == "" {
|
|
297
|
+
continue
|
|
298
|
+
}
|
|
299
|
+
rel, ok := boundaryRelativeMatch(elem.Pattern, normalized)
|
|
300
|
+
if !ok {
|
|
301
|
+
continue
|
|
302
|
+
}
|
|
303
|
+
root := boundaryElementRoot(elem.Pattern, rel)
|
|
304
|
+
local := rel
|
|
305
|
+
if root != "" {
|
|
306
|
+
local = strings.TrimPrefix(rel, root)
|
|
307
|
+
local = strings.TrimPrefix(local, "/")
|
|
308
|
+
}
|
|
309
|
+
matches = append(matches, boundaryFile{
|
|
310
|
+
Element: elem,
|
|
311
|
+
Type: elem.Type,
|
|
312
|
+
Path: normalized,
|
|
313
|
+
RelativePath: rel,
|
|
314
|
+
RootPath: root,
|
|
315
|
+
LocalPath: local,
|
|
316
|
+
Entry: elem.Entry,
|
|
317
|
+
Private: elem.Private,
|
|
318
|
+
})
|
|
319
|
+
}
|
|
320
|
+
if len(matches) == 0 {
|
|
321
|
+
return nil
|
|
322
|
+
}
|
|
323
|
+
sort.Slice(matches, func(i, j int) bool {
|
|
324
|
+
return len(matches[i].RootPath) > len(matches[j].RootPath)
|
|
325
|
+
})
|
|
326
|
+
return &matches[0]
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
func evaluateBoundaryPolicy(opts boundariesOptions, fromType, targetType string) (string, *boundaryPolicyRule) {
|
|
330
|
+
defaultPolicy := opts.Default
|
|
331
|
+
if defaultPolicy == "" {
|
|
332
|
+
defaultPolicy = "allow"
|
|
333
|
+
}
|
|
334
|
+
for i := range opts.Rules {
|
|
335
|
+
rule := &opts.Rules[i]
|
|
336
|
+
if len(rule.From) > 0 && !matchAnyBoundaryPattern(rule.From, fromType) {
|
|
337
|
+
continue
|
|
338
|
+
}
|
|
339
|
+
if len(rule.Disallow) > 0 && matchAnyBoundaryPattern(rule.Disallow, targetType) {
|
|
340
|
+
return "disallow", rule
|
|
341
|
+
}
|
|
342
|
+
if len(rule.Allow) > 0 {
|
|
343
|
+
if matchAnyBoundaryPattern(rule.Allow, targetType) {
|
|
344
|
+
return "allow", rule
|
|
345
|
+
}
|
|
346
|
+
return "disallow", rule
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return defaultPolicy, nil
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
func resolveBoundaryImport(sourceFileName, specifier string) (string, bool) {
|
|
353
|
+
if !isRelativeBoundarySpecifier(specifier) {
|
|
354
|
+
return "", false
|
|
355
|
+
}
|
|
356
|
+
base := filepath.Dir(sourceFileName)
|
|
357
|
+
target := filepath.Clean(filepath.Join(base, filepath.FromSlash(specifier)))
|
|
358
|
+
candidates := []string{target}
|
|
359
|
+
if filepath.Ext(target) == "" {
|
|
360
|
+
for _, ext := range []string{".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"} {
|
|
361
|
+
candidates = append(candidates, target+ext)
|
|
362
|
+
}
|
|
363
|
+
for _, ext := range []string{".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"} {
|
|
364
|
+
candidates = append(candidates, filepath.Join(target, "index"+ext))
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
for _, candidate := range candidates {
|
|
368
|
+
if info, err := os.Stat(candidate); err == nil && !info.IsDir() {
|
|
369
|
+
abs, err := filepath.Abs(candidate)
|
|
370
|
+
if err == nil {
|
|
371
|
+
return abs, true
|
|
372
|
+
}
|
|
373
|
+
return candidate, true
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return "", false
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
func reportBoundaryDependency(ctx *Context, dep boundaryDependency, message string) {
|
|
380
|
+
if dep.node != nil {
|
|
381
|
+
ctx.Report(dep.node, message)
|
|
382
|
+
return
|
|
383
|
+
}
|
|
384
|
+
ctx.ReportRange(0, 1, message)
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
func matchBoundaryElementLocalPattern(patterns boundaryStringList, file *boundaryFile) bool {
|
|
388
|
+
if file == nil {
|
|
389
|
+
return false
|
|
390
|
+
}
|
|
391
|
+
for _, pattern := range patterns {
|
|
392
|
+
if boundaryPatternMatch(pattern, file.LocalPath) || boundaryPatternMatch(pattern, filepath.Base(file.LocalPath)) || boundaryPatternMatch(pattern, file.RelativePath) {
|
|
393
|
+
return true
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
return false
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
func matchAnyBoundaryPattern(patterns boundaryStringList, candidates ...string) bool {
|
|
400
|
+
for _, pattern := range patterns {
|
|
401
|
+
for _, candidate := range candidates {
|
|
402
|
+
if boundaryPatternMatch(pattern, candidate) {
|
|
403
|
+
return true
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
return false
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
func boundaryRelativeMatch(pattern, fileName string) (string, bool) {
|
|
411
|
+
for _, candidate := range boundaryPathCandidates(fileName) {
|
|
412
|
+
if boundaryPatternMatch(pattern, candidate) {
|
|
413
|
+
return candidate, true
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
return "", false
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
func boundaryPatternMatch(pattern, candidate string) bool {
|
|
420
|
+
pattern = strings.TrimPrefix(normalizeBoundaryPath(pattern), "./")
|
|
421
|
+
candidate = strings.TrimPrefix(normalizeBoundaryPath(candidate), "./")
|
|
422
|
+
if pattern == "" || candidate == "" {
|
|
423
|
+
return false
|
|
424
|
+
}
|
|
425
|
+
re, err := regexp.Compile("^" + regexp.QuoteMeta(pattern) + "$")
|
|
426
|
+
if err != nil {
|
|
427
|
+
return false
|
|
428
|
+
}
|
|
429
|
+
expr := re.String()
|
|
430
|
+
expr = strings.ReplaceAll(expr, `\*\*`, ".*")
|
|
431
|
+
expr = strings.ReplaceAll(expr, `\*`, `[^/]*`)
|
|
432
|
+
expr = strings.ReplaceAll(expr, `\?`, `[^/]`)
|
|
433
|
+
re, err = regexp.Compile(expr)
|
|
434
|
+
if err != nil {
|
|
435
|
+
return false
|
|
436
|
+
}
|
|
437
|
+
return re.MatchString(candidate)
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
func boundaryPathCandidates(path string) []string {
|
|
441
|
+
normalized := strings.TrimPrefix(normalizeBoundaryPath(path), "/")
|
|
442
|
+
candidates := []string{normalized}
|
|
443
|
+
if cwd, err := os.Getwd(); err == nil {
|
|
444
|
+
if rel, err := filepath.Rel(cwd, path); err == nil && !strings.HasPrefix(rel, "..") {
|
|
445
|
+
candidates = append(candidates, normalizeBoundaryPath(rel))
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
parts := strings.Split(normalized, "/")
|
|
449
|
+
for i := 1; i < len(parts); i++ {
|
|
450
|
+
candidates = append(candidates, strings.Join(parts[i:], "/"))
|
|
451
|
+
}
|
|
452
|
+
return uniqueBoundaryStrings(candidates)
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
func boundaryElementRoot(pattern, matched string) string {
|
|
456
|
+
pattern = strings.TrimPrefix(normalizeBoundaryPath(pattern), "./")
|
|
457
|
+
wildcard := len(pattern)
|
|
458
|
+
for _, token := range []string{"*", "?"} {
|
|
459
|
+
if idx := strings.Index(pattern, token); idx >= 0 && idx < wildcard {
|
|
460
|
+
wildcard = idx
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
root := strings.TrimSuffix(pattern[:wildcard], "/")
|
|
464
|
+
if root == pattern {
|
|
465
|
+
root = filepath.ToSlash(filepath.Dir(root))
|
|
466
|
+
if root == "." {
|
|
467
|
+
root = ""
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
if root != "" {
|
|
471
|
+
return root
|
|
472
|
+
}
|
|
473
|
+
if slash := strings.LastIndex(matched, "/"); slash >= 0 {
|
|
474
|
+
return matched[:slash]
|
|
475
|
+
}
|
|
476
|
+
return ""
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
func boundaryPackageName(specifier string) string {
|
|
480
|
+
if strings.HasPrefix(specifier, "@") {
|
|
481
|
+
parts := strings.Split(specifier, "/")
|
|
482
|
+
if len(parts) >= 2 {
|
|
483
|
+
return parts[0] + "/" + parts[1]
|
|
484
|
+
}
|
|
485
|
+
return specifier
|
|
486
|
+
}
|
|
487
|
+
if idx := strings.Index(specifier, "/"); idx >= 0 {
|
|
488
|
+
return specifier[:idx]
|
|
489
|
+
}
|
|
490
|
+
return specifier
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
func boundaryDisplayPath(path string) string {
|
|
494
|
+
candidates := boundaryPathCandidates(path)
|
|
495
|
+
if len(candidates) == 0 {
|
|
496
|
+
return normalizeBoundaryPath(path)
|
|
497
|
+
}
|
|
498
|
+
return candidates[0]
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
func normalizeBoundaryPath(path string) string {
|
|
502
|
+
return filepath.ToSlash(filepath.Clean(path))
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
func isRelativeBoundarySpecifier(specifier string) bool {
|
|
506
|
+
return specifier == "." || specifier == ".." || strings.HasPrefix(specifier, "./") || strings.HasPrefix(specifier, "../")
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
func uniqueBoundaryStrings(values []string) []string {
|
|
510
|
+
seen := map[string]struct{}{}
|
|
511
|
+
out := []string{}
|
|
512
|
+
for _, value := range values {
|
|
513
|
+
if value == "" {
|
|
514
|
+
continue
|
|
515
|
+
}
|
|
516
|
+
if _, ok := seen[value]; ok {
|
|
517
|
+
continue
|
|
518
|
+
}
|
|
519
|
+
seen[value] = struct{}{}
|
|
520
|
+
out = append(out, value)
|
|
521
|
+
}
|
|
522
|
+
return out
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
func init() {
|
|
526
|
+
Register(boundariesElementTypes{})
|
|
527
|
+
Register(boundariesExternal{})
|
|
528
|
+
Register(boundariesEntryPoint{})
|
|
529
|
+
Register(boundariesNoPrivate{})
|
|
530
|
+
Register(boundariesNoUnknown{})
|
|
531
|
+
Register(boundariesDependencies{})
|
|
532
|
+
}
|