@nadicodeai/ui 12.1.165 → 12.1.167

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 (367) hide show
  1. package/AGENTS.md +8 -9
  2. package/README.md +2 -17
  3. package/dist/components/accordion.d.ts.map +1 -1
  4. package/dist/components/accordion.js +2 -1
  5. package/dist/components/account-menu.d.ts.map +1 -1
  6. package/dist/components/account-menu.js +5 -3
  7. package/dist/components/activity-calendar.d.ts.map +1 -1
  8. package/dist/components/activity-calendar.js +3 -2
  9. package/dist/components/agent-card.js +1 -1
  10. package/dist/components/agent-orb.d.ts.map +1 -1
  11. package/dist/components/agent-orb.js +1 -0
  12. package/dist/components/agent-profile.d.ts.map +1 -1
  13. package/dist/components/agent-profile.js +7 -4
  14. package/dist/components/alert-dialog.d.ts +1 -1
  15. package/dist/components/alert-dialog.d.ts.map +1 -1
  16. package/dist/components/alert-dialog.js +3 -3
  17. package/dist/components/app-mark.js +1 -1
  18. package/dist/components/avatar.js +8 -8
  19. package/dist/components/badge.d.ts +11 -16
  20. package/dist/components/badge.d.ts.map +1 -1
  21. package/dist/components/badge.js +7 -43
  22. package/dist/components/breadcrumb.d.ts.map +1 -1
  23. package/dist/components/breadcrumb.js +3 -2
  24. package/dist/components/button.d.ts +5 -21
  25. package/dist/components/button.d.ts.map +1 -1
  26. package/dist/components/button.js +6 -76
  27. package/dist/components/calendar.d.ts +1 -1
  28. package/dist/components/calendar.d.ts.map +1 -1
  29. package/dist/components/calendar.js +3 -3
  30. package/dist/components/card-row.js +1 -1
  31. package/dist/components/card.d.ts +4 -1
  32. package/dist/components/card.d.ts.map +1 -1
  33. package/dist/components/card.js +3 -2
  34. package/dist/components/catalog-drawer.d.ts.map +1 -1
  35. package/dist/components/catalog-drawer.js +3 -2
  36. package/dist/components/chart-axis.d.ts.map +1 -1
  37. package/dist/components/chart-axis.js +0 -2
  38. package/dist/components/chart-bar-horizontal.d.ts.map +1 -1
  39. package/dist/components/chart-bar-horizontal.js +16 -14
  40. package/dist/components/chart-card.d.ts.map +1 -1
  41. package/dist/components/chart-card.js +0 -1
  42. package/dist/components/chart.d.ts.map +1 -1
  43. package/dist/components/chart.js +18 -32
  44. package/dist/components/checkbox.d.ts +3 -2
  45. package/dist/components/checkbox.d.ts.map +1 -1
  46. package/dist/components/checkbox.js +4 -3
  47. package/dist/components/choicebox.d.ts +5 -5
  48. package/dist/components/choicebox.d.ts.map +1 -1
  49. package/dist/components/choicebox.js +6 -5
  50. package/dist/components/clearable-input.d.ts.map +1 -1
  51. package/dist/components/clearable-input.js +2 -2
  52. package/dist/components/code-block.d.ts.map +1 -1
  53. package/dist/components/code-block.js +4 -2
  54. package/dist/components/collapsible.js +1 -1
  55. package/dist/components/collection-filters.d.ts.map +1 -1
  56. package/dist/components/collection-filters.js +1 -0
  57. package/dist/components/collection-page.js +1 -1
  58. package/dist/components/collection-sort.d.ts.map +1 -1
  59. package/dist/components/collection-sort.js +1 -4
  60. package/dist/components/collection-toolbar.js +1 -1
  61. package/dist/components/combobox.js +4 -4
  62. package/dist/components/command.d.ts.map +1 -1
  63. package/dist/components/command.js +1 -1
  64. package/dist/components/confirm-dialog.js +2 -2
  65. package/dist/components/context-menu.d.ts +1 -1
  66. package/dist/components/context-menu.d.ts.map +1 -1
  67. package/dist/components/copy-button.js +1 -1
  68. package/dist/components/data-table.d.ts +14 -7
  69. package/dist/components/data-table.d.ts.map +1 -1
  70. package/dist/components/data-table.js +24 -15
  71. package/dist/components/dialog.d.ts +1 -1
  72. package/dist/components/dialog.d.ts.map +1 -1
  73. package/dist/components/dialog.js +2 -2
  74. package/dist/components/drawer.d.ts +4 -4
  75. package/dist/components/drawer.d.ts.map +1 -1
  76. package/dist/components/drawer.js +14 -15
  77. package/dist/components/dropdown-menu.d.ts +1 -1
  78. package/dist/components/dropdown-menu.d.ts.map +1 -1
  79. package/dist/components/dropdown-menu.js +9 -5
  80. package/dist/components/empty-art.js +1 -1
  81. package/dist/components/empty-state.js +2 -2
  82. package/dist/components/entry-scene.d.ts.map +1 -1
  83. package/dist/components/entry-scene.js +2 -3
  84. package/dist/components/field.js +3 -3
  85. package/dist/components/file-diff.d.ts.map +1 -1
  86. package/dist/components/file-diff.js +5 -2
  87. package/dist/components/footer.d.ts +1 -1
  88. package/dist/components/footer.d.ts.map +1 -1
  89. package/dist/components/footer.js +3 -3
  90. package/dist/components/form-dialog.d.ts.map +1 -1
  91. package/dist/components/form-dialog.js +2 -1
  92. package/dist/components/form-drawer.d.ts +7 -9
  93. package/dist/components/form-drawer.d.ts.map +1 -1
  94. package/dist/components/form-drawer.js +5 -5
  95. package/dist/components/form.d.ts +26 -0
  96. package/dist/components/form.d.ts.map +1 -0
  97. package/dist/components/form.js +29 -0
  98. package/dist/components/gauge.js +2 -2
  99. package/dist/components/heatmap/calendar-heatmap.d.ts.map +1 -1
  100. package/dist/components/heatmap/calendar-heatmap.js +15 -13
  101. package/dist/components/hive-scene.d.ts.map +1 -1
  102. package/dist/components/hive-scene.js +3 -1
  103. package/dist/components/hover-card.d.ts +1 -1
  104. package/dist/components/hover-card.d.ts.map +1 -1
  105. package/dist/components/hover-card.js +1 -1
  106. package/dist/components/input-group.d.ts +5 -6
  107. package/dist/components/input-group.d.ts.map +1 -1
  108. package/dist/components/input-group.js +8 -11
  109. package/dist/components/input-otp.d.ts.map +1 -1
  110. package/dist/components/input-otp.js +2 -2
  111. package/dist/components/item.d.ts +1 -1
  112. package/dist/components/item.js +2 -2
  113. package/dist/components/kbd.d.ts +6 -9
  114. package/dist/components/kbd.d.ts.map +1 -1
  115. package/dist/components/kbd.js +7 -3
  116. package/dist/components/message-notice.js +1 -1
  117. package/dist/components/middle-truncate.d.ts.map +1 -1
  118. package/dist/components/middle-truncate.js +1 -0
  119. package/dist/components/model-identity.d.ts +4 -4
  120. package/dist/components/model-identity.d.ts.map +1 -1
  121. package/dist/components/model-identity.js +2 -2
  122. package/dist/components/model-mark.d.ts.map +1 -1
  123. package/dist/components/model-mark.js +4 -2
  124. package/dist/components/multi-select.js +2 -2
  125. package/dist/components/native-select.d.ts.map +1 -1
  126. package/dist/components/native-select.js +2 -6
  127. package/dist/components/notice-banner.js +1 -1
  128. package/dist/components/object-page.js +2 -2
  129. package/dist/components/object-workspace.d.ts.map +1 -1
  130. package/dist/components/object-workspace.js +1 -3
  131. package/dist/components/overview-page.d.ts +1 -1
  132. package/dist/components/overview-page.d.ts.map +1 -1
  133. package/dist/components/overview-page.js +2 -1
  134. package/dist/components/page-actions.d.ts.map +1 -1
  135. package/dist/components/page-actions.js +9 -4
  136. package/dist/components/pairing-code.js +1 -1
  137. package/dist/components/pending-label.d.ts.map +1 -1
  138. package/dist/components/pending-label.js +0 -1
  139. package/dist/components/popover.d.ts +1 -1
  140. package/dist/components/popover.d.ts.map +1 -1
  141. package/dist/components/portal-sidebar-frame.d.ts.map +1 -1
  142. package/dist/components/portal-sidebar-frame.js +1 -1
  143. package/dist/components/product-message.d.ts.map +1 -1
  144. package/dist/components/product-message.js +1 -0
  145. package/dist/components/progress-checklist.d.ts.map +1 -1
  146. package/dist/components/progress-checklist.js +2 -2
  147. package/dist/components/progress.d.ts.map +1 -1
  148. package/dist/components/progress.js +5 -4
  149. package/dist/components/radio-group.js +2 -2
  150. package/dist/components/reading-column.js +1 -1
  151. package/dist/components/record-identity.d.ts.map +1 -1
  152. package/dist/components/record-identity.js +2 -5
  153. package/dist/components/record-list.d.ts +5 -4
  154. package/dist/components/record-list.d.ts.map +1 -1
  155. package/dist/components/record-list.js +31 -17
  156. package/dist/components/record-sheet.js +1 -1
  157. package/dist/components/record-time.d.ts.map +1 -1
  158. package/dist/components/record-time.js +2 -1
  159. package/dist/components/resizable.d.ts.map +1 -1
  160. package/dist/components/resizable.js +1 -1
  161. package/dist/components/row-edit-form.d.ts +2 -1
  162. package/dist/components/row-edit-form.d.ts.map +1 -1
  163. package/dist/components/row-edit-form.js +2 -1
  164. package/dist/components/run-timeline.js +1 -1
  165. package/dist/components/scope-switcher.js +1 -1
  166. package/dist/components/segmented-control.js +1 -1
  167. package/dist/components/select.js +1 -1
  168. package/dist/components/settings-facts.js +1 -1
  169. package/dist/components/settings-section.js +1 -1
  170. package/dist/components/sheet.d.ts +1 -1
  171. package/dist/components/sheet.d.ts.map +1 -1
  172. package/dist/components/sheet.js +1 -1
  173. package/dist/components/sidebar.d.ts +2 -2
  174. package/dist/components/sidebar.d.ts.map +1 -1
  175. package/dist/components/sidebar.js +16 -18
  176. package/dist/components/site-menu.d.ts +28 -0
  177. package/dist/components/site-menu.d.ts.map +1 -0
  178. package/dist/components/site-menu.js +23 -0
  179. package/dist/components/slider.d.ts.map +1 -1
  180. package/dist/components/slider.js +2 -1
  181. package/dist/components/snippet.d.ts +2 -0
  182. package/dist/components/snippet.d.ts.map +1 -1
  183. package/dist/components/snippet.js +13 -6
  184. package/dist/components/sonner.d.ts.map +1 -1
  185. package/dist/components/sonner.js +3 -4
  186. package/dist/components/status-badge.d.ts +1 -1
  187. package/dist/components/status-badge.d.ts.map +1 -1
  188. package/dist/components/switch.js +1 -1
  189. package/dist/components/table-card.js +1 -1
  190. package/dist/components/table-layouts.d.ts +24 -9
  191. package/dist/components/table-layouts.d.ts.map +1 -1
  192. package/dist/components/table-layouts.js +27 -10
  193. package/dist/components/table.js +4 -4
  194. package/dist/components/tabs-nav.d.ts +52 -0
  195. package/dist/components/tabs-nav.d.ts.map +1 -0
  196. package/dist/components/tabs-nav.js +95 -0
  197. package/dist/components/tabs.d.ts +2 -56
  198. package/dist/components/tabs.d.ts.map +1 -1
  199. package/dist/components/tabs.js +2 -91
  200. package/dist/components/text-link.d.ts +1 -2
  201. package/dist/components/text-link.d.ts.map +1 -1
  202. package/dist/components/text-link.js +1 -2
  203. package/dist/components/textarea.d.ts +5 -2
  204. package/dist/components/textarea.d.ts.map +1 -1
  205. package/dist/components/textarea.js +12 -4
  206. package/dist/components/toast.d.ts +2 -0
  207. package/dist/components/toast.d.ts.map +1 -1
  208. package/dist/components/toast.js +4 -0
  209. package/dist/components/toggle-group.d.ts +3 -1
  210. package/dist/components/toggle-group.d.ts.map +1 -1
  211. package/dist/components/toggle-group.js +3 -6
  212. package/dist/components/toggle.js +1 -1
  213. package/dist/components/tooltip.d.ts +12 -12
  214. package/dist/components/tooltip.d.ts.map +1 -1
  215. package/dist/components/tooltip.js +9 -9
  216. package/dist/components/trend-badge.js +2 -2
  217. package/dist/components/update-card.js +1 -1
  218. package/dist/components/usage-meter.d.ts +1 -1
  219. package/dist/components/usage-meter.d.ts.map +1 -1
  220. package/dist/components/usage-meter.js +9 -7
  221. package/dist/components/waiting-line.js +1 -1
  222. package/dist/index.d.ts +3 -7
  223. package/dist/index.d.ts.map +1 -1
  224. package/dist/index.js +3 -7
  225. package/dist/internal/agent-orb-motion.d.ts +4 -1
  226. package/dist/internal/agent-orb-motion.d.ts.map +1 -1
  227. package/dist/internal/agent-orb-motion.js +9 -7
  228. package/dist/internal/agent-orb.d.ts +4 -1
  229. package/dist/internal/agent-orb.d.ts.map +1 -1
  230. package/dist/internal/agent-orb.js +7 -1
  231. package/dist/internal/assistant-ui/attachment.d.ts.map +1 -1
  232. package/dist/internal/assistant-ui/attachment.js +15 -15
  233. package/dist/internal/assistant-ui/follow-up-suggestions.js +1 -1
  234. package/dist/internal/assistant-ui/markdown-text.js +26 -25
  235. package/dist/internal/assistant-ui/reasoning.d.ts.map +1 -1
  236. package/dist/internal/assistant-ui/reasoning.js +13 -16
  237. package/dist/internal/assistant-ui/thread.d.ts.map +1 -1
  238. package/dist/internal/assistant-ui/thread.js +22 -16
  239. package/dist/internal/assistant-ui/tool-fallback.d.ts.map +1 -1
  240. package/dist/internal/assistant-ui/tool-fallback.js +29 -21
  241. package/dist/internal/assistant-ui/tool-group.d.ts.map +1 -1
  242. package/dist/internal/assistant-ui/tool-group.js +6 -7
  243. package/dist/internal/assistant-ui/tooltip-icon-button.js +1 -1
  244. package/dist/internal/badge-frame.d.ts +15 -0
  245. package/dist/internal/badge-frame.d.ts.map +1 -0
  246. package/dist/internal/badge-frame.js +44 -0
  247. package/dist/internal/button-classes.d.ts +20 -0
  248. package/dist/internal/button-classes.d.ts.map +1 -0
  249. package/dist/internal/button-classes.js +74 -0
  250. package/dist/internal/catalog-list.d.ts.map +1 -1
  251. package/dist/internal/catalog-list.js +8 -4
  252. package/dist/internal/collection-rail.js +3 -3
  253. package/dist/internal/form-drawer-frame.d.ts +10 -0
  254. package/dist/internal/form-drawer-frame.d.ts.map +1 -0
  255. package/dist/internal/form-drawer-frame.js +9 -0
  256. package/dist/internal/form-submit.d.ts +2 -1
  257. package/dist/internal/form-submit.d.ts.map +1 -1
  258. package/dist/internal/settings-save.d.ts.map +1 -1
  259. package/dist/internal/settings-save.js +4 -2
  260. package/dist/internal/status-mark.d.ts.map +1 -1
  261. package/dist/internal/status-mark.js +4 -1
  262. package/dist/internal/tab-row.d.ts +10 -0
  263. package/dist/internal/tab-row.d.ts.map +1 -0
  264. package/dist/internal/tab-row.js +2 -0
  265. package/dist/internal/table-compact-line.d.ts +1 -1
  266. package/dist/internal/table-compact-line.d.ts.map +1 -1
  267. package/dist/internal/table-compact-line.js +1 -1
  268. package/dist/internal/tooltip-content-frame.d.ts +14 -0
  269. package/dist/internal/tooltip-content-frame.d.ts.map +1 -0
  270. package/dist/internal/tooltip-content-frame.js +11 -0
  271. package/dist/lib/css-variables.d.ts +8 -0
  272. package/dist/lib/css-variables.d.ts.map +1 -0
  273. package/dist/lib/css-variables.js +4 -0
  274. package/dist/lib/merge-tokens.generated.js +1 -1
  275. package/dist/lib/use-copy-to-clipboard.d.ts.map +1 -1
  276. package/dist/lib/use-copy-to-clipboard.js +1 -2
  277. package/dist/showcase/samples.js +1 -1
  278. package/dist/showcase/specimens/choices.d.ts.map +1 -1
  279. package/dist/showcase/specimens/choices.js +3 -2
  280. package/dist/showcase/specimens/compositions.d.ts.map +1 -1
  281. package/dist/showcase/specimens/compositions.js +7 -5
  282. package/dist/showcase/specimens/data.d.ts.map +1 -1
  283. package/dist/showcase/specimens/data.js +1 -1
  284. package/dist/showcase/specimens/feedback.d.ts.map +1 -1
  285. package/dist/showcase/specimens/feedback.js +1 -2
  286. package/dist/showcase/specimens/index.d.ts +2 -0
  287. package/dist/showcase/specimens/index.d.ts.map +1 -1
  288. package/dist/showcase/specimens/inputs.d.ts +1 -0
  289. package/dist/showcase/specimens/inputs.d.ts.map +1 -1
  290. package/dist/showcase/specimens/inputs.js +5 -2
  291. package/dist/showcase/specimens/menus.d.ts +1 -0
  292. package/dist/showcase/specimens/menus.d.ts.map +1 -1
  293. package/dist/showcase/specimens/menus.js +7 -2
  294. package/dist/showcase/specimens/navigation.d.ts.map +1 -1
  295. package/dist/showcase/specimens/navigation.js +6 -5
  296. package/dist/showcase/specimens/status.d.ts.map +1 -1
  297. package/dist/showcase/specimens/status.js +4 -4
  298. package/dist/showcase/usage.generated.d.ts +1 -1
  299. package/dist/showcase/usage.generated.d.ts.map +1 -1
  300. package/dist/showcase/usage.generated.js +40 -18
  301. package/dist/standalone/index.js +2 -2
  302. package/dist/standalone/orb-page.js +10 -8
  303. package/dist/styles/components.css +14 -1
  304. package/package.json +32 -33
  305. package/dist/eslint/index.js +0 -224
  306. package/dist/eslint/rules/badge-is-static-label.js +0 -93
  307. package/dist/eslint/rules/button-icon-slot.js +0 -102
  308. package/dist/eslint/rules/button-link-for-navigation.js +0 -146
  309. package/dist/eslint/rules/button-no-aria-label-with-text.js +0 -75
  310. package/dist/eslint/rules/button-type-roles-only-in-buttons.js +0 -83
  311. package/dist/eslint/rules/choice-control-has-a-name.js +0 -98
  312. package/dist/eslint/rules/choice-group-in-fieldset.js +0 -86
  313. package/dist/eslint/rules/command-shortcut-single-owner.js +0 -118
  314. package/dist/eslint/rules/confirm-dialog-words.js +0 -63
  315. package/dist/eslint/rules/data-table-one-unsized-column.js +0 -96
  316. package/dist/eslint/rules/destructive-action-placement.js +0 -69
  317. package/dist/eslint/rules/disabled-choice-says-why.js +0 -71
  318. package/dist/eslint/rules/disabled-control-appearance.js +0 -75
  319. package/dist/eslint/rules/ellipsis-opens-a-dialog.js +0 -110
  320. package/dist/eslint/rules/empty-state-owner.js +0 -145
  321. package/dist/eslint/rules/input-group-owners.js +0 -155
  322. package/dist/eslint/rules/jsx-class-utility.js +0 -200
  323. package/dist/eslint/rules/kbd-children-no-modifier-text.js +0 -128
  324. package/dist/eslint/rules/literal-text.js +0 -41
  325. package/dist/eslint/rules/menu-owner.js +0 -75
  326. package/dist/eslint/rules/middle-truncate-placement.js +0 -69
  327. package/dist/eslint/rules/no-app-feature-component.js +0 -100
  328. package/dist/eslint/rules/no-bare-button-label.js +0 -55
  329. package/dist/eslint/rules/no-choice-control-wrapper.js +0 -97
  330. package/dist/eslint/rules/no-comment.js +0 -77
  331. package/dist/eslint/rules/no-control-in-read-only-surface.js +0 -106
  332. package/dist/eslint/rules/no-decorative-icon.js +0 -164
  333. package/dist/eslint/rules/no-deprecated-zod-api.js +0 -215
  334. package/dist/eslint/rules/no-global-patch.js +0 -115
  335. package/dist/eslint/rules/no-hand-built-busy.js +0 -104
  336. package/dist/eslint/rules/no-hand-built-theme-picker.js +0 -144
  337. package/dist/eslint/rules/no-hand-built-tile.js +0 -41
  338. package/dist/eslint/rules/no-hand-formatted-date.js +0 -87
  339. package/dist/eslint/rules/no-hand-stacked-avatars.js +0 -67
  340. package/dist/eslint/rules/no-nested-collapse.js +0 -60
  341. package/dist/eslint/rules/no-package-component-redefinition.js +0 -175
  342. package/dist/eslint/rules/no-search-in-form.js +0 -47
  343. package/dist/eslint/rules/no-shadcn-appearance-override.js +0 -305
  344. package/dist/eslint/rules/no-shell-prompt-in-snippet.js +0 -74
  345. package/dist/eslint/rules/no-stock-error-words.js +0 -56
  346. package/dist/eslint/rules/no-subject-derived-expectation.js +0 -183
  347. package/dist/eslint/rules/no-tooltip-around-labelled-field.js +0 -72
  348. package/dist/eslint/rules/no-weight-class-on-strong-in-type-role.js +0 -57
  349. package/dist/eslint/rules/no-write-in-subscription.js +0 -140
  350. package/dist/eslint/rules/one-submenu-level.js +0 -43
  351. package/dist/eslint/rules/one-toast-per-flow.js +0 -91
  352. package/dist/eslint/rules/option-count.js +0 -167
  353. package/dist/eslint/rules/page-command-link-not-render.js +0 -43
  354. package/dist/eslint/rules/page-composition.js +0 -232
  355. package/dist/eslint/rules/progress-needs-name.js +0 -57
  356. package/dist/eslint/rules/rendered-import.js +0 -121
  357. package/dist/eslint/rules/server-action-discipline.js +0 -233
  358. package/dist/eslint/rules/settings-limit-in-footer.js +0 -94
  359. package/dist/eslint/rules/skeleton-in-region.js +0 -80
  360. package/dist/eslint/rules/sortable-heading-uses-sort.js +0 -79
  361. package/dist/eslint/rules/table-cell-inset-owner.js +0 -107
  362. package/dist/eslint/rules/tabs-selection-is-controlled.js +0 -47
  363. package/dist/eslint/rules/test-files-from-one-definition.js +0 -67
  364. package/dist/eslint/rules/tooltip-only-arrow.js +0 -38
  365. package/dist/eslint/rules/tooltip-trigger-accessible-name.js +0 -114
  366. package/dist/eslint/rules/workspace-declares-imports.js +0 -163
  367. package/dist/eslint/strict-design-system.js +0 -250
@@ -1,128 +0,0 @@
1
- /*
2
- * A shortcut hint is `<Kbd meta>K</Kbd>`: the modifier is a flag, the child is
3
- * one key from `KBD_KEYS`, and the component draws the person's platform. A
4
- * hand-written ⌘ or "Ctrl" is right on one platform and wrong on the others.
5
- *
6
- * Standard tool checked first: `no-restricted-syntax` can match a `Kbd` child
7
- * by text, but not whether this `Kbd` is the package's (an import binding, so a
8
- * renamed or local `Kbd` is judged correctly), and it would need the key list
9
- * spelled into a regex. The list is read from the package's own `KBD_KEYS`
10
- * array at lint time, so a key added there changes this rule's answer with no
11
- * edit here.
12
- */
13
- import { readFileSync } from "node:fs";
14
- import { createRequire } from "node:module";
15
- import { fileURLToPath } from "node:url";
16
-
17
- import { packageModules, partOf, renderedImports } from "./rendered-import.js";
18
-
19
- const KBD_MODULE = "@nadicodeai/ui/components/kbd";
20
- const OWNER_FILE = "packages/ui/src/components/kbd.tsx";
21
-
22
- const KBD = new Map([["Kbd", packageModules("kbd").map((from) => ({ from, part: "Kbd" }))]]);
23
-
24
- /*
25
- * TypeScript is loaded when this rule first runs, not when the plugin loads:
26
- * the plugin ships inside `@nadicodeai/ui`, which does not depend on the
27
- * compiler, and a consumer who never enables this rule never asks for it.
28
- */
29
- let ts;
30
- function typescript() {
31
- ts ??= createRequire(import.meta.url)("typescript");
32
- return ts;
33
- }
34
-
35
- function arrayLiteralOf(ts, expression) {
36
- let node = expression;
37
- while (
38
- node &&
39
- (ts.isAsExpression(node) ||
40
- ts.isSatisfiesExpression(node) ||
41
- ts.isParenthesizedExpression(node))
42
- ) {
43
- node = node.expression;
44
- }
45
- return node && ts.isArrayLiteralExpression(node) ? node : null;
46
- }
47
-
48
- function readKeys() {
49
- const ts = typescript();
50
- const file = fileURLToPath(import.meta.resolve(KBD_MODULE));
51
- const source = ts.createSourceFile(
52
- file,
53
- readFileSync(file, "utf8"),
54
- ts.ScriptTarget.Latest,
55
- false,
56
- file.endsWith(".js") ? ts.ScriptKind.JS : ts.ScriptKind.TSX,
57
- );
58
- for (const statement of source.statements) {
59
- if (!ts.isVariableStatement(statement)) continue;
60
- for (const declaration of statement.declarationList.declarations) {
61
- if (!ts.isIdentifier(declaration.name) || declaration.name.text !== "KBD_KEYS") continue;
62
- const array = arrayLiteralOf(ts, declaration.initializer);
63
- if (!array) break;
64
- return new Set(array.elements.map((element) => element.text));
65
- }
66
- }
67
- throw new Error(`${file} has no KBD_KEYS array literal to read the keys from.`);
68
- }
69
-
70
- let keys;
71
-
72
- /** Read once per lint process; the built module does not move under it. */
73
- function kbdKeys() {
74
- keys ??= readKeys();
75
- return keys;
76
- }
77
-
78
- function writtenText(child) {
79
- if (child.type === "JSXText") return child.value.trim() === "" ? null : child.value.trim();
80
- if (child.type !== "JSXExpressionContainer") return null;
81
- const { expression } = child;
82
- // oxlint-disable-next-line anti-slop/no-runtime-typeof -- ESTree types Literal.value as string | number | boolean | RegExp | bigint | null; only typeof picks the string.
83
- if (expression.type === "Literal" && typeof expression.value === "string") {
84
- return expression.value;
85
- }
86
- if (expression.type === "TemplateLiteral" && expression.expressions.length === 0) {
87
- return expression.quasis[0].value.cooked;
88
- }
89
- return null;
90
- }
91
-
92
- export const kbdChildrenNoModifierText = {
93
- meta: {
94
- type: "problem",
95
- docs: {
96
- description:
97
- "A Kbd child is one key from KBD_KEYS with the modifier as a flag, and a shortcut is never a lowercase kbd element.",
98
- },
99
- schema: [],
100
- messages: {
101
- "hand-written-key":
102
- "Write the modifier as a flag, <Kbd meta>K</Kbd>, and the child as one key from KBD_KEYS. A hand-written glyph shows the wrong key on Windows and Linux.",
103
- },
104
- },
105
- create(context) {
106
- const importOf = renderedImports(context);
107
- const ownsTheElement = context.filename.replaceAll("\\", "/").endsWith(`/${OWNER_FILE}`);
108
-
109
- return {
110
- JSXElement(node) {
111
- const name = node.openingElement.name;
112
- if (name.type === "JSXIdentifier" && name.name === "kbd") {
113
- if (!ownsTheElement) {
114
- context.report({ node: node.openingElement, messageId: "hand-written-key" });
115
- }
116
- return;
117
- }
118
- if (partOf(importOf(name), KBD, context.filename) !== "Kbd") return;
119
- for (const child of node.children) {
120
- const text = writtenText(child);
121
- if (text !== null && !kbdKeys().has(text)) {
122
- context.report({ node: child, messageId: "hand-written-key" });
123
- }
124
- }
125
- },
126
- };
127
- },
128
- };
@@ -1,41 +0,0 @@
1
- import { staticAttribute } from "./rendered-import.js";
2
-
3
- /** The string a Literal or a template without expressions states, else null. */
4
- export function literalText(node) {
5
- if (!node) return null;
6
- if (node.type === "Literal") {
7
- // oxlint-disable-next-line anti-slop/no-runtime-typeof -- ESTree types Literal.value as string | number | boolean | RegExp | bigint | null; only typeof picks the string.
8
- return typeof node.value === "string" ? node.value : null;
9
- }
10
- if (node.type === "TemplateLiteral" && node.expressions.length === 0) {
11
- return node.quasis[0].value.cooked;
12
- }
13
- return null;
14
- }
15
-
16
- /** The text a JSX element's children state when all of them are literal text, else null. */
17
- export function childText(element) {
18
- let text = "";
19
- for (const child of element.children) {
20
- if (child.type === "JSXText") text += child.value;
21
- else if (child.type === "JSXExpressionContainer" && literalText(child.expression) !== null) {
22
- text += literalText(child.expression);
23
- } else return null;
24
- }
25
- const trimmed = text.replace(/\s+/g, " ").trim();
26
- return trimmed === "" ? null : trimmed;
27
- }
28
-
29
- /** The key an object property names, else null. */
30
- export function keyName(property) {
31
- if (property.type !== "Property" || property.computed) return null;
32
- if (property.key.type === "Identifier") return property.key.name;
33
- return literalText(property.key);
34
- }
35
-
36
- /** An attribute's value when the source states it as a string, else null. */
37
- export function stringAttribute(openingElement, name) {
38
- const value = staticAttribute(openingElement, name);
39
- // oxlint-disable-next-line anti-slop/no-runtime-typeof -- staticAttribute returns true, a number or a string; only typeof picks the string.
40
- return typeof value === "string" ? value : null;
41
- }
@@ -1,75 +0,0 @@
1
- /*
2
- * Standard tool checked first: `no-restricted-imports` holds the menu modules
3
- * and the ellipsis icons (`repo/menu-owner-imports` in the root config's
4
- * product-composition blocks), but not a destructive `Button` rendered once per
5
- * row: that is an import binding joined to where its element renders, which no
6
- * import rule sees and a selector cannot follow through a renamed import.
7
- */
8
- import { PACKAGE_BARREL, partOf, renderedImports, staticAttribute } from "./rendered-import.js";
9
-
10
- const BUTTON = new Map([
11
- [
12
- "Button",
13
- ["@nadicodeai/ui/components/button", PACKAGE_BARREL].map((from) => ({ from, part: "Button" })),
14
- ],
15
- ]);
16
-
17
- const FUNCTIONS = new Set(["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"]);
18
- const ROW_CALLBACKS = new Set(["map", "flatMap"]);
19
- const ROW_RENDERERS = new Set(["cell", "command"]);
20
- const ROW_COMPONENT = /Row$/;
21
-
22
- const nameOf = (key) => (key?.type === "Identifier" ? key.name : key?.value);
23
-
24
- function drawsOneRecord(fn) {
25
- const { parent } = fn;
26
- if (
27
- parent.type === "CallExpression" &&
28
- parent.arguments[0] === fn &&
29
- parent.callee.type === "MemberExpression" &&
30
- !parent.callee.computed &&
31
- ROW_CALLBACKS.has(parent.callee.property.name)
32
- ) {
33
- return true;
34
- }
35
- if (parent.type === "Property" && parent.value === fn) {
36
- return ROW_RENDERERS.has(nameOf(parent.key));
37
- }
38
- if (parent.type === "JSXExpressionContainer" && parent.parent.type === "JSXAttribute") {
39
- return ROW_RENDERERS.has(parent.parent.name.name);
40
- }
41
- if (fn.type === "FunctionDeclaration") return ROW_COMPONENT.test(fn.id?.name ?? "");
42
- return parent.type === "VariableDeclarator" && ROW_COMPONENT.test(nameOf(parent.id) ?? "");
43
- }
44
-
45
- function insideARow(node) {
46
- for (let current = node.parent; current; current = current.parent) {
47
- if (FUNCTIONS.has(current.type) && drawsOneRecord(current)) return true;
48
- }
49
- return false;
50
- }
51
-
52
- export const menuOwner = {
53
- meta: {
54
- type: "problem",
55
- docs: {
56
- description:
57
- "A record's destructive command is the last item of its ActionMenu, never a destructive button in its row.",
58
- },
59
- schema: [],
60
- messages: {
61
- "row-destructive-button":
62
- "A destructive command is the last item of the row's ActionMenu, after a divider.",
63
- },
64
- },
65
- create(context) {
66
- const importOf = renderedImports(context);
67
- return {
68
- JSXOpeningElement(node) {
69
- if (partOf(importOf(node.name), BUTTON, context.filename) !== "Button") return;
70
- if (staticAttribute(node, "variant") !== "destructive") return;
71
- if (insideARow(node)) context.report({ node, messageId: "row-destructive-button" });
72
- },
73
- };
74
- },
75
- };
@@ -1,69 +0,0 @@
1
- /*
2
- * Standard tool checked first: a `no-restricted-syntax` descendant selector can
3
- * match `MiddleTruncate` under an element by name, but not that the name is the
4
- * design system's import, that the class sits in a `cn(...)` call or a
5
- * same-file table, nor that the nearest control carries an `aria-label`
6
- * without a second selector per spelling.
7
- */
8
- import { openingElementClassUtilities } from "./jsx-class-utility.js";
9
- import { renderedImports } from "./rendered-import.js";
10
-
11
- const FROM_DESIGN_SYSTEM = /^(@nadicodeai\/ui(\/|$)|@\/|\.)/;
12
- const CONTROLS = new Set(["Button", "ButtonLink", "TextLink"]);
13
- const HOST_CONTROLS = new Set(["a", "button"]);
14
- const NAMING_ATTRIBUTES = new Set(["aria-label", "aria-labelledby"]);
15
- const TRUNCATING = /^(truncate|text-ellipsis|overflow-ellipsis|line-clamp-(?!none$).+)$/;
16
-
17
- const withoutVariants = (utility) => utility.split(":").pop().replace(/^!/, "");
18
-
19
- const namesItself = (openingElement) =>
20
- openingElement.attributes.some(
21
- (attribute) => attribute.type === "JSXAttribute" && NAMING_ATTRIBUTES.has(attribute.name.name),
22
- );
23
-
24
- export const middleTruncatePlacement = {
25
- meta: {
26
- type: "problem",
27
- docs: {
28
- description: "MiddleTruncate cuts its own ellipsis and a control around it carries the name.",
29
- },
30
- schema: [],
31
- messages: {
32
- "cuts-its-own-ellipsis":
33
- "MiddleTruncate cuts its own ellipsis: take it out of the element that also truncates. Inside a control, give the control an aria-label that names its target, since the cut value is not a name.",
34
- },
35
- },
36
- create(context) {
37
- const importOf = renderedImports(context);
38
- const designSystemExport = (elementName) => {
39
- const imported = importOf(elementName);
40
- return imported && FROM_DESIGN_SYSTEM.test(imported.source) ? imported.name : null;
41
- };
42
- const isControl = ({ name }) =>
43
- CONTROLS.has(designSystemExport(name)) ||
44
- (name.type === "JSXIdentifier" && HOST_CONTROLS.has(name.name) && !importOf(name));
45
- const truncates = (openingElement) =>
46
- openingElementClassUtilities(openingElement, context).some((utility) =>
47
- TRUNCATING.test(withoutVariants(utility)),
48
- );
49
-
50
- return {
51
- JSXElement(node) {
52
- if (designSystemExport(node.openingElement.name) !== "MiddleTruncate") return;
53
- let nearestControl = null;
54
- for (let ancestor = node.parent; ancestor; ancestor = ancestor.parent) {
55
- if (ancestor.type !== "JSXElement") continue;
56
- const { openingElement } = ancestor;
57
- if (truncates(openingElement)) {
58
- context.report({ node: node.openingElement, messageId: "cuts-its-own-ellipsis" });
59
- return;
60
- }
61
- if (!nearestControl && isControl(openingElement)) nearestControl = openingElement;
62
- }
63
- if (nearestControl && !namesItself(nearestControl)) {
64
- context.report({ node: node.openingElement, messageId: "cuts-its-own-ellipsis" });
65
- }
66
- },
67
- };
68
- },
69
- };
@@ -1,100 +0,0 @@
1
- /*
2
- * `@nadicodeai/ui` ships standard components. An operator login, a portal
3
- * activation screen, a customer-credential panel — those are use cases, and a
4
- * use case in the package is a screen two consumers can never both want. The
5
- * boundary is named in the app's vocabulary, so the rule reads names: the
6
- * module's own file name and everything it exports.
7
- *
8
- * Standard tool checked first: core `no-restricted-syntax` matches
9
- * an exported identifier against a regex through esquery, but it is given one
10
- * node at a time and never the file that node is in — and a module called
11
- * `activation.tsx` exporting `Banner` is the case the file name is there to
12
- * catch. `context.filename` is why this is a rule rather than a selector list.
13
- *
14
- * The vocabulary itself is configuration, not code: the banned words live in the
15
- * workspace's eslint config where the package boundary is drawn, and this file
16
- * holds only the matching. Replaces the @nadicodeai/ui no-app-feature-components
17
- * scanner (#822), which built a TypeScript AST over the package's components to
18
- * ask the same question.
19
- */
20
-
21
- /** `OperatorLoginCard` and `operator-login.tsx` both normalise to `operator-login`. */
22
- function normalizeName(value) {
23
- return value
24
- .replace(/\.[jt]sx?$/, "")
25
- .replace(/([a-z0-9])([A-Z])/g, "$1-$2")
26
- .replace(/[\s_]+/g, "-")
27
- .toLowerCase();
28
- }
29
-
30
- /** The declared names one `export` statement introduces. */
31
- function exportedNames(node) {
32
- if (!node.declaration) {
33
- return node.specifiers.map((specifier) => specifier.exported.name ?? specifier.exported.value);
34
- }
35
- const declaration = node.declaration;
36
- if (declaration.type === "VariableDeclaration") {
37
- return declaration.declarations
38
- .filter((declarator) => declarator.id.type === "Identifier")
39
- .map((declarator) => declarator.id.name);
40
- }
41
- return declaration.id ? [declaration.id.name] : [];
42
- }
43
-
44
- export const noAppFeatureComponent = {
45
- meta: {
46
- type: "problem",
47
- docs: {
48
- description: "Disallow app-owned feature and use-case names in a shared component package",
49
- },
50
- schema: [
51
- {
52
- type: "object",
53
- properties: {
54
- names: {
55
- type: "array",
56
- items: {
57
- type: "object",
58
- properties: { feature: { type: "string" }, pattern: { type: "string" } },
59
- required: ["feature", "pattern"],
60
- additionalProperties: false,
61
- },
62
- },
63
- },
64
- additionalProperties: false,
65
- },
66
- ],
67
- messages: {
68
- appFeature:
69
- "{{what}} names the {{feature}} use case. This package ships standard components; compose an app feature inside the consuming app.",
70
- },
71
- },
72
- create(context) {
73
- const names = (context.options?.[0]?.names ?? []).map(({ feature, pattern }) => ({
74
- feature,
75
- pattern: new RegExp(pattern),
76
- }));
77
- if (names.length === 0) return {};
78
-
79
- const feature = (candidate) =>
80
- names.find(({ pattern }) => pattern.test(normalizeName(candidate)))?.feature;
81
-
82
- const report = (node, candidate, what) => {
83
- const matched = feature(candidate);
84
- if (matched)
85
- context.report({ node, messageId: "appFeature", data: { what, feature: matched } });
86
- };
87
-
88
- return {
89
- Program(node) {
90
- const file = context.filename.replaceAll("\\", "/").split("/").at(-1) ?? "";
91
- report(node, file, `The module name "${file}"`);
92
- },
93
- ExportNamedDeclaration(node) {
94
- for (const name of exportedNames(node)) {
95
- report(node, name, `The export "${name}"`);
96
- }
97
- },
98
- };
99
- },
100
- };
@@ -1,55 +0,0 @@
1
- /*
2
- * Standard tool checked first: `no-restricted-syntax` can match a `Button`
3
- * whose text is "OK", but not whether that `Button` is the package's (an
4
- * import binding, so a renamed or local one is judged correctly), nor read the
5
- * same word off a form's `submit={{ label }}`.
6
- */
7
- import { keyName, childText, literalText } from "./literal-text.js";
8
- import { renderedImports } from "./rendered-import.js";
9
-
10
- const BUTTONS = new Set(["Button", "ButtonLink"]);
11
- const BARE = /^(?:submit|ok|okay|confirm)[.!…]*$/i;
12
- const FROM_DESIGN_SYSTEM = /^(@nadicodeai\/ui(\/|$)|@\/|\.)/;
13
-
14
- export const noBareButtonLabel = {
15
- meta: {
16
- type: "problem",
17
- docs: {
18
- description:
19
- "A button says its result as a verb and a noun, never a bare Submit, OK or Confirm.",
20
- },
21
- schema: [],
22
- messages: {
23
- "bare-label":
24
- 'A button says its result: "Create customer", "Save changes", "Remove mailbox". "{{label}}" says nothing about what happens.',
25
- },
26
- },
27
- create(context) {
28
- const importOf = renderedImports(context);
29
-
30
- function report(node, label) {
31
- context.report({ node, messageId: "bare-label", data: { label } });
32
- }
33
-
34
- return {
35
- JSXElement(node) {
36
- const imported = importOf(node.openingElement.name);
37
- if (!imported || !BUTTONS.has(imported.name) || !FROM_DESIGN_SYSTEM.test(imported.source)) {
38
- return;
39
- }
40
- const label = childText(node);
41
- if (label !== null && BARE.test(label)) report(node.openingElement, label);
42
- },
43
- JSXAttribute(node) {
44
- if (node.name.name !== "submit" || node.value?.type !== "JSXExpressionContainer") return;
45
- const { expression } = node.value;
46
- if (expression.type !== "ObjectExpression") return;
47
- for (const property of expression.properties) {
48
- if (keyName(property) !== "label") continue;
49
- const label = literalText(property.value);
50
- if (label !== null && BARE.test(label.trim())) report(property.value, label.trim());
51
- }
52
- },
53
- };
54
- },
55
- };
@@ -1,97 +0,0 @@
1
- const CHOICE_CONTROLS = new Set(["Select", "ToggleGroup", "RadioGroup", "Tabs"]);
2
-
3
- const FUNCTIONS = new Set(["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"]);
4
-
5
- function enclosingFunction(node) {
6
- let current = node.parent;
7
- while (current && !FUNCTIONS.has(current.type)) current = current.parent;
8
- return current;
9
- }
10
-
11
- /** A component's own props: a destructured or typed parameter. */
12
- const isComponent = (fn) =>
13
- fn.params.some((param) => param.type === "ObjectPattern" || param.typeAnnotation);
14
-
15
- /** Whether `owner` handed the element its value: the element's own component, or a callback inside it. */
16
- function handedTo(element, owner) {
17
- for (let fn = enclosingFunction(element); fn; fn = enclosingFunction(fn)) {
18
- if (fn === owner) return true;
19
- if (isComponent(fn)) return false;
20
- }
21
- return false;
22
- }
23
-
24
- /** The identifiers in a handler that invoke what they name: the handler itself, a callee, or a method's receiver. */
25
- function invoked(handler) {
26
- const found = [];
27
- const visit = (node) => {
28
- // oxlint-disable-next-line anti-slop/no-runtime-typeof -- walks the generic AST, where only an object whose type is a string is a node.
29
- if (!node || typeof node.type !== "string") return;
30
- if (node.type === "Identifier") {
31
- const parent = node.parent;
32
- const isCallee = parent?.type === "CallExpression" && parent.callee === node;
33
- const isReceiver =
34
- parent?.type === "MemberExpression" &&
35
- parent.object === node &&
36
- parent.parent?.type === "CallExpression" &&
37
- parent.parent.callee === parent;
38
- if (node === handler || isCallee || isReceiver) found.push(node);
39
- }
40
- for (const [key, value] of Object.entries(node)) {
41
- if (key === "parent") continue;
42
- for (const child of Array.isArray(value) ? value : [value]) {
43
- // oxlint-disable-next-line anti-slop/no-runtime-typeof -- walks the generic AST, where only an object whose type is a string is a node.
44
- if (child && typeof child.type === "string") visit(child);
45
- }
46
- }
47
- };
48
- visit(handler);
49
- return found;
50
- }
51
-
52
- /**
53
- * A kit choice control whose onValueChange forwards to a callback the enclosing
54
- * component was handed. `ToolbarToggle` flattened Base UI's array into a string
55
- * there, and "Split by" stopped working while every check stayed green.
56
- */
57
- export const noChoiceControlWrapper = {
58
- meta: {
59
- type: "problem",
60
- docs: {
61
- description:
62
- "Render a kit choice control where its value is used, never behind a wrapper that forwards it.",
63
- },
64
- schema: [],
65
- messages: {
66
- wrapper:
67
- "Render the kit's {{control}} where the value is used, with its own API: this one forwards onValueChange to \"{{name}}\", which the component was handed, and a wrapper is where the value's shape gets lost.",
68
- },
69
- },
70
- create(context) {
71
- return {
72
- "JSXAttribute[name.name='onValueChange'] > JSXExpressionContainer"(container) {
73
- const opening = container.parent.parent;
74
- const control = opening.name.type === "JSXIdentifier" ? opening.name.name : null;
75
- if (!CHOICE_CONTROLS.has(control)) return;
76
- const handler = container.expression;
77
- for (const identifier of invoked(handler)) {
78
- const scope = context.sourceCode.getScope(identifier);
79
- let variable = null;
80
- for (let current = scope; current && !variable; current = current.upper) {
81
- variable = current.set.get(identifier.name) ?? null;
82
- }
83
- const definition = variable?.defs[0];
84
- if (definition?.type !== "Parameter") continue;
85
- if (definition.node === handler) continue;
86
- if (!handedTo(opening, definition.node)) continue;
87
- context.report({
88
- node: container,
89
- messageId: "wrapper",
90
- data: { control, name: identifier.name },
91
- });
92
- return;
93
- }
94
- },
95
- };
96
- },
97
- };
@@ -1,77 +0,0 @@
1
- /*
2
- * Code says what it does in its names and its structure, and a test says what
3
- * it proves in its name and its assertions; a comment restates one of them and
4
- * nothing keeps it true when the code changes. A directive to a tool is not
5
- * prose for the reader: ESLint's, Oxlint's, TypeScript's, Biome's, Prettier's,
6
- * coverage's and Vitest's stay, and so does the marker the seam guard requires.
7
- */
8
-
9
- const DIRECTIVE =
10
- /^[*/]?\s*(?:@ts-|eslint-|eslint\s+[\w@/-]+\s*:|oxlint-|biome-ignore|<reference\b|istanbul\b|c8\s|prettier-ignore|@vitest-environment|@jsx)/;
11
-
12
- const SEAM_MARKER = /^\s*NADIA\((?:added|changed|removed)\):/;
13
-
14
- function moduleHeader(comments, firstTokenStart) {
15
- const [first, ...rest] = comments;
16
- if (first === undefined || first.range[1] > firstTokenStart) return [];
17
- if (first.type === "Block") return [first];
18
- const run = [first];
19
- for (const next of rest) {
20
- if (
21
- next.type !== "Line" ||
22
- next.range[1] > firstTokenStart ||
23
- next.loc.start.line !== run.at(-1).loc.end.line + 1
24
- ) {
25
- break;
26
- }
27
- run.push(next);
28
- }
29
- return run;
30
- }
31
-
32
- export const noComment = {
33
- meta: {
34
- type: "problem",
35
- docs: {
36
- description:
37
- "Disallow comments in code, but for directives to a tool, the marker the seam guard requires and, when allowed, the one comment that opens a module",
38
- },
39
- schema: [
40
- {
41
- type: "object",
42
- properties: { allowModuleHeader: { type: "boolean" } },
43
- additionalProperties: false,
44
- },
45
- ],
46
- defaultOptions: [{ allowModuleHeader: false }],
47
- messages: {
48
- comment:
49
- "Code says what it does in its names and its structure, never in a comment. Rename or restructure, or remove the comment.",
50
- },
51
- },
52
-
53
- create(context) {
54
- const [{ allowModuleHeader }] = context.options;
55
- const { sourceCode } = context;
56
- return {
57
- Program() {
58
- const prose = sourceCode
59
- .getAllComments()
60
- .filter(
61
- (comment) =>
62
- comment.type !== "Shebang" &&
63
- !DIRECTIVE.test(comment.value) &&
64
- !SEAM_MARKER.test(comment.value),
65
- );
66
- const header = allowModuleHeader
67
- ? moduleHeader(prose, sourceCode.ast.tokens[0]?.range[0] ?? Infinity)
68
- : [];
69
- for (const comment of prose) {
70
- if (!header.includes(comment)) {
71
- context.report({ loc: comment.loc, messageId: "comment" });
72
- }
73
- }
74
- },
75
- };
76
- },
77
- };