@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.
Files changed (467) hide show
  1. package/README.md +948 -69
  2. package/lib/defaultFormat.d.ts +9 -6
  3. package/lib/defaultFormat.js +9 -6
  4. package/lib/defaultFormat.js.map +1 -1
  5. package/lib/index.d.ts +46 -0
  6. package/lib/index.js +60 -37
  7. package/lib/index.js.map +1 -1
  8. package/lib/structures/ITtscLintConfig.d.ts +12 -6
  9. package/lib/structures/{ITtscLintFormatConfig.d.ts → ITtscLintFormat.d.ts} +2 -2
  10. package/lib/structures/{TtscLintRuleMap.js → ITtscLintFormat.js} +1 -1
  11. package/lib/structures/ITtscLintFormat.js.map +1 -0
  12. package/lib/structures/TtscLintRuleSetting.d.ts +49 -0
  13. package/lib/structures/{TtscLintRuleOptions.js → TtscLintRuleSetting.js} +1 -1
  14. package/lib/structures/TtscLintRuleSetting.js.map +1 -0
  15. package/lib/structures/index.d.ts +3 -4
  16. package/lib/structures/index.js +3 -4
  17. package/lib/structures/index.js.map +1 -1
  18. package/lib/structures/rules/ITtscLintBoundariesRuleOptions.d.ts +104 -0
  19. package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js +14 -0
  20. package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js.map +1 -0
  21. package/lib/structures/rules/ITtscLintBoundariesRules.d.ts +79 -0
  22. package/lib/structures/rules/ITtscLintBoundariesRules.js +3 -0
  23. package/lib/structures/rules/ITtscLintBoundariesRules.js.map +1 -0
  24. package/lib/structures/rules/ITtscLintContributorRules.d.ts +17 -0
  25. package/lib/structures/rules/ITtscLintContributorRules.js +3 -0
  26. package/lib/structures/rules/ITtscLintContributorRules.js.map +1 -0
  27. package/lib/structures/rules/ITtscLintCoreRules.d.ts +1257 -0
  28. package/lib/structures/{ITtscLintFormatConfig.js → rules/ITtscLintCoreRules.js} +1 -1
  29. package/lib/structures/rules/ITtscLintCoreRules.js.map +1 -0
  30. package/lib/structures/rules/ITtscLintCypressRuleOptions.d.ts +17 -0
  31. package/lib/structures/rules/ITtscLintCypressRuleOptions.js +10 -0
  32. package/lib/structures/rules/ITtscLintCypressRuleOptions.js.map +1 -0
  33. package/lib/structures/rules/ITtscLintCypressRules.d.ts +129 -0
  34. package/lib/structures/rules/ITtscLintCypressRules.js +3 -0
  35. package/lib/structures/rules/ITtscLintCypressRules.js.map +1 -0
  36. package/lib/structures/rules/ITtscLintFunctionalRuleOptions.d.ts +157 -0
  37. package/lib/structures/rules/ITtscLintFunctionalRuleOptions.js +13 -0
  38. package/lib/structures/rules/ITtscLintFunctionalRuleOptions.js.map +1 -0
  39. package/lib/structures/rules/ITtscLintFunctionalRules.d.ts +167 -0
  40. package/lib/structures/rules/ITtscLintFunctionalRules.js +3 -0
  41. package/lib/structures/rules/ITtscLintFunctionalRules.js.map +1 -0
  42. package/lib/structures/rules/ITtscLintJestRules.d.ts +201 -0
  43. package/lib/structures/rules/ITtscLintJestRules.js +3 -0
  44. package/lib/structures/rules/ITtscLintJestRules.js.map +1 -0
  45. package/lib/structures/rules/ITtscLintJsdocRules.d.ts +140 -0
  46. package/lib/structures/rules/ITtscLintJsdocRules.js +3 -0
  47. package/lib/structures/rules/ITtscLintJsdocRules.js.map +1 -0
  48. package/lib/structures/rules/ITtscLintJsxA11yRules.d.ts +302 -0
  49. package/lib/structures/rules/ITtscLintJsxA11yRules.js +3 -0
  50. package/lib/structures/rules/ITtscLintJsxA11yRules.js.map +1 -0
  51. package/lib/structures/rules/ITtscLintNextjsRules.d.ts +185 -0
  52. package/lib/structures/rules/ITtscLintNextjsRules.js +3 -0
  53. package/lib/structures/rules/ITtscLintNextjsRules.js.map +1 -0
  54. package/lib/structures/rules/ITtscLintPlaywrightRules.d.ts +330 -0
  55. package/lib/structures/rules/ITtscLintPlaywrightRules.js +3 -0
  56. package/lib/structures/rules/ITtscLintPlaywrightRules.js.map +1 -0
  57. package/lib/structures/rules/ITtscLintPromiseRules.d.ts +188 -0
  58. package/lib/structures/rules/ITtscLintPromiseRules.js +3 -0
  59. package/lib/structures/rules/ITtscLintPromiseRules.js.map +1 -0
  60. package/lib/structures/rules/ITtscLintReactPerfRuleOptions.d.ts +18 -0
  61. package/lib/structures/rules/ITtscLintReactPerfRuleOptions.js +8 -0
  62. package/lib/structures/rules/ITtscLintReactPerfRuleOptions.js.map +1 -0
  63. package/lib/structures/rules/ITtscLintReactPerfRules.d.ts +51 -0
  64. package/lib/structures/rules/ITtscLintReactPerfRules.js +3 -0
  65. package/lib/structures/rules/ITtscLintReactPerfRules.js.map +1 -0
  66. package/lib/structures/rules/ITtscLintReactRuleOptions.d.ts +39 -0
  67. package/lib/structures/rules/ITtscLintReactRuleOptions.js +12 -0
  68. package/lib/structures/rules/ITtscLintReactRuleOptions.js.map +1 -0
  69. package/lib/structures/rules/ITtscLintReactRules.d.ts +289 -0
  70. package/lib/structures/rules/ITtscLintReactRules.js +3 -0
  71. package/lib/structures/rules/ITtscLintReactRules.js.map +1 -0
  72. package/lib/structures/rules/ITtscLintRegexpRules.d.ts +190 -0
  73. package/lib/structures/rules/ITtscLintRegexpRules.js +3 -0
  74. package/lib/structures/rules/ITtscLintRegexpRules.js.map +1 -0
  75. package/lib/structures/rules/ITtscLintRuleOptionsMap.d.ts +66 -0
  76. package/lib/structures/rules/ITtscLintRuleOptionsMap.js +3 -0
  77. package/lib/structures/rules/ITtscLintRuleOptionsMap.js.map +1 -0
  78. package/lib/structures/rules/ITtscLintRules.d.ts +55 -0
  79. package/lib/structures/{TtscLintRule.js → rules/ITtscLintRules.js} +1 -1
  80. package/lib/structures/rules/ITtscLintRules.js.map +1 -0
  81. package/lib/structures/rules/ITtscLintSecurityRules.d.ts +148 -0
  82. package/lib/structures/rules/ITtscLintSecurityRules.js +3 -0
  83. package/lib/structures/rules/ITtscLintSecurityRules.js.map +1 -0
  84. package/lib/structures/rules/ITtscLintSolidRules.d.ts +181 -0
  85. package/lib/structures/rules/ITtscLintSolidRules.js +3 -0
  86. package/lib/structures/rules/ITtscLintSolidRules.js.map +1 -0
  87. package/lib/structures/rules/ITtscLintStorybookRuleOptions.d.ts +21 -0
  88. package/lib/structures/rules/ITtscLintStorybookRuleOptions.js +9 -0
  89. package/lib/structures/rules/ITtscLintStorybookRuleOptions.js.map +1 -0
  90. package/lib/structures/rules/ITtscLintStorybookRules.d.ts +174 -0
  91. package/lib/structures/rules/ITtscLintStorybookRules.js +3 -0
  92. package/lib/structures/rules/ITtscLintStorybookRules.js.map +1 -0
  93. package/lib/structures/rules/ITtscLintTanstackQueryRules.d.ts +94 -0
  94. package/lib/structures/rules/ITtscLintTanstackQueryRules.js +3 -0
  95. package/lib/structures/rules/ITtscLintTanstackQueryRules.js.map +1 -0
  96. package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.d.ts +22 -0
  97. package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.js +10 -0
  98. package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.js.map +1 -0
  99. package/lib/structures/rules/ITtscLintTestingLibraryRules.d.ts +310 -0
  100. package/lib/structures/rules/ITtscLintTestingLibraryRules.js +3 -0
  101. package/lib/structures/rules/ITtscLintTestingLibraryRules.js.map +1 -0
  102. package/lib/structures/rules/ITtscLintTypeScriptRules.d.ts +1132 -0
  103. package/lib/structures/rules/ITtscLintTypeScriptRules.js +3 -0
  104. package/lib/structures/rules/ITtscLintTypeScriptRules.js.map +1 -0
  105. package/lib/structures/rules/ITtscLintUnicornRules.d.ts +997 -0
  106. package/lib/structures/rules/ITtscLintUnicornRules.js +3 -0
  107. package/lib/structures/rules/ITtscLintUnicornRules.js.map +1 -0
  108. package/lib/structures/rules/ITtscLintVitestRules.d.ts +141 -0
  109. package/lib/structures/rules/ITtscLintVitestRules.js +3 -0
  110. package/lib/structures/rules/ITtscLintVitestRules.js.map +1 -0
  111. package/lib/structures/rules/index.d.ts +31 -0
  112. package/lib/structures/rules/index.js +48 -0
  113. package/lib/structures/rules/index.js.map +1 -0
  114. package/linthost/ast_helpers.go +30 -5
  115. package/linthost/compile.go +33 -2
  116. package/linthost/config.go +48 -17
  117. package/linthost/config_format.go +9 -9
  118. package/linthost/directives.go +67 -25
  119. package/linthost/dispatch.go +14 -3
  120. package/linthost/engine.go +160 -40
  121. package/linthost/fix.go +2 -2
  122. package/linthost/flags_gen.go +17 -15
  123. package/linthost/host.go +40 -3
  124. package/linthost/lsp.go +747 -0
  125. package/linthost/print_dispatch.go +2 -2
  126. package/linthost/print_nodes_function.go +2 -2
  127. package/linthost/print_nodes_object.go +1 -1
  128. package/linthost/rule_names.go +14 -0
  129. package/linthost/rules_arrays.go +2 -2
  130. package/linthost/rules_boundaries.go +532 -0
  131. package/linthost/rules_camelcase.go +133 -0
  132. package/linthost/rules_complexity.go +94 -0
  133. package/linthost/rules_consistent_return.go +130 -0
  134. package/linthost/rules_console.go +1 -1
  135. package/linthost/rules_core_extra.go +739 -0
  136. package/linthost/rules_curly.go +70 -0
  137. package/linthost/rules_cypress.go +608 -0
  138. package/linthost/rules_debugger.go +2 -2
  139. package/linthost/rules_default_case.go +39 -0
  140. package/linthost/rules_default_case_last.go +46 -0
  141. package/linthost/rules_dupes.go +3 -3
  142. package/linthost/rules_empty.go +3 -3
  143. package/linthost/rules_escape.go +44 -24
  144. package/linthost/rules_eval.go +2 -2
  145. package/linthost/rules_finally.go +2 -2
  146. package/linthost/rules_format_jsdoc.go +1 -1
  147. package/linthost/rules_format_print_width.go +9 -9
  148. package/linthost/rules_format_quotes.go +1 -1
  149. package/linthost/rules_format_semi.go +1 -1
  150. package/linthost/rules_format_sort_imports.go +1 -1
  151. package/linthost/rules_format_trailing_comma.go +1 -1
  152. package/linthost/rules_functional.go +967 -0
  153. package/linthost/rules_gap.go +24 -45
  154. package/linthost/rules_grouped_accessor_pairs.go +87 -0
  155. package/linthost/rules_guard_for_in.go +198 -0
  156. package/linthost/rules_id_length.go +77 -0
  157. package/linthost/rules_imports.go +70 -2
  158. package/linthost/rules_init_declarations.go +53 -0
  159. package/linthost/rules_jest.go +618 -0
  160. package/linthost/rules_jsdoc.go +502 -0
  161. package/linthost/rules_jsx_a11y.go +1264 -0
  162. package/linthost/rules_logic.go +12 -12
  163. package/linthost/rules_loops.go +1 -1
  164. package/linthost/rules_max_classes_per_file.go +58 -0
  165. package/linthost/rules_max_depth.go +83 -0
  166. package/linthost/rules_max_lines.go +101 -0
  167. package/linthost/rules_max_lines_per_function.go +57 -0
  168. package/linthost/rules_max_nested_callbacks.go +61 -0
  169. package/linthost/rules_max_params.go +49 -0
  170. package/linthost/rules_max_statements.go +59 -0
  171. package/linthost/rules_misc.go +1 -1
  172. package/linthost/rules_nextjs.go +697 -0
  173. package/linthost/rules_no_else_return.go +75 -0
  174. package/linthost/rules_no_empty_named_blocks.go +91 -0
  175. package/linthost/rules_no_extend_native.go +51 -0
  176. package/linthost/rules_no_import_assign.go +140 -0
  177. package/linthost/rules_no_invalid_this.go +52 -0
  178. package/linthost/rules_no_loop_func.go +85 -0
  179. package/linthost/rules_no_magic_numbers.go +123 -0
  180. package/linthost/rules_no_mixed_operators.go +80 -0
  181. package/linthost/rules_no_param_reassign.go +98 -0
  182. package/linthost/rules_no_redeclare.go +270 -0
  183. package/linthost/rules_no_restricted_imports.go +105 -0
  184. package/linthost/rules_no_restricted_syntax.go +49 -0
  185. package/linthost/rules_no_shadow.go +147 -0
  186. package/linthost/rules_no_unreachable.go +77 -0
  187. package/linthost/rules_no_useless_assignment.go +120 -0
  188. package/linthost/rules_no_useless_constructor.go +245 -0
  189. package/linthost/rules_no_useless_return.go +51 -0
  190. package/linthost/rules_params.go +1 -1
  191. package/linthost/rules_playwright.go +788 -0
  192. package/linthost/rules_prefer_arrow_callback.go +124 -0
  193. package/linthost/rules_prefer_destructuring.go +98 -0
  194. package/linthost/rules_prefer_named_capture_group.go +129 -0
  195. package/linthost/rules_prefer_rest_params.go +94 -0
  196. package/linthost/rules_problems.go +41 -30
  197. package/linthost/rules_promise.go +1128 -73
  198. package/linthost/rules_protos.go +2 -2
  199. package/linthost/rules_react.go +773 -0
  200. package/linthost/rules_react_extras.go +227 -0
  201. package/linthost/rules_react_hooks.go +848 -0
  202. package/linthost/rules_react_perf.go +293 -0
  203. package/linthost/rules_react_refresh.go +583 -0
  204. package/linthost/rules_regexp.go +410 -0
  205. package/linthost/rules_security.go +830 -0
  206. package/linthost/rules_self.go +2 -2
  207. package/linthost/rules_solid.go +1073 -0
  208. package/linthost/rules_sort_imports.go +69 -0
  209. package/linthost/rules_sort_keys.go +134 -0
  210. package/linthost/rules_storybook.go +1176 -0
  211. package/linthost/rules_strings.go +4 -4
  212. package/linthost/rules_suggestions.go +38 -38
  213. package/linthost/rules_tanstack_query.go +844 -0
  214. package/linthost/rules_testing_library.go +1204 -0
  215. package/linthost/rules_throw.go +1 -1
  216. package/linthost/rules_ts.go +19 -19
  217. package/linthost/rules_ts_async.go +399 -0
  218. package/linthost/rules_ts_class_literal_property_style.go +115 -0
  219. package/linthost/rules_ts_consistent_type_exports.go +256 -0
  220. package/linthost/rules_ts_explicit_function_return_type.go +67 -0
  221. package/linthost/rules_ts_extra.go +155 -36
  222. package/linthost/rules_ts_no_base_to_string.go +218 -0
  223. package/linthost/rules_ts_no_confusing_void.go +72 -0
  224. package/linthost/rules_ts_no_deprecated.go +195 -0
  225. package/linthost/rules_ts_no_for_in_array.go +84 -0
  226. package/linthost/rules_ts_no_magic_numbers.go +124 -0
  227. package/linthost/rules_ts_no_meaningless_void_operator.go +84 -0
  228. package/linthost/rules_ts_no_misused_spread.go +104 -0
  229. package/linthost/rules_ts_no_redundant_type_constituents.go +113 -0
  230. package/linthost/rules_ts_no_restricted_types.go +62 -0
  231. package/linthost/rules_ts_no_unnecessary_boolean_literal_compare.go +129 -0
  232. package/linthost/rules_ts_no_unnecessary_condition.go +250 -0
  233. package/linthost/rules_ts_no_unnecessary_qualifier.go +118 -0
  234. package/linthost/rules_ts_no_unnecessary_template_expression.go +178 -0
  235. package/linthost/rules_ts_no_unnecessary_type_arguments.go +234 -0
  236. package/linthost/rules_ts_no_unnecessary_type_assertion.go +157 -0
  237. package/linthost/rules_ts_no_unsafe_argument.go +82 -0
  238. package/linthost/rules_ts_no_unsafe_assignment.go +102 -0
  239. package/linthost/rules_ts_no_unsafe_call.go +82 -0
  240. package/linthost/rules_ts_no_unsafe_enum_comparison.go +235 -0
  241. package/linthost/rules_ts_no_unsafe_member_access.go +58 -0
  242. package/linthost/rules_ts_no_unsafe_return.go +126 -0
  243. package/linthost/rules_ts_no_unsafe_unary_minus.go +81 -0
  244. package/linthost/rules_ts_no_useless_constructor.go +52 -0
  245. package/linthost/rules_ts_non_nullable_type_assertion_style.go +108 -0
  246. package/linthost/rules_ts_parameter_properties.go +38 -0
  247. package/linthost/rules_ts_prefer_find.go +178 -0
  248. package/linthost/rules_ts_prefer_includes.go +255 -0
  249. package/linthost/rules_ts_prefer_nullish_coalescing.go +104 -0
  250. package/linthost/rules_ts_prefer_optional_chain.go +228 -0
  251. package/linthost/rules_ts_prefer_promise_reject_errors.go +176 -0
  252. package/linthost/rules_ts_prefer_readonly.go +73 -0
  253. package/linthost/rules_ts_prefer_reduce_type_parameter.go +116 -0
  254. package/linthost/rules_ts_prefer_regexp_exec.go +122 -0
  255. package/linthost/rules_ts_prefer_return_this_type.go +135 -0
  256. package/linthost/rules_ts_prefer_string_starts_ends_with.go +360 -0
  257. package/linthost/rules_ts_promise_function_async.go +77 -0
  258. package/linthost/rules_ts_related_getter_setter_pairs.go +113 -0
  259. package/linthost/rules_ts_require_array_sort_compare.go +96 -0
  260. package/linthost/rules_ts_restrict_plus_operands.go +127 -0
  261. package/linthost/rules_ts_restrict_template_expressions.go +95 -0
  262. package/linthost/rules_ts_simple.go +387 -0
  263. package/linthost/rules_ts_sort_type_constituents.go +144 -0
  264. package/linthost/rules_ts_strict_boolean_expressions.go +157 -0
  265. package/linthost/rules_ts_switch_exhaustiveness_check.go +147 -0
  266. package/linthost/rules_ts_unbound_method.go +126 -0
  267. package/linthost/rules_tsdoc.go +136 -0
  268. package/linthost/rules_unicorn_better_regex.go +27 -0
  269. package/linthost/rules_unicorn_catch_error_name.go +46 -0
  270. package/linthost/rules_unicorn_consistent_assert.go +47 -0
  271. package/linthost/rules_unicorn_consistent_date_clone.go +54 -0
  272. package/linthost/rules_unicorn_consistent_destructuring.go +25 -0
  273. package/linthost/rules_unicorn_consistent_empty_array_spread.go +62 -0
  274. package/linthost/rules_unicorn_consistent_existence_index_check.go +80 -0
  275. package/linthost/rules_unicorn_consistent_function_scoping.go +25 -0
  276. package/linthost/rules_unicorn_consistent_template_literal_escape.go +25 -0
  277. package/linthost/rules_unicorn_custom_error_definition.go +138 -0
  278. package/linthost/rules_unicorn_empty_brace_spaces.go +73 -0
  279. package/linthost/rules_unicorn_error_message.go +64 -0
  280. package/linthost/rules_unicorn_escape_case.go +51 -0
  281. package/linthost/rules_unicorn_expiring_todo_comments.go +78 -0
  282. package/linthost/rules_unicorn_explicit_length_check.go +88 -0
  283. package/linthost/rules_unicorn_filename_case.go +29 -0
  284. package/linthost/rules_unicorn_import_style.go +28 -0
  285. package/linthost/rules_unicorn_isolated_functions.go +29 -0
  286. package/linthost/rules_unicorn_new_for_builtins.go +87 -0
  287. package/linthost/rules_unicorn_no_abusive_eslint_disable.go +63 -0
  288. package/linthost/rules_unicorn_no_accessor_recursion.go +115 -0
  289. package/linthost/rules_unicorn_no_anonymous_default_export.go +74 -0
  290. package/linthost/rules_unicorn_no_array_callback_reference.go +65 -0
  291. package/linthost/rules_unicorn_no_array_for_each.go +40 -0
  292. package/linthost/rules_unicorn_no_array_method_this_argument.go +61 -0
  293. package/linthost/rules_unicorn_no_array_reduce.go +41 -0
  294. package/linthost/rules_unicorn_no_array_reverse.go +44 -0
  295. package/linthost/rules_unicorn_no_array_sort.go +43 -0
  296. package/linthost/rules_unicorn_no_await_expression_member.go +40 -0
  297. package/linthost/rules_unicorn_no_await_in_promise_methods.go +69 -0
  298. package/linthost/rules_unicorn_no_console_spaces.go +61 -0
  299. package/linthost/rules_unicorn_no_document_cookie.go +41 -0
  300. package/linthost/rules_unicorn_no_empty_file.go +44 -0
  301. package/linthost/rules_unicorn_no_for_loop.go +102 -0
  302. package/linthost/rules_unicorn_no_hex_escape.go +42 -0
  303. package/linthost/rules_unicorn_no_immediate_mutation.go +90 -0
  304. package/linthost/rules_unicorn_no_instanceof_builtins.go +66 -0
  305. package/linthost/rules_unicorn_no_invalid_fetch_options.go +79 -0
  306. package/linthost/rules_unicorn_no_invalid_remove_event_listener.go +51 -0
  307. package/linthost/rules_unicorn_no_keyword_prefix.go +101 -0
  308. package/linthost/rules_unicorn_no_lonely_if.go +44 -0
  309. package/linthost/rules_unicorn_no_magic_array_flat_depth.go +51 -0
  310. package/linthost/rules_unicorn_no_named_default.go +54 -0
  311. package/linthost/rules_unicorn_no_negated_condition.go +85 -0
  312. package/linthost/rules_unicorn_no_negation_in_equality_check.go +50 -0
  313. package/linthost/rules_unicorn_no_nested_ternary.go +43 -0
  314. package/linthost/rules_unicorn_no_new_array.go +30 -0
  315. package/linthost/rules_unicorn_no_new_buffer.go +31 -0
  316. package/linthost/rules_unicorn_no_null.go +24 -0
  317. package/linthost/rules_unicorn_no_object_as_default_parameter.go +48 -0
  318. package/linthost/rules_unicorn_no_process_exit.go +43 -0
  319. package/linthost/rules_unicorn_no_single_promise_in_promise_methods.go +59 -0
  320. package/linthost/rules_unicorn_no_static_only_class.go +56 -0
  321. package/linthost/rules_unicorn_no_thenable.go +74 -0
  322. package/linthost/rules_unicorn_no_this_assignment.go +35 -0
  323. package/linthost/rules_unicorn_no_typeof_undefined.go +58 -0
  324. package/linthost/rules_unicorn_no_unnecessary_array_flat_depth.go +49 -0
  325. package/linthost/rules_unicorn_no_unnecessary_array_splice_count.go +70 -0
  326. package/linthost/rules_unicorn_no_unnecessary_await.go +51 -0
  327. package/linthost/rules_unicorn_no_unnecessary_polyfills.go +32 -0
  328. package/linthost/rules_unicorn_no_unnecessary_slice_end.go +48 -0
  329. package/linthost/rules_unicorn_no_unreadable_array_destructuring.go +115 -0
  330. package/linthost/rules_unicorn_no_unreadable_iife.go +50 -0
  331. package/linthost/rules_unicorn_no_unused_properties.go +30 -0
  332. package/linthost/rules_unicorn_no_useless_collection_argument.go +63 -0
  333. package/linthost/rules_unicorn_no_useless_error_capture_stack_trace.go +46 -0
  334. package/linthost/rules_unicorn_no_useless_fallback_in_spread.go +81 -0
  335. package/linthost/rules_unicorn_no_useless_iterator_to_array.go +72 -0
  336. package/linthost/rules_unicorn_no_useless_length_check.go +144 -0
  337. package/linthost/rules_unicorn_no_useless_promise_resolve_reject.go +81 -0
  338. package/linthost/rules_unicorn_no_useless_spread.go +67 -0
  339. package/linthost/rules_unicorn_no_useless_switch_case.go +55 -0
  340. package/linthost/rules_unicorn_no_useless_undefined.go +55 -0
  341. package/linthost/rules_unicorn_no_zero_fractions.go +52 -0
  342. package/linthost/rules_unicorn_number_literal_case.go +69 -0
  343. package/linthost/rules_unicorn_numeric_separators_style.go +75 -0
  344. package/linthost/rules_unicorn_prefer_add_event_listener.go +66 -0
  345. package/linthost/rules_unicorn_prefer_array_find.go +51 -0
  346. package/linthost/rules_unicorn_prefer_array_flat.go +52 -0
  347. package/linthost/rules_unicorn_prefer_array_flat_map.go +63 -0
  348. package/linthost/rules_unicorn_prefer_array_index_of.go +147 -0
  349. package/linthost/rules_unicorn_prefer_array_some.go +67 -0
  350. package/linthost/rules_unicorn_prefer_at.go +77 -0
  351. package/linthost/rules_unicorn_prefer_bigint_literals.go +77 -0
  352. package/linthost/rules_unicorn_prefer_blob_reading_methods.go +44 -0
  353. package/linthost/rules_unicorn_prefer_class_fields.go +93 -0
  354. package/linthost/rules_unicorn_prefer_classlist_toggle.go +120 -0
  355. package/linthost/rules_unicorn_prefer_code_point.go +49 -0
  356. package/linthost/rules_unicorn_prefer_date_now.go +78 -0
  357. package/linthost/rules_unicorn_prefer_default_parameters.go +144 -0
  358. package/linthost/rules_unicorn_prefer_dom_node_append.go +40 -0
  359. package/linthost/rules_unicorn_prefer_dom_node_dataset.go +55 -0
  360. package/linthost/rules_unicorn_prefer_dom_node_remove.go +41 -0
  361. package/linthost/rules_unicorn_prefer_dom_node_text_content.go +37 -0
  362. package/linthost/rules_unicorn_prefer_event_target.go +36 -0
  363. package/linthost/rules_unicorn_prefer_export_from.go +129 -0
  364. package/linthost/rules_unicorn_prefer_global_this.go +127 -0
  365. package/linthost/rules_unicorn_prefer_import_meta_properties.go +66 -0
  366. package/linthost/rules_unicorn_prefer_includes.go +149 -0
  367. package/linthost/rules_unicorn_prefer_json_parse_buffer.go +65 -0
  368. package/linthost/rules_unicorn_prefer_keyboard_event_key.go +38 -0
  369. package/linthost/rules_unicorn_prefer_logical_operator_over_ternary.go +48 -0
  370. package/linthost/rules_unicorn_prefer_math_min_max.go +60 -0
  371. package/linthost/rules_unicorn_prefer_math_trunc.go +62 -0
  372. package/linthost/rules_unicorn_prefer_modern_dom_apis.go +47 -0
  373. package/linthost/rules_unicorn_prefer_modern_math_apis.go +70 -0
  374. package/linthost/rules_unicorn_prefer_module.go +50 -0
  375. package/linthost/rules_unicorn_prefer_native_coercion_functions.go +114 -0
  376. package/linthost/rules_unicorn_prefer_negative_index.go +74 -0
  377. package/linthost/rules_unicorn_prefer_node_protocol.go +122 -0
  378. package/linthost/rules_unicorn_prefer_number_properties.go +88 -0
  379. package/linthost/rules_unicorn_prefer_object_from_entries.go +55 -0
  380. package/linthost/rules_unicorn_prefer_optional_catch_binding.go +62 -0
  381. package/linthost/rules_unicorn_prefer_prototype_methods.go +54 -0
  382. package/linthost/rules_unicorn_prefer_query_selector.go +56 -0
  383. package/linthost/rules_unicorn_prefer_reflect_apply.go +36 -0
  384. package/linthost/rules_unicorn_prefer_regexp_test_rule.go +80 -0
  385. package/linthost/rules_unicorn_prefer_response_static_json.go +53 -0
  386. package/linthost/rules_unicorn_prefer_set_has.go +42 -0
  387. package/linthost/rules_unicorn_prefer_set_size.go +48 -0
  388. package/linthost/rules_unicorn_prefer_simple_condition_first.go +34 -0
  389. package/linthost/rules_unicorn_prefer_single_call.go +96 -0
  390. package/linthost/rules_unicorn_prefer_spread.go +51 -0
  391. package/linthost/rules_unicorn_prefer_string_raw.go +43 -0
  392. package/linthost/rules_unicorn_prefer_string_replace_all.go +95 -0
  393. package/linthost/rules_unicorn_prefer_string_slice.go +43 -0
  394. package/linthost/rules_unicorn_prefer_string_starts_ends_with.go +148 -0
  395. package/linthost/rules_unicorn_prefer_string_trim_start_end.go +48 -0
  396. package/linthost/rules_unicorn_prefer_structured_clone.go +71 -0
  397. package/linthost/rules_unicorn_prefer_switch.go +103 -0
  398. package/linthost/rules_unicorn_prefer_ternary.go +71 -0
  399. package/linthost/rules_unicorn_prefer_top_level_await.go +72 -0
  400. package/linthost/rules_unicorn_prefer_type_error.go +127 -0
  401. package/linthost/rules_unicorn_prevent_abbreviations.go +127 -0
  402. package/linthost/rules_unicorn_relative_url_style.go +49 -0
  403. package/linthost/rules_unicorn_require_array_join_separator.go +45 -0
  404. package/linthost/rules_unicorn_require_module_attributes.go +54 -0
  405. package/linthost/rules_unicorn_require_module_specifiers.go +55 -0
  406. package/linthost/rules_unicorn_require_number_to_fixed_digits_argument.go +43 -0
  407. package/linthost/rules_unicorn_require_post_message_target_origin.go +44 -0
  408. package/linthost/rules_unicorn_string_content.go +27 -0
  409. package/linthost/rules_unicorn_switch_case_braces.go +42 -0
  410. package/linthost/rules_unicorn_switch_case_break_position.go +31 -0
  411. package/linthost/rules_unicorn_template_indent.go +28 -0
  412. package/linthost/rules_unicorn_text_encoding_identifier_case.go +72 -0
  413. package/linthost/rules_unicorn_throw_new_error.go +61 -0
  414. package/linthost/rules_var.go +10 -4
  415. package/linthost/rules_vitest.go +568 -0
  416. package/package.json +3 -3
  417. package/plugin/main.go +49 -3
  418. package/rule/astutil/astutil.go +10 -3
  419. package/rule/rule.go +12 -10
  420. package/src/defaultFormat.ts +11 -8
  421. package/src/index.ts +65 -43
  422. package/src/structures/ITtscLintConfig.ts +12 -6
  423. package/src/structures/{ITtscLintFormatConfig.ts → ITtscLintFormat.ts} +2 -2
  424. package/src/structures/TtscLintRuleSetting.ts +55 -0
  425. package/src/structures/index.ts +3 -4
  426. package/src/structures/rules/ITtscLintBoundariesRuleOptions.ts +128 -0
  427. package/src/structures/rules/ITtscLintBoundariesRules.ts +95 -0
  428. package/src/structures/rules/ITtscLintContributorRules.ts +21 -0
  429. package/src/structures/rules/ITtscLintCoreRules.ts +1406 -0
  430. package/src/structures/rules/ITtscLintCypressRuleOptions.ts +18 -0
  431. package/src/structures/rules/ITtscLintCypressRules.ts +145 -0
  432. package/src/structures/rules/ITtscLintFunctionalRuleOptions.ts +213 -0
  433. package/src/structures/rules/ITtscLintFunctionalRules.ts +202 -0
  434. package/src/structures/rules/ITtscLintJestRules.ts +220 -0
  435. package/src/structures/rules/ITtscLintJsdocRules.ts +153 -0
  436. package/src/structures/rules/ITtscLintJsxA11yRules.ts +339 -0
  437. package/src/structures/rules/ITtscLintNextjsRules.ts +206 -0
  438. package/src/structures/rules/ITtscLintPlaywrightRules.ts +361 -0
  439. package/src/structures/rules/ITtscLintPromiseRules.ts +205 -0
  440. package/src/structures/rules/ITtscLintReactPerfRuleOptions.ts +19 -0
  441. package/src/structures/rules/ITtscLintReactPerfRules.ts +55 -0
  442. package/src/structures/rules/ITtscLintReactRuleOptions.ts +43 -0
  443. package/src/structures/rules/ITtscLintReactRules.ts +321 -0
  444. package/src/structures/rules/ITtscLintRegexpRules.ts +212 -0
  445. package/src/structures/rules/ITtscLintRuleOptionsMap.ts +89 -0
  446. package/src/structures/rules/ITtscLintRules.ts +77 -0
  447. package/src/structures/rules/ITtscLintSecurityRules.ts +162 -0
  448. package/src/structures/rules/ITtscLintSolidRules.ts +202 -0
  449. package/src/structures/rules/ITtscLintStorybookRuleOptions.ts +23 -0
  450. package/src/structures/rules/ITtscLintStorybookRules.ts +193 -0
  451. package/src/structures/rules/ITtscLintTanstackQueryRules.ts +102 -0
  452. package/src/structures/rules/ITtscLintTestingLibraryRuleOptions.ts +24 -0
  453. package/src/structures/rules/ITtscLintTestingLibraryRules.ts +342 -0
  454. package/src/structures/rules/ITtscLintTypeScriptRules.ts +1230 -0
  455. package/src/structures/rules/ITtscLintUnicornRules.ts +1143 -0
  456. package/src/structures/rules/ITtscLintVitestRules.ts +154 -0
  457. package/src/structures/rules/index.ts +31 -0
  458. package/lib/structures/ITtscLintFormatConfig.js.map +0 -1
  459. package/lib/structures/TtscLintRule.d.ts +0 -17
  460. package/lib/structures/TtscLintRule.js.map +0 -1
  461. package/lib/structures/TtscLintRuleMap.d.ts +0 -46
  462. package/lib/structures/TtscLintRuleMap.js.map +0 -1
  463. package/lib/structures/TtscLintRuleOptions.d.ts +0 -137
  464. package/lib/structures/TtscLintRuleOptions.js.map +0 -1
  465. package/src/structures/TtscLintRule.ts +0 -160
  466. package/src/structures/TtscLintRuleMap.ts +0 -55
  467. 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 format/print-width
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 format/print-width rule consults `covered` to decide whether to
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 format/print-width rule abstains.
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 format/print-width rule abstain.
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. format/print-width mirrors that:
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
+ }
@@ -2,7 +2,7 @@ package linthost
2
2
 
3
3
  import shimast "github.com/microsoft/typescript-go/shim/ast"
4
4
 
5
- // no-sparse-arrays: `[1, , 2]` — the implied undefined slot is almost
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
- // no-array-constructor: forbid `new Array(0)` / `Array(1, 2, 3)` (use
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
+ }