@geonosis/oxlint-plugin-biological-architecture 3.0.0 → 3.2.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 (239) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +48 -5
  3. package/RULES.md +201 -98
  4. package/corpus/.oxlintrc.json +6 -0
  5. package/corpus/data/bad-dynamic-orm.ts +5 -0
  6. package/corpus/data/bad-type-only-orm.ts +3 -0
  7. package/corpus/e2e/bad-list-response.spec.ts +5 -0
  8. package/corpus/e2e/bad-timeout.spec.ts +5 -0
  9. package/corpus/e2e/good-detail-response.spec.ts +5 -0
  10. package/corpus/e2e/good-state.spec.ts +5 -0
  11. package/corpus/icon-controls/bad-unnamed-icon-button.tsx +8 -0
  12. package/corpus/icon-controls/good-named-icon-button.tsx +19 -0
  13. package/corpus/manifest.json +3 -0
  14. package/corpus/tissues/bad-awaits-data.tsx +8 -0
  15. package/corpus/tissues/bad-fetches-data.tsx +7 -0
  16. package/corpus/tissues/good-takes-products.tsx +5 -0
  17. package/dist/discover-atoms.d.ts +2 -37
  18. package/dist/discover-atoms.js +1 -104
  19. package/dist/index.d.ts +3 -12
  20. package/dist/index.js +19 -174
  21. package/dist/presets.d.ts +11 -19
  22. package/dist/presets.js +89 -3
  23. package/dist/registry.d.ts +2 -0
  24. package/dist/registry.js +172 -0
  25. package/dist/rules/atom-no-deps.d.ts +1 -0
  26. package/dist/rules/atom-no-deps.js +10 -11
  27. package/dist/rules/boundary-time-is-primitive.d.ts +0 -7
  28. package/dist/rules/cell-must-be-stateful.d.ts +2 -2
  29. package/dist/rules/cell-must-be-stateful.js +24 -23
  30. package/dist/rules/cell-must-not-compose-cell.d.ts +1 -0
  31. package/dist/rules/cell-must-not-compose-cell.js +10 -3
  32. package/dist/rules/cell-no-cross-feature-organelles.d.ts +1 -0
  33. package/dist/rules/cell-no-cross-feature-organelles.js +7 -0
  34. package/dist/rules/cell-no-tissues.d.ts +1 -0
  35. package/dist/rules/cell-no-tissues.js +11 -7
  36. package/dist/rules/cells-folder-index-is-barrel.d.ts +12 -10
  37. package/dist/rules/cells-folder-index-is-barrel.js +66 -34
  38. package/dist/rules/compound-must-be-stateless.d.ts +2 -0
  39. package/dist/rules/compound-must-be-stateless.js +24 -26
  40. package/dist/rules/compound-no-stores.d.ts +1 -0
  41. package/dist/rules/compound-no-stores.js +12 -10
  42. package/dist/rules/constants-in-constants-file.d.ts +2 -8
  43. package/dist/rules/constants-in-constants-file.js +5 -6
  44. package/dist/rules/dialect-through-the-seam.d.ts +0 -13
  45. package/dist/rules/durable-body-reads-through-steps.d.ts +0 -14
  46. package/dist/rules/durable-body-reads-through-steps.js +8 -3
  47. package/dist/rules/effect-hook-naming.d.ts +9 -11
  48. package/dist/rules/effect-hook-naming.js +33 -31
  49. package/dist/rules/emit-declares-attempts.d.ts +0 -17
  50. package/dist/rules/emit-declares-attempts.js +5 -10
  51. package/dist/rules/font-roles-only.d.ts +0 -18
  52. package/dist/rules/font-roles-only.js +19 -22
  53. package/dist/rules/hermetic-e2e-no-wall-clock-waits.d.ts +53 -0
  54. package/dist/rules/hermetic-e2e-no-wall-clock-waits.js +100 -0
  55. package/dist/rules/icon-control-has-name.d.ts +53 -0
  56. package/dist/rules/icon-control-has-name.js +71 -0
  57. package/dist/rules/layer-walls.d.ts +0 -25
  58. package/dist/rules/layer-walls.js +7 -13
  59. package/dist/rules/lib/atom-map.d.ts +24 -0
  60. package/dist/rules/lib/atom-map.js +16 -0
  61. package/dist/rules/lib/cells-barrel.d.ts +0 -1
  62. package/dist/rules/lib/colors.d.ts +0 -19
  63. package/dist/rules/lib/colors.js +10 -243
  64. package/dist/rules/lib/comments.d.ts +19 -0
  65. package/dist/rules/lib/comments.js +5 -0
  66. package/dist/rules/lib/context.d.ts +0 -10
  67. package/dist/rules/lib/direction-rule.d.ts +3 -21
  68. package/dist/rules/lib/direction-rule.js +12 -3
  69. package/dist/rules/lib/doors.d.ts +2 -18
  70. package/dist/rules/lib/doors.js +79 -41
  71. package/dist/rules/lib/hooks.d.ts +2 -17
  72. package/dist/rules/lib/hooks.js +14 -9
  73. package/dist/rules/lib/imports.d.ts +2 -23
  74. package/dist/rules/lib/imports.js +7 -2
  75. package/dist/rules/lib/jsx.d.ts +31 -0
  76. package/dist/rules/lib/jsx.js +11 -0
  77. package/dist/rules/lib/landing.d.ts +0 -40
  78. package/dist/rules/lib/literal-call.d.ts +1 -0
  79. package/dist/rules/lib/literal-call.js +2 -0
  80. package/dist/rules/lib/module-text.d.ts +3 -27
  81. package/dist/rules/lib/module-text.js +19 -4
  82. package/dist/rules/lib/mutations.d.ts +0 -14
  83. package/dist/rules/lib/nodes.d.ts +1 -18
  84. package/dist/rules/lib/nodes.js +1 -0
  85. package/dist/rules/lib/objects.d.ts +2 -11
  86. package/dist/rules/lib/objects.js +21 -0
  87. package/dist/rules/lib/options.d.ts +2 -52
  88. package/dist/rules/lib/options.js +44 -18
  89. package/dist/rules/lib/package-imports.d.ts +0 -5
  90. package/dist/rules/lib/package-imports.js +4 -10
  91. package/dist/rules/lib/paths.d.ts +15 -41
  92. package/dist/rules/lib/paths.js +34 -1
  93. package/dist/rules/lib/pattern-match.d.ts +2 -12
  94. package/dist/rules/lib/pattern-match.js +5 -1
  95. package/dist/rules/lib/probe.d.ts +0 -43
  96. package/dist/rules/lib/reexports.d.ts +0 -18
  97. package/dist/rules/lib/render-tracking.d.ts +0 -8
  98. package/dist/rules/lib/shared-features.d.ts +0 -8
  99. package/dist/rules/lib/shared-features.js +2 -9
  100. package/dist/rules/lib/state-sources.d.ts +8 -0
  101. package/dist/rules/lib/state-sources.js +55 -0
  102. package/dist/rules/lib/steps.d.ts +3 -5
  103. package/dist/rules/lib/steps.js +6 -1
  104. package/dist/rules/lib/styling.d.ts +9 -42
  105. package/dist/rules/lib/styling.js +36 -10
  106. package/dist/rules/lib/tiers.d.ts +11 -24
  107. package/dist/rules/lib/tiers.js +41 -1
  108. package/dist/rules/lib/tissue-entrypoint.d.ts +0 -1
  109. package/dist/rules/lib/tissue-entrypoint.js +4 -5
  110. package/dist/rules/lib/tsconfig-paths.d.ts +0 -4
  111. package/dist/rules/lib/tsconfig-paths.js +47 -15
  112. package/dist/rules/lib/type-members.d.ts +6 -0
  113. package/dist/rules/lib/type-members.js +165 -0
  114. package/dist/rules/lib/visitors.d.ts +0 -22
  115. package/dist/rules/lib/workspace-members.d.ts +2 -0
  116. package/dist/rules/lib/workspace-members.js +115 -0
  117. package/dist/rules/list-take-without-order.js +2 -8
  118. package/dist/rules/max-comment-density.d.ts +3 -18
  119. package/dist/rules/max-comment-density.js +3 -3
  120. package/dist/rules/molecule-atoms-only.d.ts +1 -0
  121. package/dist/rules/molecule-atoms-only.js +11 -7
  122. package/dist/rules/molecule-must-compose.d.ts +3 -1
  123. package/dist/rules/molecule-must-compose.js +17 -21
  124. package/dist/rules/mutating-step-declares-retry.d.ts +2 -7
  125. package/dist/rules/mutating-step-declares-retry.js +29 -11
  126. package/dist/rules/named-when-block.d.ts +0 -2
  127. package/dist/rules/named-when-block.js +2 -8
  128. package/dist/rules/next-route-segment-is-thin-delegate.d.ts +4 -19
  129. package/dist/rules/next-route-segment-is-thin-delegate.js +47 -71
  130. package/dist/rules/no-brand-names.d.ts +0 -9
  131. package/dist/rules/no-brand-names.js +1 -1
  132. package/dist/rules/no-card-shaped-div.d.ts +4 -42
  133. package/dist/rules/no-card-shaped-div.js +12 -4
  134. package/dist/rules/no-cross-feature-stores.d.ts +1 -0
  135. package/dist/rules/no-cross-feature-stores.js +9 -5
  136. package/dist/rules/no-d1-transaction.d.ts +2 -5
  137. package/dist/rules/no-d1-transaction.js +7 -0
  138. package/dist/rules/no-date-string-compare.d.ts +2 -0
  139. package/dist/rules/no-date-string-compare.js +14 -8
  140. package/dist/rules/no-duplicate-jsx-patterns.d.ts +2 -0
  141. package/dist/rules/no-duplicate-jsx-patterns.js +16 -1
  142. package/dist/rules/no-generic-utility-package.d.ts +48 -2
  143. package/dist/rules/no-generic-utility-package.js +48 -9
  144. package/dist/rules/no-hook-in-component-disguise.d.ts +27 -13
  145. package/dist/rules/no-hook-in-component-disguise.js +38 -30
  146. package/dist/rules/no-index-count-as-exact.d.ts +0 -3
  147. package/dist/rules/no-inert-hidden-jsx.d.ts +4 -21
  148. package/dist/rules/no-inert-hidden-jsx.js +13 -12
  149. package/dist/rules/no-inline-data-in-jsx.d.ts +2 -0
  150. package/dist/rules/no-inline-data-in-jsx.js +17 -2
  151. package/dist/rules/no-invalid-feature-folders.d.ts +2 -0
  152. package/dist/rules/no-invalid-feature-folders.js +12 -4
  153. package/dist/rules/no-loader-side-effect-in-index-file.d.ts +0 -7
  154. package/dist/rules/no-logic-in-component-files.d.ts +6 -5
  155. package/dist/rules/no-logic-in-component-files.js +52 -31
  156. package/dist/rules/no-mock-db-in-integration.d.ts +0 -15
  157. package/dist/rules/no-mock-db-in-integration.js +3 -4
  158. package/dist/rules/no-orm-outside-db.d.ts +1 -0
  159. package/dist/rules/no-orm-outside-db.js +9 -7
  160. package/dist/rules/no-raw-html-atoms.d.ts +3 -22
  161. package/dist/rules/no-raw-html-atoms.js +5 -17
  162. package/dist/rules/no-raw-sql-outside-allowed.d.ts +2 -0
  163. package/dist/rules/no-raw-sql-outside-allowed.js +10 -15
  164. package/dist/rules/no-react-namespace.d.ts +2 -0
  165. package/dist/rules/no-react-namespace.js +13 -0
  166. package/dist/rules/no-renamed-html-props.d.ts +2 -0
  167. package/dist/rules/no-renamed-html-props.js +11 -2
  168. package/dist/rules/no-render-prop-reader.d.ts +4 -20
  169. package/dist/rules/no-render-prop-reader.js +13 -5
  170. package/dist/rules/no-runtime-dead-affordance.d.ts +3 -26
  171. package/dist/rules/no-runtime-dead-affordance.js +7 -20
  172. package/dist/rules/no-swallowed-catch.js +2 -8
  173. package/dist/rules/no-trivial-wrapper-component.d.ts +4 -19
  174. package/dist/rules/no-trivial-wrapper-component.js +24 -33
  175. package/dist/rules/no-ts-in-bio-folders.d.ts +2 -13
  176. package/dist/rules/no-ts-in-bio-folders.js +9 -7
  177. package/dist/rules/no-type-definitions-in-components.d.ts +2 -0
  178. package/dist/rules/no-type-definitions-in-components.js +12 -1
  179. package/dist/rules/no-unregistered-plugin-dir.d.ts +0 -41
  180. package/dist/rules/no-unregistered-plugin-dir.js +1 -9
  181. package/dist/rules/no-void-port.d.ts +2 -4
  182. package/dist/rules/no-void-port.js +7 -0
  183. package/dist/rules/organelle-dependency.d.ts +1 -0
  184. package/dist/rules/organelle-dependency.js +10 -8
  185. package/dist/rules/organelle-single-source.d.ts +2 -0
  186. package/dist/rules/organelle-single-source.js +58 -9
  187. package/dist/rules/plugin-route-namespaced.d.ts +0 -11
  188. package/dist/rules/plugin-route-namespaced.js +2 -2
  189. package/dist/rules/queries-require-org-scope.d.ts +0 -3
  190. package/dist/rules/queries-require-org-scope.js +3 -10
  191. package/dist/rules/queue-loop-is-the-library.js +3 -2
  192. package/dist/rules/route-no-inline-mutation.d.ts +1 -25
  193. package/dist/rules/route-no-inline-mutation.js +2 -7
  194. package/dist/rules/router-schema-parity.d.ts +0 -9
  195. package/dist/rules/router-schema-parity.js +5 -9
  196. package/dist/rules/service-name-not-reserved.d.ts +0 -3
  197. package/dist/rules/service-name-not-reserved.js +1 -34
  198. package/dist/rules/ssot-no-inline-facts.js +2 -5
  199. package/dist/rules/ssot-no-process-env.js +4 -12
  200. package/dist/rules/step-declares-compensation-or-none.d.ts +2 -1
  201. package/dist/rules/step-declares-compensation-or-none.js +17 -1
  202. package/dist/rules/step-opens-its-own-cell.d.ts +2 -25
  203. package/dist/rules/step-opens-its-own-cell.js +8 -13
  204. package/dist/rules/store-route-scopes-tenant-data.js +8 -26
  205. package/dist/rules/subpath-over-barrel.d.ts +2 -10
  206. package/dist/rules/subpath-over-barrel.js +48 -9
  207. package/dist/rules/subscriber-declares-id.d.ts +0 -2
  208. package/dist/rules/subscriber-declares-id.js +2 -8
  209. package/dist/rules/tables-declare-their-plane.d.ts +0 -2
  210. package/dist/rules/tables-declare-their-plane.js +4 -10
  211. package/dist/rules/tenant-tables-carry-org-id.d.ts +1 -4
  212. package/dist/rules/tenant-tables-carry-org-id.js +5 -12
  213. package/dist/rules/test-no-clock-polling-for-promise-flips.d.ts +2 -0
  214. package/dist/rules/test-no-clock-polling-for-promise-flips.js +18 -1
  215. package/dist/rules/time-through-the-door.d.ts +0 -24
  216. package/dist/rules/time-through-the-door.js +5 -5
  217. package/dist/rules/tissue-must-compose.d.ts +4 -2
  218. package/dist/rules/tissue-must-compose.js +25 -20
  219. package/dist/rules/tissue-no-data-props.d.ts +56 -0
  220. package/dist/rules/tissue-no-data-props.js +114 -32
  221. package/dist/rules/tissue-no-fetch.d.ts +26 -0
  222. package/dist/rules/tissue-no-fetch.js +57 -0
  223. package/dist/rules/tissue-no-hooks.d.ts +20 -22
  224. package/dist/rules/tissue-no-hooks.js +22 -4
  225. package/dist/rules/tissue-no-organelles.d.ts +1 -0
  226. package/dist/rules/tissue-no-organelles.js +9 -1
  227. package/dist/rules/tissue-no-stores.d.ts +1 -0
  228. package/dist/rules/tissue-no-stores.js +9 -1
  229. package/dist/rules/todo-names-its-plan.d.ts +1 -28
  230. package/dist/rules/todo-names-its-plan.js +2 -2
  231. package/dist/rules/tokens-only-colors.d.ts +2 -37
  232. package/dist/rules/tokens-only-colors.js +33 -18
  233. package/dist/rules/unique-query-step-name.d.ts +0 -7
  234. package/dist/rules/unique-query-step-name.js +6 -10
  235. package/dist/rules/worker-handles-are-scoped.d.ts +11 -8
  236. package/dist/rules/worker-handles-are-scoped.js +12 -5
  237. package/dist/rules/zustand-v5-best-practices.d.ts +8 -18
  238. package/dist/rules/zustand-v5-best-practices.js +32 -56
  239. package/package.json +2 -2
@@ -0,0 +1,172 @@
1
+ // src/registry.ts
2
+ import atomNoDeps from "./rules/atom-no-deps.js";
3
+ import boundaryTimeIsPrimitive from "./rules/boundary-time-is-primitive.js";
4
+ import cellMustBeStateful from "./rules/cell-must-be-stateful.js";
5
+ import cellMustNotComposeCell from "./rules/cell-must-not-compose-cell.js";
6
+ import cellNoCrossFeatureOrganelles from "./rules/cell-no-cross-feature-organelles.js";
7
+ import cellNoTissues from "./rules/cell-no-tissues.js";
8
+ import cellsFolderIndexIsBarrel from "./rules/cells-folder-index-is-barrel.js";
9
+ import compoundMustBeStateless from "./rules/compound-must-be-stateless.js";
10
+ import compoundNoStores from "./rules/compound-no-stores.js";
11
+ import constantsInConstantsFile from "./rules/constants-in-constants-file.js";
12
+ import dialectThroughTheSeam from "./rules/dialect-through-the-seam.js";
13
+ import durableBodyReadsThroughSteps from "./rules/durable-body-reads-through-steps.js";
14
+ import effectHookNaming from "./rules/effect-hook-naming.js";
15
+ import emitDeclaresAttempts from "./rules/emit-declares-attempts.js";
16
+ import fontRolesOnly from "./rules/font-roles-only.js";
17
+ import hermeticE2eNoWallClockWaits from "./rules/hermetic-e2e-no-wall-clock-waits.js";
18
+ import iconControlHasName from "./rules/icon-control-has-name.js";
19
+ import layerWalls from "./rules/layer-walls.js";
20
+ import listTakeWithoutOrder from "./rules/list-take-without-order.js";
21
+ import maxCommentDensity from "./rules/max-comment-density.js";
22
+ import moleculeAtomsOnly from "./rules/molecule-atoms-only.js";
23
+ import moleculeMustCompose from "./rules/molecule-must-compose.js";
24
+ import mutatingStepDeclaresRetry from "./rules/mutating-step-declares-retry.js";
25
+ import namedWhenBlock from "./rules/named-when-block.js";
26
+ import nextRouteSegmentIsThinDelegate from "./rules/next-route-segment-is-thin-delegate.js";
27
+ import noBrandNames from "./rules/no-brand-names.js";
28
+ import noCardShapedDiv from "./rules/no-card-shaped-div.js";
29
+ import noCrossFeatureStores from "./rules/no-cross-feature-stores.js";
30
+ import noD1Transaction from "./rules/no-d1-transaction.js";
31
+ import noDateStringCompare from "./rules/no-date-string-compare.js";
32
+ import noDuplicateJsxPatterns from "./rules/no-duplicate-jsx-patterns.js";
33
+ import noGenericUtilityPackage from "./rules/no-generic-utility-package.js";
34
+ import noHookInComponentDisguise from "./rules/no-hook-in-component-disguise.js";
35
+ import noIndexCountAsExact from "./rules/no-index-count-as-exact.js";
36
+ import noInertHiddenJsx from "./rules/no-inert-hidden-jsx.js";
37
+ import noInlineDataInJsx from "./rules/no-inline-data-in-jsx.js";
38
+ import noInvalidFeatureFolders from "./rules/no-invalid-feature-folders.js";
39
+ import noLoaderSideEffectInIndexFile from "./rules/no-loader-side-effect-in-index-file.js";
40
+ import noLogicInComponentFiles from "./rules/no-logic-in-component-files.js";
41
+ import noMockDbInIntegration from "./rules/no-mock-db-in-integration.js";
42
+ import noOrmOutsideDb from "./rules/no-orm-outside-db.js";
43
+ import noRawHtmlAtoms from "./rules/no-raw-html-atoms.js";
44
+ import noRawSqlOutsideAllowed from "./rules/no-raw-sql-outside-allowed.js";
45
+ import noReactNamespace from "./rules/no-react-namespace.js";
46
+ import noRenamedHtmlProps from "./rules/no-renamed-html-props.js";
47
+ import noRenderPropReader from "./rules/no-render-prop-reader.js";
48
+ import noRuntimeDeadAffordance from "./rules/no-runtime-dead-affordance.js";
49
+ import noSwallowedCatch from "./rules/no-swallowed-catch.js";
50
+ import noTrivialWrapperComponent from "./rules/no-trivial-wrapper-component.js";
51
+ import noTsInBioFolders from "./rules/no-ts-in-bio-folders.js";
52
+ import noTypeDefinitionsInComponents from "./rules/no-type-definitions-in-components.js";
53
+ import noUnregisteredPluginDir from "./rules/no-unregistered-plugin-dir.js";
54
+ import noVoidPort from "./rules/no-void-port.js";
55
+ import organelleDependency from "./rules/organelle-dependency.js";
56
+ import organelleSingleSource from "./rules/organelle-single-source.js";
57
+ import pluginRouteNamespaced from "./rules/plugin-route-namespaced.js";
58
+ import queriesRequireOrgScope from "./rules/queries-require-org-scope.js";
59
+ import queueLoopIsTheLibrary from "./rules/queue-loop-is-the-library.js";
60
+ import routeNoInlineMutation from "./rules/route-no-inline-mutation.js";
61
+ import routerSchemaParity from "./rules/router-schema-parity.js";
62
+ import serviceNameNotReserved from "./rules/service-name-not-reserved.js";
63
+ import ssotNoInlineFacts from "./rules/ssot-no-inline-facts.js";
64
+ import ssotNoProcessEnv from "./rules/ssot-no-process-env.js";
65
+ import stepDeclaresCompensationOrNone from "./rules/step-declares-compensation-or-none.js";
66
+ import stepOpensItsOwnCell from "./rules/step-opens-its-own-cell.js";
67
+ import storeRouteScopesTenantData from "./rules/store-route-scopes-tenant-data.js";
68
+ import subpathOverBarrel from "./rules/subpath-over-barrel.js";
69
+ import subscriberDeclaresId from "./rules/subscriber-declares-id.js";
70
+ import tablesDeclareTheirPlane from "./rules/tables-declare-their-plane.js";
71
+ import tenantTablesCarryOrgId from "./rules/tenant-tables-carry-org-id.js";
72
+ import testNoClockPollingForPromiseFlips from "./rules/test-no-clock-polling-for-promise-flips.js";
73
+ import timeThroughTheDoor from "./rules/time-through-the-door.js";
74
+ import tissueMustCompose from "./rules/tissue-must-compose.js";
75
+ import tissueNoDataProps from "./rules/tissue-no-data-props.js";
76
+ import tissueNoFetch from "./rules/tissue-no-fetch.js";
77
+ import tissueNoHooks from "./rules/tissue-no-hooks.js";
78
+ import tissueNoOrganelles from "./rules/tissue-no-organelles.js";
79
+ import tissueNoStores from "./rules/tissue-no-stores.js";
80
+ import todoNamesItsPlan from "./rules/todo-names-its-plan.js";
81
+ import tokensOnlyColors from "./rules/tokens-only-colors.js";
82
+ import uniqueQueryStepName from "./rules/unique-query-step-name.js";
83
+ import workerHandlesAreScoped from "./rules/worker-handles-are-scoped.js";
84
+ import zustandV5BestPractices from "./rules/zustand-v5-best-practices.js";
85
+ var registered = {
86
+ "atom-no-deps": atomNoDeps,
87
+ "boundary-time-is-primitive": boundaryTimeIsPrimitive,
88
+ "cell-must-be-stateful": cellMustBeStateful,
89
+ "cell-must-not-compose-cell": cellMustNotComposeCell,
90
+ "cell-no-cross-feature-organelles": cellNoCrossFeatureOrganelles,
91
+ "cell-no-tissues": cellNoTissues,
92
+ "cells-folder-index-is-barrel": cellsFolderIndexIsBarrel,
93
+ "compound-must-be-stateless": compoundMustBeStateless,
94
+ "compound-no-stores": compoundNoStores,
95
+ "constants-in-constants-file": constantsInConstantsFile,
96
+ "dialect-through-the-seam": dialectThroughTheSeam,
97
+ "durable-body-reads-through-steps": durableBodyReadsThroughSteps,
98
+ "effect-hook-naming": effectHookNaming,
99
+ "emit-declares-attempts": emitDeclaresAttempts,
100
+ "font-roles-only": fontRolesOnly,
101
+ "hermetic-e2e-no-wall-clock-waits": hermeticE2eNoWallClockWaits,
102
+ "icon-control-has-name": iconControlHasName,
103
+ "layer-walls": layerWalls,
104
+ "list-take-without-order": listTakeWithoutOrder,
105
+ "max-comment-density": maxCommentDensity,
106
+ "molecule-atoms-only": moleculeAtomsOnly,
107
+ "molecule-must-compose": moleculeMustCompose,
108
+ "mutating-step-declares-retry": mutatingStepDeclaresRetry,
109
+ "named-when-block": namedWhenBlock,
110
+ "next-route-segment-is-thin-delegate": nextRouteSegmentIsThinDelegate,
111
+ "no-brand-names": noBrandNames,
112
+ "no-card-shaped-div": noCardShapedDiv,
113
+ "no-cross-feature-stores": noCrossFeatureStores,
114
+ "no-d1-transaction": noD1Transaction,
115
+ "no-date-string-compare": noDateStringCompare,
116
+ "no-duplicate-jsx-patterns": noDuplicateJsxPatterns,
117
+ "no-generic-utility-package": noGenericUtilityPackage,
118
+ "no-hook-in-component-disguise": noHookInComponentDisguise,
119
+ "no-index-count-as-exact": noIndexCountAsExact,
120
+ "no-inert-hidden-jsx": noInertHiddenJsx,
121
+ "no-inline-data-in-jsx": noInlineDataInJsx,
122
+ "no-invalid-feature-folders": noInvalidFeatureFolders,
123
+ "no-loader-side-effect-in-index-file": noLoaderSideEffectInIndexFile,
124
+ "no-logic-in-component-files": noLogicInComponentFiles,
125
+ "no-mock-db-in-integration": noMockDbInIntegration,
126
+ "no-orm-outside-db": noOrmOutsideDb,
127
+ "no-raw-html-atoms": noRawHtmlAtoms,
128
+ "no-raw-sql-outside-allowed": noRawSqlOutsideAllowed,
129
+ "no-react-namespace": noReactNamespace,
130
+ "no-renamed-html-props": noRenamedHtmlProps,
131
+ "no-render-prop-reader": noRenderPropReader,
132
+ "no-runtime-dead-affordance": noRuntimeDeadAffordance,
133
+ "no-swallowed-catch": noSwallowedCatch,
134
+ "no-trivial-wrapper-component": noTrivialWrapperComponent,
135
+ "no-ts-in-bio-folders": noTsInBioFolders,
136
+ "no-type-definitions-in-components": noTypeDefinitionsInComponents,
137
+ "no-unregistered-plugin-dir": noUnregisteredPluginDir,
138
+ "no-void-port": noVoidPort,
139
+ "organelle-dependency": organelleDependency,
140
+ "organelle-single-source": organelleSingleSource,
141
+ "plugin-route-namespaced": pluginRouteNamespaced,
142
+ "queries-require-org-scope": queriesRequireOrgScope,
143
+ "queue-loop-is-the-library": queueLoopIsTheLibrary,
144
+ "route-no-inline-mutation": routeNoInlineMutation,
145
+ "router-schema-parity": routerSchemaParity,
146
+ "service-name-not-reserved": serviceNameNotReserved,
147
+ "ssot-no-inline-facts": ssotNoInlineFacts,
148
+ "ssot-no-process-env": ssotNoProcessEnv,
149
+ "step-declares-compensation-or-none": stepDeclaresCompensationOrNone,
150
+ "step-opens-its-own-cell": stepOpensItsOwnCell,
151
+ "store-route-scopes-tenant-data": storeRouteScopesTenantData,
152
+ "subpath-over-barrel": subpathOverBarrel,
153
+ "subscriber-declares-id": subscriberDeclaresId,
154
+ "tables-declare-their-plane": tablesDeclareTheirPlane,
155
+ "tenant-tables-carry-org-id": tenantTablesCarryOrgId,
156
+ "test-no-clock-polling-for-promise-flips": testNoClockPollingForPromiseFlips,
157
+ "time-through-the-door": timeThroughTheDoor,
158
+ "tissue-must-compose": tissueMustCompose,
159
+ "tissue-no-data-props": tissueNoDataProps,
160
+ "tissue-no-fetch": tissueNoFetch,
161
+ "tissue-no-hooks": tissueNoHooks,
162
+ "tissue-no-organelles": tissueNoOrganelles,
163
+ "tissue-no-stores": tissueNoStores,
164
+ "todo-names-its-plan": todoNamesItsPlan,
165
+ "tokens-only-colors": tokensOnlyColors,
166
+ "unique-query-step-name": uniqueQueryStepName,
167
+ "worker-handles-are-scoped": workerHandlesAreScoped,
168
+ "zustand-v5-best-practices": zustandV5BestPractices
169
+ };
170
+ export {
171
+ registered
172
+ };
@@ -9,6 +9,7 @@ declare const atomNoDeps: {
9
9
  }) => void;
10
10
  }): import('./lib/visitors.js').Visitor;
11
11
  fixShape: string;
12
+ probe?: ((options: readonly unknown[]) => import('./lib/probe.js').Probe | import('./lib/probe.js').ProbeTree) | undefined;
12
13
  meta: {
13
14
  docs: {
14
15
  description: string;
@@ -1,25 +1,24 @@
1
1
  // src/rules/atom-no-deps.ts
2
2
  import { directionRule } from "./lib/direction-rule.js";
3
- var FORBIDDEN_PATTERNS = [
4
- /(?:^|\/)molecules\//,
5
- /(?:^|\/)compounds\//,
6
- /(?:^|\/)organelles\//,
7
- /(?:^|\/)cells\//,
8
- /(?:^|\/)tissues\//,
9
- /(?:^|\/)stores\//,
10
- /(?:^|[/@])domains(?:\/|$)/,
11
- /\/app\//
12
- ];
3
+ import { inTiersAbove, APP_FOLDER, STORES_FOLDER } from "./lib/tiers.js";
4
+ var FORBIDDEN_PATTERNS = [STORES_FOLDER, /(?:^|[/@])domains(?:\/|$)/, APP_FOLDER];
13
5
  var atomNoDeps = directionRule({
14
6
  description: "Atoms cannot import from molecules, compounds, organelles, cells, stores, or domains",
15
7
  fixShape: `Raw \`<button>\`, \`<input>\`, or a \`<div>\` with border + background in levels 2-6 belongs in an atom.
16
8
  An atom imports nothing above itself — no molecule, compound, organelle, cell, tissue, store or domain,
17
9
  and that includes \`export … from\`. If an atom needs a shared constant, the constant moves down to the atom
18
10
  tier or into a plain \`lib/\` module, never the other way round.`,
19
- forbidden: (target) => FORBIDDEN_PATTERNS.some((pattern) => pattern.test(target.path)),
11
+ forbidden: (target) => inTiersAbove(target.path, "atoms") || FORBIDDEN_PATTERNS.some((pattern) => pattern.test(target.path)),
20
12
  messages: {
21
13
  forbidden: "Atoms cannot import from {{source}}. Atoms are the lowest level and must not depend on higher-level components."
22
14
  },
15
+ probe: () => ({
16
+ path: "src/atoms/geonosis-probe.tsx",
17
+ source: `import { Up } from '../molecules/geonosis-up'
18
+
19
+ export const GeonosisProbe = Up
20
+ `
21
+ }),
23
22
  scope: "atoms",
24
23
  typeOnly: "visit"
25
24
  });
@@ -1,9 +1,7 @@
1
1
  import { type RuleContextWithOptions } from './lib/context.js';
2
2
  import { type Probe } from './lib/probe.js';
3
3
  interface Options {
4
- /** The modules that may name these types in an exported signature, each written out in full. */
5
4
  doors?: string[];
6
- /** The type names that must not cross an exported boundary. A namespace covers its members. */
7
5
  types?: string[];
8
6
  }
9
7
  declare const boundaryTimeIsPrimitive: {
@@ -46,11 +44,6 @@ declare const boundaryTimeIsPrimitive: {
46
44
  }[];
47
45
  type: 'problem';
48
46
  };
49
- /**
50
- * A file that is not one of the declared doors, exporting the repo's own first forbidden type.
51
- * `String(at)` rather than a second annotation: one finding is the claim, and a probe that fired
52
- * twice would pass a count nobody asked for.
53
- */
54
47
  probe(options: readonly unknown[]): Probe;
55
48
  };
56
49
  export default boundaryTimeIsPrimitive;
@@ -1,11 +1,10 @@
1
1
  import { type RuleContext } from './lib/context.js';
2
+ import { type Probe } from './lib/probe.js';
2
3
  declare const cellMustBeStateful: {
3
4
  create(context: RuleContext): {
4
5
  Program?: undefined;
5
- 'Program:exit'?: undefined;
6
6
  } | {
7
7
  Program(node: unknown): void;
8
- 'Program:exit'(): void;
9
8
  };
10
9
  fixShape: string;
11
10
  meta: {
@@ -18,5 +17,6 @@ declare const cellMustBeStateful: {
18
17
  schema: never[];
19
18
  type: 'problem';
20
19
  };
20
+ probe(): Probe;
21
21
  };
22
22
  export default cellMustBeStateful;
@@ -1,7 +1,8 @@
1
1
  // src/rules/cell-must-be-stateful.ts
2
2
  import * as fs from "node:fs";
3
- import { normalise } from "./lib/paths.js";
3
+ import { normalise, fileOf } from "./lib/paths.js";
4
4
  import { launderedHomesOf } from "./lib/reexports.js";
5
+ import { CELL_PRIVATE_SIBLING, inTier } from "./lib/tiers.js";
5
6
  var STATE_SIGNATURE = /\buse[A-Z]\w*\s*\(|from\s+['"][^'"]*\/organelles(?:\/|['"])|from\s+['"][^'"]*\/stores?(?:\/|['"])|createContext\s*\(/;
6
7
  var SIBLING_SUFFIXES = [
7
8
  ".tsx",
@@ -15,41 +16,32 @@ var SIBLING_SUFFIXES = [
15
16
  ".data.tsx",
16
17
  ".steps.tsx"
17
18
  ];
18
- var PRIVATE_OR_NON_ENTRY = /\.(parts|sections|layouts|types|icons|sidebar|summary|form|data|steps|stories|test|spec)\.tsx$/;
19
- function familyHasState(mainFile) {
20
- const stem = mainFile.replace(/\.tsx$/, "");
21
- for (const file of [mainFile, ...SIBLING_SUFFIXES.map((suffix) => stem + suffix)]) {
22
- try {
23
- if (fs.existsSync(file) && STATE_SIGNATURE.test(fs.readFileSync(file, "utf8"))) {
24
- return true;
25
- }
26
- } catch {}
19
+ var readable = (file) => {
20
+ try {
21
+ return fs.readFileSync(file, "utf8");
22
+ } catch {
23
+ return "";
27
24
  }
28
- return false;
29
- }
25
+ };
26
+ var familyHasState = (mainFile) => {
27
+ const stem = mainFile.replace(/\.tsx$/, "");
28
+ return [mainFile, ...SIBLING_SUFFIXES.map((suffix) => stem + suffix)].some((file) => STATE_SIGNATURE.test(readable(file)));
29
+ };
30
30
  var cellMustBeStateful = {
31
31
  create(context) {
32
32
  const normalized = normalise(context.filename);
33
- const base = normalized.split("/").pop() || "";
34
- const isCellEntrypoint = /(?:^|\/)cells\//.test(normalized) && base.endsWith(".tsx") && base !== "index.tsx" && !PRIVATE_OR_NON_ENTRY.test(base);
33
+ const base = fileOf(normalized);
34
+ const isCellEntrypoint = inTier(normalized, "cells") && base.endsWith(".tsx") && base !== "index.tsx" && !CELL_PRIVATE_SIBLING.test(base);
35
35
  if (!isCellEntrypoint)
36
36
  return {};
37
37
  const laundered = launderedHomesOf(context.filename);
38
38
  if (laundered !== undefined && laundered.length === 0)
39
39
  return {};
40
40
  const judged = laundered ?? [normalized];
41
- let programNode = null;
42
41
  return {
43
42
  Program(node) {
44
- programNode = node;
45
- },
46
- "Program:exit"() {
47
43
  if (!judged.every((file) => familyHasState(normalise(file)))) {
48
- context.report({
49
- data: { file: base },
50
- messageId: "shouldBeCompound",
51
- node: programNode
52
- });
44
+ context.report({ data: { file: base }, messageId: "shouldBeCompound", node });
53
45
  }
54
46
  }
55
47
  };
@@ -67,6 +59,15 @@ stateful, put the store read or the organelle in it rather than taking the data
67
59
  },
68
60
  schema: [],
69
61
  type: "problem"
62
+ },
63
+ probe() {
64
+ return {
65
+ path: "src/cells/geonosis-probe.tsx",
66
+ source: `export function GeonosisProbe({ label }: { label: string }) {
67
+ return <div>{label}</div>
68
+ }
69
+ `
70
+ };
70
71
  }
71
72
  };
72
73
  var cell_must_be_stateful_default = cellMustBeStateful;
@@ -9,6 +9,7 @@ declare const cellMustNotComposeCell: {
9
9
  }) => void;
10
10
  }): import('./lib/visitors.js').Visitor;
11
11
  fixShape: string;
12
+ probe?: ((options: readonly unknown[]) => import('./lib/probe.js').Probe | import('./lib/probe.js').ProbeTree) | undefined;
12
13
  meta: {
13
14
  docs: {
14
15
  description: string;
@@ -1,8 +1,8 @@
1
1
  // src/rules/cell-must-not-compose-cell.ts
2
2
  import { isCellsBarrel } from "./lib/cells-barrel.js";
3
3
  import { directionRule } from "./lib/direction-rule.js";
4
+ import { inTier } from "./lib/tiers.js";
4
5
  var cellStem = (filePath) => filePath.replace(/\.[jt]sx?$/, "").replace(/\.(parts|sections|summary|layouts|icons|types|hooks|utils|context|store|sidebar|data|config)$/i, "");
5
- var IN_CELLS = /(?:^|\/)cells\//;
6
6
  var cellMustNotComposeCell = directionRule({
7
7
  data: (target, importer) => ({ currentFile: importer.file, importedFile: target.file }),
8
8
  description: "Cells must not import from any other cell anywhere in the repo. No same-feature exception, no shared/document/charts exception. Cells compose only atoms, molecules, compounds, and organelles. Type-only imports are allowed.",
@@ -17,11 +17,18 @@ the other. A stateless adapter between cells is a tissue — it may take the dat
17
17
  component (\`invoice-editor.parts.tsx\` from \`invoice-editor.tsx\`) are one cell and are fine. The
18
18
  barrels \`cells/index.ts\`, \`cells/dynamic.ts\` and \`cells/dynamic.tsx\` are exempt — re-exporting
19
19
  siblings is the shape \`cells-folder-index-is-barrel\` requires of them.`,
20
- forbidden: (target, importer) => IN_CELLS.test(target.path) && cellStem(target.file) !== cellStem(importer.file),
20
+ forbidden: (target, importer) => inTier(target.path, "cells") && cellStem(target.file) !== cellStem(importer.file),
21
21
  messages: {
22
22
  forbidden: 'Cell "{{currentFile}}" imports from another cell "{{importedFile}}". Cells never compose other cells. Decompose: if this is arrangement, move the parent to tissues/. If the import is a stateless display, move the child to compounds/. If the child is a store adapter, move it to organelles/.'
23
23
  },
24
- scope: (importer) => IN_CELLS.test(importer.path) && !isCellsBarrel(importer.path)
24
+ probe: () => ({
25
+ path: "src/cells/geonosis-probe.tsx",
26
+ source: `import { Other } from './geonosis-other'
27
+
28
+ export const GeonosisProbe = Other
29
+ `
30
+ }),
31
+ scope: (importer) => inTier(importer.path, "cells") && !isCellsBarrel(importer.path)
25
32
  });
26
33
  var cell_must_not_compose_cell_default = cellMustNotComposeCell;
27
34
  export {
@@ -9,6 +9,7 @@ declare const cellNoCrossFeatureOrganelles: {
9
9
  }) => void;
10
10
  }): import('./lib/visitors.js').Visitor;
11
11
  fixShape: string;
12
+ probe?: ((options: readonly unknown[]) => import('./lib/probe.js').Probe | import('./lib/probe.js').ProbeTree) | undefined;
12
13
  meta: {
13
14
  docs: {
14
15
  description: string;
@@ -28,6 +28,13 @@ aliased sources are judged alike: \`../../billing/organelles/totals\` lands wher
28
28
  forbidden: `Cell "{{file}}" in feature "{{ownFeature}}" imports "{{source}}", an organelle of feature "{{importedFeature}}". A cell hosts its own feature's organelles; another feature's state arrives as props from the tissue above. Only features/{{ownFeature}}/organelles/* and the shared features are allowed here.`
29
29
  },
30
30
  optionsFrom: (raw) => raw ?? {},
31
+ probe: () => ({
32
+ path: "src/features/geonosis/cells/geonosis-probe.tsx",
33
+ source: `import { other } from '@/features/geonosis-neighbour/organelles/other'
34
+
35
+ export const GeonosisProbe = other
36
+ `
37
+ }),
31
38
  scope: "cells",
32
39
  schema: SHARED_FEATURES_SCHEMA
33
40
  });
@@ -9,6 +9,7 @@ declare const cellNoTissues: {
9
9
  }) => void;
10
10
  }): import('./lib/visitors.js').Visitor;
11
11
  fixShape: string;
12
+ probe?: ((options: readonly unknown[]) => import('./lib/probe.js').Probe | import('./lib/probe.js').ProbeTree) | undefined;
12
13
  meta: {
13
14
  docs: {
14
15
  description: string;
@@ -1,20 +1,24 @@
1
1
  // src/rules/cell-no-tissues.ts
2
2
  import { directionRule } from "./lib/direction-rule.js";
3
- var HIGHER_LEVEL_PATTERNS = [
4
- /(?:^|\/)(?:features\/[^/]+\/)?tissues\//,
5
- /(?:^|\/)(?:features\/[^/]+\/)?organs\//,
6
- /(?:^|\/)layouts\//,
7
- /(?:^|\/)app\//
8
- ];
3
+ import { matchesAny } from "./lib/paths.js";
4
+ import { APP_FOLDER, inOrgans, inTier, LAYOUTS_FOLDER } from "./lib/tiers.js";
5
+ var OTHER_HIGHER_LEVEL_FOLDERS = [LAYOUTS_FOLDER, APP_FOLDER];
9
6
  var cellNoTissues = directionRule({
10
7
  description: "Cells cannot import tissues, organs, or app route files. Direction is wrong: tissues compose cells (not the reverse), and organs compose tissues and cells.",
11
8
  fixShape: `A cell cannot import a tissue, an organ, a layout or an app route — that is the direction
12
9
  inverted. If a cell needs a layout around it, take the layout as \`children\` and let a tissue arrange
13
10
  both. Type-only imports are exempt; \`export … from\` is not.`,
14
- forbidden: (target) => HIGHER_LEVEL_PATTERNS.some((pattern) => pattern.test(target.path)),
11
+ forbidden: (target) => inTier(target.path, "tissues") || inOrgans(target.path) || matchesAny(OTHER_HIGHER_LEVEL_FOLDERS, target.path),
15
12
  messages: {
16
13
  forbidden: 'Cell "{{file}}" cannot import higher-level component "{{source}}". Direction is wrong: tissues/organs compose cells, not the reverse. If this cell needs to render a layout-like wrapper, the wrapper should be a compound, or this cell should be promoted.'
17
14
  },
15
+ probe: () => ({
16
+ path: "src/cells/geonosis-probe.tsx",
17
+ source: `import { Up } from '../tissues/geonosis-up'
18
+
19
+ export const GeonosisProbe = Up
20
+ `
21
+ }),
18
22
  scope: "cells"
19
23
  });
20
24
  var cell_no_tissues_default = cellNoTissues;
@@ -1,24 +1,24 @@
1
1
  import { type RuleContext } from './lib/context.js';
2
- interface ProgramNode {
3
- body: Statement[];
4
- loc?: unknown;
5
- type: 'Program';
6
- }
2
+ import { type Probe } from './lib/probe.js';
7
3
  interface Statement {
8
- declaration?: unknown;
9
4
  importKind?: string;
10
- loc?: unknown;
11
5
  source?: {
12
- value: string;
6
+ value?: unknown;
13
7
  } | null;
14
- specifiers?: unknown[];
8
+ specifiers?: {
9
+ exported?: {
10
+ name?: unknown;
11
+ };
12
+ }[];
15
13
  type: string;
16
14
  }
17
15
  declare const cellsFolderIndexIsBarrel: {
18
16
  create(context: RuleContext): {
19
17
  Program?: undefined;
20
18
  } | {
21
- Program(node: ProgramNode): void;
19
+ Program(node: {
20
+ body: Statement[];
21
+ }): void;
22
22
  };
23
23
  fixShape: string;
24
24
  meta: {
@@ -26,10 +26,12 @@ declare const cellsFolderIndexIsBarrel: {
26
26
  description: string;
27
27
  };
28
28
  messages: {
29
+ organelleWearingCells: string;
29
30
  notBarrel: string;
30
31
  };
31
32
  schema: never[];
32
33
  type: 'problem';
33
34
  };
35
+ probe(): Probe;
34
36
  };
35
37
  export default cellsFolderIndexIsBarrel;
@@ -1,46 +1,68 @@
1
1
  // src/rules/cells-folder-index-is-barrel.ts
2
2
  import { isCellsBarrel } from "./lib/cells-barrel.js";
3
- import { normalise } from "./lib/paths.js";
4
- function describeStatement(stmt) {
5
- switch (stmt.type) {
6
- case "ClassDeclaration":
7
- return "a class declaration";
8
- case "ExportDefaultDeclaration":
9
- return "a default export declaration";
10
- case "ExportNamedDeclaration":
11
- return "a named export declaration (not a re-export)";
12
- case "ExpressionStatement":
13
- return "a top-level expression statement";
14
- case "FunctionDeclaration":
15
- return "a function declaration";
16
- case "ImportDeclaration":
17
- return "a side-effect import";
18
- case "VariableDeclaration":
19
- return "a variable declaration";
20
- default:
21
- return `a ${stmt.type} statement`;
22
- }
23
- }
3
+ import { landingsOf } from "./lib/landing.js";
4
+ import { normalise, fileOf } from "./lib/paths.js";
5
+ import { inTier } from "./lib/tiers.js";
6
+ var DESCRIPTIONS = {
7
+ ClassDeclaration: "a class declaration",
8
+ ExportDefaultDeclaration: "a default export declaration",
9
+ ExportNamedDeclaration: "a named export declaration (not a re-export)",
10
+ ExpressionStatement: "a top-level expression statement",
11
+ FunctionDeclaration: "a function declaration",
12
+ ImportDeclaration: "a side-effect import",
13
+ VariableDeclaration: "a variable declaration"
14
+ };
15
+ var reexportedFrom = (statement) => (statement.type === "ExportNamedDeclaration" || statement.type === "ExportAllDeclaration") && typeof statement.source?.value === "string" ? statement.source.value : undefined;
16
+ var namesOf = (statement) => statement.type === "ExportAllDeclaration" ? [] : (statement.specifiers ?? []).flatMap((one) => typeof one.exported?.name === "string" ? [one.exported.name] : []);
17
+ var landsInOrganelles = (filename, statement, source) => {
18
+ const landed = landingsOf(filename, source, namesOf(statement));
19
+ if (landed.door === undefined)
20
+ return inTier(`${source}/`, "organelles");
21
+ return [landed.door, ...landed.homes.values()].some((file) => inTier(file, "organelles"));
22
+ };
24
23
  var cellsFolderIndexIsBarrel = {
25
24
  create(context) {
26
25
  const filename = context.filename;
27
26
  const normalized = normalise(filename);
28
- if (!isCellsBarrel(normalized))
29
- return {};
30
- const shortName = normalized.split("/").pop() || normalized;
27
+ const shortName = fileOf(normalized);
28
+ if (!isCellsBarrel(normalized)) {
29
+ if (!inTier(normalized, "cells"))
30
+ return {};
31
+ return {
32
+ Program(node) {
33
+ const sources = node.body.map(reexportedFrom);
34
+ if (sources.length === 0 || sources.some((one) => one === undefined))
35
+ return;
36
+ const names = node.body.flatMap(namesOf);
37
+ const organelle = node.body.find((statement) => landsInOrganelles(filename, statement, reexportedFrom(statement) ?? ""));
38
+ if (organelle === undefined)
39
+ return;
40
+ context.report({
41
+ data: {
42
+ file: shortName,
43
+ names: names.length > 0 ? names.join(", ") : "*",
44
+ source: reexportedFrom(organelle) ?? ""
45
+ },
46
+ messageId: "organelleWearingCells",
47
+ node: organelle
48
+ });
49
+ }
50
+ };
51
+ }
31
52
  return {
32
53
  Program(node) {
33
- for (const stmt of node.body) {
34
- if (stmt.type === "ExportAllDeclaration")
35
- continue;
36
- if (stmt.type === "ExportNamedDeclaration" && stmt.source)
37
- continue;
38
- if (stmt.type === "ImportDeclaration" && stmt.importKind === "type")
54
+ for (const statement of node.body) {
55
+ const isReexport = reexportedFrom(statement) !== undefined;
56
+ if (isReexport || statement.type === "ImportDeclaration" && statement.importKind === "type") {
39
57
  continue;
58
+ }
40
59
  context.report({
41
- data: { file: shortName, kind: describeStatement(stmt) },
60
+ data: {
61
+ file: shortName,
62
+ kind: DESCRIPTIONS[statement.type] ?? `a ${statement.type} statement`
63
+ },
42
64
  messageId: "notBarrel",
43
- node: stmt
65
+ node: statement
44
66
  });
45
67
  }
46
68
  }
@@ -48,16 +70,26 @@ var cellsFolderIndexIsBarrel = {
48
70
  },
49
71
  fixShape: `\`cells/index.ts\` and \`cells/dynamic.ts\` are barrels: \`export … from\` lines and nothing else. No
50
72
  function, class or variable declaration, no side-effect import. Logic that wants to live in the
51
- barrel belongs in a cell file the barrel re-exports.`,
73
+ barrel belongs in a cell file the barrel re-exports. A file in \`cells/\` that is not a barrel and only
74
+ re-exports an organelle is that organelle wearing the cell folder, and every parent that composes it
75
+ becomes a cell composing a cell: import the organelle where it is used, or write the cell here.`,
52
76
  meta: {
53
77
  docs: {
54
- description: "Barrel files under cells/ (index.ts, dynamic.ts, dynamic.tsx) must contain ONLY re-export statements. Component definitions belong in their own file."
78
+ description: "Barrel files under cells/ (index.ts, dynamic.ts, dynamic.tsx) must contain ONLY re-export statements. Component definitions belong in their own file. Any other file in cells/ that only re-exports an organelle is an organelle wearing the cell folder."
55
79
  },
56
80
  messages: {
81
+ organelleWearingCells: 'File "{{file}}" only re-exports {{names}} from "{{source}}", which is an organelle. A file in cells/ that holds no cell is an organelle wearing the cell folder, and every parent that composes it becomes a cell composing a cell. Import the organelle where it is used, or write the cell here.',
57
82
  notBarrel: 'Barrel file "{{file}}" contains {{kind}}. Barrel files under cells/ must be pure re-export manifests (only `export * from` or `export { X } from`). Component definitions belong in their own file.'
58
83
  },
59
84
  schema: [],
60
85
  type: "problem"
86
+ },
87
+ probe() {
88
+ return {
89
+ path: "src/cells/index.ts",
90
+ source: `export const geonosisProbe = 1
91
+ `
92
+ };
61
93
  }
62
94
  };
63
95
  var cells_folder_index_is_barrel_default = cellsFolderIndexIsBarrel;
@@ -1,5 +1,6 @@
1
1
  import { type RuleContext } from './lib/context.js';
2
2
  import type { AnyNode } from './lib/nodes.js';
3
+ import { type Probe } from './lib/probe.js';
3
4
  interface ImportNode {
4
5
  importKind?: string;
5
6
  source: {
@@ -35,5 +36,6 @@ declare const compoundMustBeStateless: {
35
36
  schema: never[];
36
37
  type: 'problem';
37
38
  };
39
+ probe(): Probe;
38
40
  };
39
41
  export default compoundMustBeStateless;