@geonosis/oxlint-plugin-biological-architecture 2.13.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (233) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +2 -2
  3. package/RULES.md +7 -6
  4. package/corpus/.oxlintrc.json +1 -0
  5. package/corpus/icon-controls/bad-unnamed-icon-button.tsx +8 -0
  6. package/corpus/icon-controls/good-named-icon-button.tsx +19 -0
  7. package/corpus/manifest.json +1 -0
  8. package/dist/discover-atoms.d.ts +5 -6
  9. package/dist/discover-atoms.js +33 -24
  10. package/dist/index.d.ts +7 -54
  11. package/dist/index.js +182 -7973
  12. package/dist/presets.d.ts +6 -8
  13. package/dist/presets.js +138 -6
  14. package/dist/rules/atom-no-deps.d.ts +21 -0
  15. package/dist/rules/atom-no-deps.js +29 -0
  16. package/dist/rules/boundary-time-is-primitive.d.ts +56 -0
  17. package/dist/rules/boundary-time-is-primitive.js +134 -0
  18. package/dist/rules/cell-must-be-stateful.d.ts +22 -0
  19. package/dist/rules/cell-must-be-stateful.js +75 -0
  20. package/dist/rules/cell-must-not-compose-cell.d.ts +21 -0
  21. package/dist/rules/cell-must-not-compose-cell.js +29 -0
  22. package/dist/rules/cell-no-cross-feature-organelles.d.ts +21 -0
  23. package/dist/rules/cell-no-cross-feature-organelles.js +37 -0
  24. package/dist/rules/cell-no-tissues.d.ts +21 -0
  25. package/dist/rules/cell-no-tissues.js +23 -0
  26. package/dist/rules/cells-folder-index-is-barrel.d.ts +35 -0
  27. package/dist/rules/cells-folder-index-is-barrel.js +66 -0
  28. package/dist/rules/compound-must-be-stateless.d.ts +39 -0
  29. package/dist/rules/compound-must-be-stateless.js +86 -0
  30. package/dist/rules/compound-no-stores.d.ts +21 -0
  31. package/dist/rules/compound-no-stores.js +25 -0
  32. package/dist/rules/constants-in-constants-file.d.ts +41 -0
  33. package/dist/rules/constants-in-constants-file.js +41 -0
  34. package/dist/rules/dialect-through-the-seam.d.ts +63 -0
  35. package/dist/rules/dialect-through-the-seam.js +102 -0
  36. package/dist/rules/durable-body-reads-through-steps.d.ts +78 -0
  37. package/dist/rules/durable-body-reads-through-steps.js +122 -0
  38. package/dist/rules/effect-hook-naming.d.ts +48 -0
  39. package/dist/rules/effect-hook-naming.js +82 -0
  40. package/dist/rules/emit-declares-attempts.d.ts +62 -0
  41. package/dist/rules/emit-declares-attempts.js +102 -0
  42. package/dist/rules/font-roles-only.d.ts +78 -0
  43. package/dist/rules/font-roles-only.js +88 -0
  44. package/dist/rules/icon-control-has-name.d.ts +53 -0
  45. package/dist/rules/icon-control-has-name.js +65 -0
  46. package/dist/rules/layer-walls.d.ts +97 -0
  47. package/dist/rules/layer-walls.js +138 -0
  48. package/dist/rules/lib/cells-barrel.d.ts +2 -0
  49. package/dist/rules/lib/cells-barrel.js +6 -0
  50. package/dist/rules/lib/colors.d.ts +24 -0
  51. package/dist/rules/lib/colors.js +261 -0
  52. package/dist/rules/lib/context.d.ts +26 -0
  53. package/dist/rules/lib/context.js +0 -0
  54. package/dist/rules/lib/direction-rule.d.ts +65 -0
  55. package/dist/rules/lib/direction-rule.js +125 -0
  56. package/dist/rules/lib/doors.d.ts +26 -0
  57. package/dist/rules/lib/doors.js +89 -0
  58. package/dist/rules/lib/hooks.d.ts +20 -0
  59. package/dist/rules/lib/hooks.js +21 -0
  60. package/dist/rules/lib/imports.d.ts +52 -0
  61. package/dist/rules/lib/imports.js +25 -0
  62. package/dist/rules/lib/landing.d.ts +50 -0
  63. package/dist/rules/lib/landing.js +111 -0
  64. package/dist/rules/lib/literal-call.d.ts +11 -0
  65. package/dist/rules/lib/literal-call.js +10 -0
  66. package/dist/rules/lib/module-text.d.ts +43 -0
  67. package/dist/{chunk-H7UQNDFE.js → rules/lib/module-text.js} +44 -30
  68. package/dist/rules/lib/mutations.d.ts +19 -0
  69. package/dist/rules/lib/mutations.js +27 -0
  70. package/dist/rules/lib/nodes.d.ts +25 -0
  71. package/dist/rules/lib/nodes.js +71 -0
  72. package/dist/rules/lib/objects.d.ts +17 -0
  73. package/dist/rules/lib/objects.js +35 -0
  74. package/dist/rules/lib/options.d.ts +74 -0
  75. package/dist/rules/lib/options.js +64 -0
  76. package/dist/rules/lib/package-imports.d.ts +6 -0
  77. package/dist/rules/lib/package-imports.js +43 -0
  78. package/dist/rules/lib/paths.d.ts +47 -0
  79. package/dist/rules/lib/paths.js +28 -0
  80. package/dist/rules/lib/pattern-match.d.ts +16 -0
  81. package/dist/rules/lib/pattern-match.js +29 -0
  82. package/dist/rules/lib/probe.d.ts +55 -0
  83. package/dist/rules/lib/probe.js +39 -0
  84. package/dist/rules/lib/reexports.d.ts +20 -0
  85. package/dist/rules/lib/reexports.js +40 -0
  86. package/dist/rules/lib/render-tracking.d.ts +54 -0
  87. package/dist/rules/lib/render-tracking.js +27 -0
  88. package/dist/rules/lib/schema.d.ts +14 -0
  89. package/dist/rules/lib/schema.js +11 -0
  90. package/dist/rules/lib/shared-features.d.ts +24 -0
  91. package/dist/rules/lib/shared-features.js +16 -0
  92. package/dist/rules/lib/steps.d.ts +19 -0
  93. package/dist/rules/lib/steps.js +37 -0
  94. package/dist/rules/lib/styling.d.ts +65 -0
  95. package/dist/rules/lib/styling.js +90 -0
  96. package/dist/rules/lib/tiers.d.ts +31 -0
  97. package/dist/rules/lib/tiers.js +32 -0
  98. package/dist/rules/lib/tissue-entrypoint.d.ts +5 -0
  99. package/dist/rules/lib/tissue-entrypoint.js +15 -0
  100. package/dist/rules/lib/tsconfig-paths.d.ts +5 -0
  101. package/dist/rules/lib/tsconfig-paths.js +109 -0
  102. package/dist/rules/lib/visitors.d.ts +31 -0
  103. package/dist/rules/lib/visitors.js +38 -0
  104. package/dist/rules/list-take-without-order.d.ts +36 -0
  105. package/dist/rules/list-take-without-order.js +84 -0
  106. package/dist/rules/max-comment-density.d.ts +49 -0
  107. package/dist/rules/max-comment-density.js +72 -0
  108. package/dist/rules/molecule-atoms-only.d.ts +21 -0
  109. package/dist/rules/molecule-atoms-only.js +28 -0
  110. package/dist/rules/molecule-must-compose.d.ts +25 -0
  111. package/dist/rules/molecule-must-compose.js +73 -0
  112. package/dist/rules/mutating-step-declares-retry.d.ts +57 -0
  113. package/dist/rules/mutating-step-declares-retry.js +92 -0
  114. package/dist/rules/named-when-block.d.ts +37 -0
  115. package/dist/rules/named-when-block.js +59 -0
  116. package/dist/rules/next-route-segment-is-thin-delegate.d.ts +56 -0
  117. package/dist/rules/next-route-segment-is-thin-delegate.js +194 -0
  118. package/dist/rules/no-brand-names.d.ts +64 -0
  119. package/dist/rules/no-brand-names.js +80 -0
  120. package/dist/rules/no-card-shaped-div.d.ts +67 -0
  121. package/dist/rules/no-card-shaped-div.js +73 -0
  122. package/dist/rules/no-cross-feature-stores.d.ts +21 -0
  123. package/dist/rules/no-cross-feature-stores.js +31 -0
  124. package/dist/rules/no-d1-transaction.d.ts +69 -0
  125. package/dist/rules/no-d1-transaction.js +90 -0
  126. package/dist/rules/no-date-string-compare.d.ts +28 -0
  127. package/dist/rules/no-date-string-compare.js +100 -0
  128. package/dist/rules/no-duplicate-jsx-patterns.d.ts +55 -0
  129. package/dist/rules/no-duplicate-jsx-patterns.js +103 -0
  130. package/dist/rules/no-generic-utility-package.d.ts +38 -0
  131. package/dist/rules/no-generic-utility-package.js +86 -0
  132. package/dist/rules/no-hook-in-component-disguise.d.ts +96 -0
  133. package/dist/rules/no-hook-in-component-disguise.js +229 -0
  134. package/dist/rules/no-index-count-as-exact.d.ts +42 -0
  135. package/dist/rules/no-index-count-as-exact.js +65 -0
  136. package/dist/rules/no-inert-hidden-jsx.d.ts +40 -0
  137. package/dist/rules/no-inert-hidden-jsx.js +75 -0
  138. package/dist/rules/no-inline-data-in-jsx.d.ts +24 -0
  139. package/dist/rules/no-inline-data-in-jsx.js +71 -0
  140. package/dist/rules/no-invalid-feature-folders.d.ts +36 -0
  141. package/dist/rules/no-invalid-feature-folders.js +88 -0
  142. package/dist/rules/no-loader-side-effect-in-index-file.d.ts +55 -0
  143. package/dist/rules/no-loader-side-effect-in-index-file.js +77 -0
  144. package/dist/rules/no-logic-in-component-files.d.ts +49 -0
  145. package/dist/rules/no-logic-in-component-files.js +105 -0
  146. package/dist/rules/no-mock-db-in-integration.d.ts +88 -0
  147. package/dist/rules/no-mock-db-in-integration.js +105 -0
  148. package/dist/rules/no-orm-outside-db.d.ts +21 -0
  149. package/dist/rules/no-orm-outside-db.js +37 -0
  150. package/dist/rules/no-raw-html-atoms.d.ts +82 -0
  151. package/dist/rules/no-raw-html-atoms.js +91 -0
  152. package/dist/rules/no-raw-sql-outside-allowed.d.ts +61 -0
  153. package/dist/rules/no-raw-sql-outside-allowed.js +57 -0
  154. package/dist/rules/no-react-namespace.d.ts +39 -0
  155. package/dist/rules/no-react-namespace.js +46 -0
  156. package/dist/rules/no-renamed-html-props.d.ts +38 -0
  157. package/dist/rules/no-renamed-html-props.js +80 -0
  158. package/dist/rules/no-render-prop-reader.d.ts +67 -0
  159. package/dist/rules/no-render-prop-reader.js +59 -0
  160. package/dist/rules/no-runtime-dead-affordance.d.ts +69 -0
  161. package/dist/rules/no-runtime-dead-affordance.js +86 -0
  162. package/dist/rules/no-swallowed-catch.d.ts +36 -0
  163. package/dist/rules/no-swallowed-catch.js +92 -0
  164. package/dist/rules/no-trivial-wrapper-component.d.ts +61 -0
  165. package/dist/rules/no-trivial-wrapper-component.js +147 -0
  166. package/dist/rules/no-ts-in-bio-folders.d.ts +52 -0
  167. package/dist/rules/no-ts-in-bio-folders.js +58 -0
  168. package/dist/rules/no-type-definitions-in-components.d.ts +33 -0
  169. package/dist/rules/no-type-definitions-in-components.js +48 -0
  170. package/dist/rules/no-unregistered-plugin-dir.d.ts +116 -0
  171. package/dist/rules/no-unregistered-plugin-dir.js +138 -0
  172. package/dist/rules/no-void-port.d.ts +65 -0
  173. package/dist/rules/no-void-port.js +53 -0
  174. package/dist/rules/organelle-dependency.d.ts +21 -0
  175. package/dist/rules/organelle-dependency.js +37 -0
  176. package/dist/rules/organelle-single-source.d.ts +19 -0
  177. package/dist/rules/organelle-single-source.js +97 -0
  178. package/dist/rules/plugin-route-namespaced.d.ts +79 -0
  179. package/dist/rules/plugin-route-namespaced.js +137 -0
  180. package/dist/rules/queries-require-org-scope.d.ts +88 -0
  181. package/dist/rules/queries-require-org-scope.js +83 -0
  182. package/dist/rules/queue-loop-is-the-library.d.ts +28 -0
  183. package/dist/rules/queue-loop-is-the-library.js +35 -0
  184. package/dist/rules/route-no-inline-mutation.d.ts +81 -0
  185. package/dist/rules/route-no-inline-mutation.js +125 -0
  186. package/dist/rules/router-schema-parity.d.ts +60 -0
  187. package/dist/rules/router-schema-parity.js +95 -0
  188. package/dist/rules/service-name-not-reserved.d.ts +47 -0
  189. package/dist/rules/service-name-not-reserved.js +112 -0
  190. package/dist/rules/ssot-no-inline-facts.d.ts +68 -0
  191. package/dist/rules/ssot-no-inline-facts.js +221 -0
  192. package/dist/rules/ssot-no-process-env.d.ts +55 -0
  193. package/dist/rules/ssot-no-process-env.js +51 -0
  194. package/dist/rules/step-declares-compensation-or-none.d.ts +34 -0
  195. package/dist/rules/step-declares-compensation-or-none.js +52 -0
  196. package/dist/rules/step-opens-its-own-cell.d.ts +82 -0
  197. package/dist/rules/step-opens-its-own-cell.js +163 -0
  198. package/dist/rules/store-route-scopes-tenant-data.d.ts +52 -0
  199. package/dist/rules/store-route-scopes-tenant-data.js +150 -0
  200. package/dist/rules/subpath-over-barrel.d.ts +67 -0
  201. package/dist/rules/subpath-over-barrel.js +153 -0
  202. package/dist/rules/subscriber-declares-id.d.ts +39 -0
  203. package/dist/rules/subscriber-declares-id.js +79 -0
  204. package/dist/rules/tables-declare-their-plane.d.ts +44 -0
  205. package/dist/rules/tables-declare-their-plane.js +64 -0
  206. package/dist/rules/tenant-tables-carry-org-id.d.ts +66 -0
  207. package/dist/rules/tenant-tables-carry-org-id.js +64 -0
  208. package/dist/rules/test-no-clock-polling-for-promise-flips.d.ts +42 -0
  209. package/dist/rules/test-no-clock-polling-for-promise-flips.js +130 -0
  210. package/dist/rules/time-through-the-door.d.ts +86 -0
  211. package/dist/rules/time-through-the-door.js +138 -0
  212. package/dist/rules/tissue-must-compose.d.ts +41 -0
  213. package/dist/rules/tissue-must-compose.js +113 -0
  214. package/dist/rules/tissue-no-data-props.d.ts +27 -0
  215. package/dist/rules/tissue-no-data-props.js +148 -0
  216. package/dist/rules/tissue-no-hooks.d.ts +43 -0
  217. package/dist/rules/tissue-no-hooks.js +72 -0
  218. package/dist/rules/tissue-no-organelles.d.ts +21 -0
  219. package/dist/rules/tissue-no-organelles.js +17 -0
  220. package/dist/rules/tissue-no-stores.d.ts +21 -0
  221. package/dist/rules/tissue-no-stores.js +17 -0
  222. package/dist/rules/todo-names-its-plan.d.ts +75 -0
  223. package/dist/rules/todo-names-its-plan.js +68 -0
  224. package/dist/rules/tokens-only-colors.d.ts +100 -0
  225. package/dist/rules/tokens-only-colors.js +129 -0
  226. package/dist/rules/unique-query-step-name.d.ts +50 -0
  227. package/dist/rules/unique-query-step-name.js +130 -0
  228. package/dist/rules/worker-handles-are-scoped.d.ts +65 -0
  229. package/dist/rules/worker-handles-are-scoped.js +97 -0
  230. package/dist/rules/zustand-v5-best-practices.d.ts +65 -0
  231. package/dist/rules/zustand-v5-best-practices.js +107 -0
  232. package/package.json +4 -4
  233. package/dist/chunk-ZY3XIRRE.js +0 -145
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @geonosis/oxlint-plugin-biological-architecture
2
2
 
3
+ ## 3.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 27d169d: `icon-control-has-name`, in the `frontend` preset: a `<button>` or `<a>` — or a control atom the repo names in `controls` — whose only content is an icon (a component whose name matches `icons`, `Icon$` by default, or an inline `<svg>`) and that carries no `aria-label`, `aria-labelledby` or `title` has no name a screen reader can read. A spread is left alone. It needs no option to run.
8
+
9
+ ## 3.0.0
10
+
11
+ ### Major Changes
12
+
13
+ - 237a353: `document-sagas-are-generic` and `documents-share-one-table`, retired in 2.7.0 and kept as no-ops until this major, are gone: a config that still names either is refused by oxlint with "rule not found". Remove them from the config. `RETIRED_RULES` is no longer exported.
14
+
3
15
  ## 2.13.0
4
16
 
5
17
  ## 2.12.0
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @geonosis/oxlint-plugin-biological-architecture
2
2
 
3
- 80 architecture rules as an oxlint JS plugin: which tier a file belongs to, what it may import,
3
+ 81 architecture rules as an oxlint JS plugin: which tier a file belongs to, what it may import,
4
4
  where state is allowed to live, and the backend invariants that go with them. Nothing is hardcoded
5
5
  to a repo — every list of brands, features, tables or paths is an option. A rule enabled without the
6
6
  options it needs says so once a run and judges nothing, rather than passing silently.
@@ -57,7 +57,7 @@ everything below the organelle is inert. A cell never composes another cell.
57
57
 
58
58
  | preset | rules | what it is |
59
59
  | --- | --- | --- |
60
- | `frontend` (= `recommended`) | 37 | tier direction, state placement, element choice, file shape |
60
+ | `frontend` (= `recommended`) | 38 | tier direction, state placement, element choice, file shape |
61
61
  | `backend-workflows` | 15 | workflows, time, the data layer, single source of truth |
62
62
  | `backend-medusa` | 13 | Medusa steps, emits, subscribers, loaders and the store route surface |
63
63
  | `tenant-scoping` | 4 | every row placed, scoped and narrowed to one tenant |
package/RULES.md CHANGED
@@ -11,13 +11,12 @@ One plugin name, two rule sets, no shared code. **33 rules had the same filename
11
11
 
12
12
  The union here is **52 rules** — 54 when it was cut, less `document-sagas-are-generic` and
13
13
  `documents-share-one-table`, retired in 2.7.0 because both enforced one consumer's document kinds —
14
- plus twenty-eight the kit wrote for itself: `layer-walls`, `emit-declares-attempts`,
14
+ plus twenty-nine the kit wrote for itself: `layer-walls`, `emit-declares-attempts`,
15
15
  `cell-no-cross-feature-organelles`, the `backend-medusa` ten, `no-unregistered-plugin-dir` +
16
16
  `router-schema-parity`, the `themekit` two, `no-mock-db-in-integration`, `todo-names-its-plan`,
17
17
  `boundary-time-is-primitive`, `durable-body-reads-through-steps`, `subpath-over-barrel` and the six
18
- of the W67 batch — **80**. The two retired ids still resolve until the next major, as no-ops that
19
- say they are retired, so a config naming them parses.
20
- Every one of the twenty-eight is marked **written here** in the inventory, and the table below is
18
+ of the W67 batch, and `icon-control-has-name` — **81**. The two retired ids went in 3.0.0.
19
+ Every one of the twenty-nine is marked **written here** in the inventory, and the table below is
21
20
  held against that column rather than kept by hand.
22
21
 
23
22
  | | count |
@@ -27,8 +26,8 @@ held against that column rather than kept by hand.
27
26
  | A Medusa storefront only | 3 |
28
27
  | A Workers + D1 app only | 16 |
29
28
  | **union** | **52** |
30
- | written here | 28 |
31
- | **total** | **80** |
29
+ | written here | 29 |
30
+ | **total** | **81** |
32
31
 
33
32
  ## How divergence was resolved
34
33
 
@@ -722,6 +721,7 @@ every repo's.
722
721
  | `dialect-through-the-seam` | backend-workflows | `seam` | `onImportSource` + `mergeVisitors` + `paths` + `options` | — | yes | a Workers + D1 app only, de-hardcoded |
723
722
  | `durable-body-reads-through-steps` | backend-workflows | `ports` | `nodes` + `objects` + `steps` + `options` | — | — | **written here** (#167, design-026 §8) |
724
723
  | `effect-hook-naming` | frontend | — | `paths` | yes | yes | diverged |
724
+ | `icon-control-has-name` | frontend | — | `nodes` + `options` | — | — | **written here** |
725
725
  | `emit-declares-attempts` | backend-medusa | — | `options` | — | — | **written here** |
726
726
  | `font-roles-only` | themekit | `roles` | `paths` + `options` + `styling` | — | — | **written here** (U2) |
727
727
  | `layer-walls` | tooling | `layers` | `onImportSource` + `imports` + `paths` + `options` | — | — | **written here** |
@@ -879,6 +879,7 @@ option not named here is one no rule reads.
879
879
  | `effect-hook-naming` | — |
880
880
  | `emit-declares-attempts` | `budgetHelpers`, `emitters` |
881
881
  | `font-roles-only` | `allow`, `exemptModules`, `prefix`, `roles` |
882
+ | `icon-control-has-name` | `controls`, `icons` |
882
883
  | `layer-walls` | `externals`, `layers`, `typeOnly` |
883
884
  | `list-take-without-order` | `callees`, `orderKeys` |
884
885
  | `max-comment-density` | — |
@@ -171,6 +171,7 @@
171
171
  ]
172
172
  ],
173
173
  "biological-architecture/no-raw-sql-outside-allowed": "error",
174
+ "biological-architecture/icon-control-has-name": "error",
174
175
  "biological-architecture/no-react-namespace": "error",
175
176
  "biological-architecture/no-runtime-dead-affordance": [
176
177
  "error",
@@ -0,0 +1,8 @@
1
+ // BREACH: a screen reader announces "button" and nothing else.
2
+ import { BinIcon } from '@kit/ui/atoms/icons/bin-icon'
3
+
4
+ export const RemoveLine = ({ onRemove }: { onRemove: () => void }): JSX.Element => (
5
+ <button type="button" onClick={onRemove}>
6
+ <BinIcon />
7
+ </button>
8
+ )
@@ -0,0 +1,19 @@
1
+ import { BinIcon } from '@kit/ui/atoms/icons/bin-icon'
2
+
3
+ export const RemoveLine = ({
4
+ label,
5
+ onRemove
6
+ }: {
7
+ label: string
8
+ onRemove: () => void
9
+ }): JSX.Element => (
10
+ <div>
11
+ <button type="button" onClick={onRemove} aria-label={label}>
12
+ <BinIcon />
13
+ </button>
14
+ <button type="button" onClick={onRemove}>
15
+ <BinIcon />
16
+ <span className="sr-only">{label}</span>
17
+ </button>
18
+ </div>
19
+ )
@@ -16,6 +16,7 @@
16
16
  "biological-architecture/effect-hook-naming",
17
17
  "biological-architecture/emit-declares-attempts",
18
18
  "biological-architecture/font-roles-only",
19
+ "biological-architecture/icon-control-has-name",
19
20
  "biological-architecture/layer-walls",
20
21
  "biological-architecture/list-take-without-order",
21
22
  "biological-architecture/max-comment-density",
@@ -17,12 +17,12 @@ interface RestrictedSyntaxEntry {
17
17
  * for every native element wrapped by an atom. Apply these entries to
18
18
  * molecules, compounds, cells, and tissues (NOT atoms themselves).
19
19
  */
20
- declare function buildAtomRestrictions(atomsDir: string, importPathPrefix?: string): RestrictedSyntaxEntry[];
20
+ export declare function buildAtomRestrictions(atomsDir: string, importPathPrefix?: string): RestrictedSyntaxEntry[];
21
21
  /**
22
22
  * Build atom restrictions in the format expected by the no-raw-html-atoms rule.
23
23
  * This replaces no-restricted-syntax for linters that don't support it (e.g. oxlint).
24
24
  */
25
- declare function buildAtomRuleRestrictions(atomsDir: string, importPathPrefix?: string): AtomRestriction[];
25
+ export declare function buildAtomRuleRestrictions(atomsDir: string, importPathPrefix?: string): AtomRestriction[];
26
26
  /**
27
27
  * Scan the atoms directory and build a mapping from native HTML element
28
28
  * to the atom that wraps it. This is used to generate no-restricted-syntax
@@ -33,7 +33,7 @@ declare function buildAtomRuleRestrictions(atomsDir: string, importPathPrefix?:
33
33
  * exactly matches the element name is preferred as the canonical one.
34
34
  * Variants are kept as alternatives in the error message.
35
35
  */
36
- declare function scanAtomMappings(atomsDir: string): AtomMapping[];
36
+ export declare function scanAtomMappings(atomsDir: string): AtomMapping[];
37
37
  /**
38
38
  * The native element an atom wraps, read from the one place every atom says so: its props type.
39
39
  *
@@ -46,6 +46,5 @@ declare function scanAtomMappings(atomsDir: string): AtomMapping[];
46
46
  *
47
47
  * The name is kept because consumers import it.
48
48
  */
49
- declare function detectFirstNativeJsxElement(source: string): null | string;
50
-
51
- export { buildAtomRestrictions, buildAtomRuleRestrictions, detectFirstNativeJsxElement, scanAtomMappings };
49
+ export declare function detectFirstNativeJsxElement(source: string): null | string;
50
+ export {};
@@ -1,12 +1,9 @@
1
- import {
2
- stripComments
3
- } from "./chunk-H7UQNDFE.js";
4
-
5
1
  // src/discover-atoms.ts
6
- import { readdirSync, readFileSync } from "fs";
7
- import { basename, join } from "path";
8
- var GENERIC_ELEMENTS = /* @__PURE__ */ new Set(["div", "span"]);
9
- var HTML_ELEMENTS = /* @__PURE__ */ new Set([
2
+ import { readdirSync, readFileSync } from "node:fs";
3
+ import { basename, join } from "node:path";
4
+ import { stripComments } from "./rules/lib/module-text.js";
5
+ var GENERIC_ELEMENTS = new Set(["div", "span"]);
6
+ var HTML_ELEMENTS = new Set([
10
7
  "a",
11
8
  "abbr",
12
9
  "address",
@@ -181,17 +178,22 @@ function buildAtomRuleRestrictions(atomsDir, importPathPrefix = "@kit/ui/atoms")
181
178
  }
182
179
  function scanAtomMappings(atomsDir) {
183
180
  const entries = readdirSync(atomsDir, { withFileTypes: true });
184
- const candidates = /* @__PURE__ */ new Map();
181
+ const candidates = new Map;
185
182
  for (const entry of entries) {
186
- if (!entry.isFile()) continue;
187
- if (!entry.name.endsWith(".tsx")) continue;
188
- if (NOT_AN_ATOM.test(entry.name)) continue;
183
+ if (!entry.isFile())
184
+ continue;
185
+ if (!entry.name.endsWith(".tsx"))
186
+ continue;
187
+ if (NOT_AN_ATOM.test(entry.name))
188
+ continue;
189
189
  const atomFile = entry.name;
190
190
  const atomName = basename(atomFile, ".tsx");
191
191
  const content = readFileSync(join(atomsDir, atomFile), "utf8");
192
192
  const nativeElement = detectFirstNativeJsxElement(content);
193
- if (!nativeElement) continue;
194
- if (GENERIC_ELEMENTS.has(nativeElement)) continue;
193
+ if (!nativeElement)
194
+ continue;
195
+ if (GENERIC_ELEMENTS.has(nativeElement))
196
+ continue;
195
197
  const existing = candidates.get(nativeElement) || [];
196
198
  existing.push({ atomFile, atomName, nativeElement });
197
199
  candidates.set(nativeElement, existing);
@@ -200,44 +202,51 @@ function scanAtomMappings(atomsDir) {
200
202
  for (const [element, list] of candidates) {
201
203
  const exact = list.find((m) => m.atomName === element);
202
204
  const chosen = exact ?? list[0];
203
- if (chosen) mappings.push(chosen);
205
+ if (chosen)
206
+ mappings.push(chosen);
204
207
  }
205
208
  return mappings;
206
209
  }
207
210
  function detectFirstNativeJsxElement(source) {
208
211
  const withoutComments = stripComments(source);
209
212
  const declared = elementFromPropsType(withoutComments);
210
- if (declared) return declared;
213
+ if (declared)
214
+ return declared;
211
215
  const slot = SLOT_FALLBACK.exec(withoutComments)?.[1];
212
- if (slot && HTML_ELEMENTS.has(slot)) return slot;
216
+ if (slot && HTML_ELEMENTS.has(slot))
217
+ return slot;
213
218
  return elementFromJsx(withoutComments);
214
219
  }
215
220
  function elementFromPropsType(source) {
216
221
  const found = [];
217
222
  for (const match of source.matchAll(COMPONENT_PROPS)) {
218
223
  const element = match[1];
219
- if (element && HTML_ELEMENTS.has(element)) found.push({ at: match.index, element });
224
+ if (element && HTML_ELEMENTS.has(element))
225
+ found.push({ at: match.index, element });
220
226
  }
221
227
  for (const match of source.matchAll(HTML_ATTRIBUTES)) {
222
228
  const element = elementOfAttributes(match[1], match[2]);
223
- if (element) found.push({ at: match.index, element });
229
+ if (element)
230
+ found.push({ at: match.index, element });
224
231
  }
225
232
  return found.toSorted((a, b) => a.at - b.at)[0]?.element ?? null;
226
233
  }
227
234
  function elementOfAttributes(prefix, domInterface) {
228
- if (prefix !== void 0) {
235
+ if (prefix !== undefined) {
229
236
  const lower = prefix.toLowerCase();
230
237
  const named = TAG_OF_ATTRIBUTES_PREFIX[lower] ?? lower;
231
- if (HTML_ELEMENTS.has(named)) return named;
238
+ if (HTML_ELEMENTS.has(named))
239
+ return named;
232
240
  }
233
- const mapped = domInterface === void 0 ? void 0 : TAG_OF_DOM_INTERFACE[domInterface];
234
- return mapped !== void 0 && HTML_ELEMENTS.has(mapped) ? mapped : null;
241
+ const mapped = domInterface === undefined ? undefined : TAG_OF_DOM_INTERFACE[domInterface];
242
+ return mapped !== undefined && HTML_ELEMENTS.has(mapped) ? mapped : null;
235
243
  }
236
244
  function elementFromJsx(withoutComments) {
237
245
  const cleaned = withoutComments.replaceAll(/(["'`])(?:\\.|(?!\1)[^\\])*\1/g, '""');
238
246
  for (const match of cleaned.matchAll(JSX_TAG)) {
239
247
  const tag = match[1];
240
- if (tag && HTML_ELEMENTS.has(tag)) return tag;
248
+ if (tag && HTML_ELEMENTS.has(tag))
249
+ return tag;
241
250
  }
242
251
  return null;
243
252
  }
package/dist/index.d.ts CHANGED
@@ -1,52 +1,5 @@
1
- import { Preset } from './presets.js';
2
- export { PRESETS, PresetName, RENAMED_TO, rulesOfPreset } from './presets.js';
3
-
4
- /**
5
- * The file a rule says MUST fire it, given the options it was handed.
6
- *
7
- * `requireOption` closed one hole: an enabled rule with no option reports that, once a run,
8
- * instead of reading as a clean tree. It leaves the next one open. A rule CONFIGURED with a repo's own
9
- * vocabulary — its own brand, `packages/workflows/src/`, `@repo/db` — cannot be exercised by a corpus
10
- * that ships fixtures saying `acme` and `corpus/workflows/`, so "fires nowhere" is what an
11
- * adoption's doctor reports about a rule the repo is enforcing perfectly well. Both consumers filed
12
- * exactly that on 2026-08-30, and both were right about the fact and wrong about whose defect it is.
13
- *
14
- * A probe is the answer the rule itself can give: hand it the options and it writes the smallest
15
- * source that must fire it under THOSE options, at a path that lands where it looks. It is a claim,
16
- * so it is tested through the real binary — a probe that does not fire is a rule that cannot be
17
- * exercised, and the honest thing then is to say so rather than to widen the probe until it does.
18
- */
19
- type Probe = {
20
- /** Repo-root-relative, `/`-separated. It must satisfy every PATH option the rule reads. */
21
- path: string;
22
- source: string;
23
- };
24
- /**
25
- * A probe that needs a TREE rather than a file.
26
- *
27
- * A rule that reads a sibling off disk — a registry, a schema's twin — cannot be exercised by one
28
- * file however right its source is: `no-unregistered-plugin-dir` returns silently when the registry
29
- * its options name is not there, so the single-file probe fired nothing and every consumer
30
- * enforcing the rule over a real registry read as a permanent FAIL. The answer is not a widened
31
- * probe, which would be the rule claiming evidence it does not have; it is a probe that may declare
32
- * the sibling too, and a reader that mounts all of them.
33
- */
34
- type ProbeTree = {
35
- files: readonly Probe[];
36
- };
37
- type ProbeFn = (options: readonly unknown[]) => Probe | ProbeTree;
38
-
39
- type RetiredRule = Rule & {
40
- meta: Rule['meta'] & {
41
- retired: {
42
- reason: string;
43
- since: string;
44
- };
45
- };
46
- };
47
- declare const RETIRED_RULES: Record<'document-sagas-are-generic' | 'documents-share-one-table', RetiredRule>;
48
-
49
- type Rule = {
1
+ import type { ProbeFn } from './rules/lib/probe.js';
2
+ export type Rule = {
50
3
  create: (context: never) => Record<string, unknown>;
51
4
  fixShape: string;
52
5
  meta: {
@@ -74,8 +27,9 @@ type Rule = {
74
27
  packages: readonly string[];
75
28
  };
76
29
  };
77
- declare const rules: Record<string, Rule>;
78
-
30
+ export declare const rules: Record<string, Rule>;
31
+ export { PRESETS, RENAMED_TO, rulesOfPreset } from './presets.js';
32
+ export type { Preset, PresetName } from './presets.js';
79
33
  declare const plugin: {
80
34
  configs: {
81
35
  'backend-d1': {
@@ -96,7 +50,7 @@ declare const plugin: {
96
50
  'backend-workflows-cf': {
97
51
  rules: Record<string, "error">;
98
52
  };
99
- 'comment-ceiling': Preset;
53
+ 'comment-ceiling': import('./presets.js').Preset;
100
54
  'failure-paths': {
101
55
  rules: Record<string, "error">;
102
56
  };
@@ -131,5 +85,4 @@ declare const plugin: {
131
85
  };
132
86
  rules: Record<string, Rule>;
133
87
  };
134
-
135
- export { Preset, RETIRED_RULES, type Rule, plugin as default, rules };
88
+ export default plugin;