@geonosis/oxlint-plugin-biological-architecture 2.13.0 → 3.0.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 (226) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/RULES.md +1 -2
  3. package/dist/discover-atoms.d.ts +5 -6
  4. package/dist/discover-atoms.js +33 -24
  5. package/dist/index.d.ts +7 -54
  6. package/dist/index.js +180 -7973
  7. package/dist/presets.d.ts +6 -8
  8. package/dist/presets.js +137 -6
  9. package/dist/rules/atom-no-deps.d.ts +21 -0
  10. package/dist/rules/atom-no-deps.js +29 -0
  11. package/dist/rules/boundary-time-is-primitive.d.ts +56 -0
  12. package/dist/rules/boundary-time-is-primitive.js +134 -0
  13. package/dist/rules/cell-must-be-stateful.d.ts +22 -0
  14. package/dist/rules/cell-must-be-stateful.js +75 -0
  15. package/dist/rules/cell-must-not-compose-cell.d.ts +21 -0
  16. package/dist/rules/cell-must-not-compose-cell.js +29 -0
  17. package/dist/rules/cell-no-cross-feature-organelles.d.ts +21 -0
  18. package/dist/rules/cell-no-cross-feature-organelles.js +37 -0
  19. package/dist/rules/cell-no-tissues.d.ts +21 -0
  20. package/dist/rules/cell-no-tissues.js +23 -0
  21. package/dist/rules/cells-folder-index-is-barrel.d.ts +35 -0
  22. package/dist/rules/cells-folder-index-is-barrel.js +66 -0
  23. package/dist/rules/compound-must-be-stateless.d.ts +39 -0
  24. package/dist/rules/compound-must-be-stateless.js +86 -0
  25. package/dist/rules/compound-no-stores.d.ts +21 -0
  26. package/dist/rules/compound-no-stores.js +25 -0
  27. package/dist/rules/constants-in-constants-file.d.ts +41 -0
  28. package/dist/rules/constants-in-constants-file.js +41 -0
  29. package/dist/rules/dialect-through-the-seam.d.ts +63 -0
  30. package/dist/rules/dialect-through-the-seam.js +102 -0
  31. package/dist/rules/durable-body-reads-through-steps.d.ts +78 -0
  32. package/dist/rules/durable-body-reads-through-steps.js +122 -0
  33. package/dist/rules/effect-hook-naming.d.ts +48 -0
  34. package/dist/rules/effect-hook-naming.js +82 -0
  35. package/dist/rules/emit-declares-attempts.d.ts +62 -0
  36. package/dist/rules/emit-declares-attempts.js +102 -0
  37. package/dist/rules/font-roles-only.d.ts +78 -0
  38. package/dist/rules/font-roles-only.js +88 -0
  39. package/dist/rules/layer-walls.d.ts +97 -0
  40. package/dist/rules/layer-walls.js +138 -0
  41. package/dist/rules/lib/cells-barrel.d.ts +2 -0
  42. package/dist/rules/lib/cells-barrel.js +6 -0
  43. package/dist/rules/lib/colors.d.ts +24 -0
  44. package/dist/rules/lib/colors.js +261 -0
  45. package/dist/rules/lib/context.d.ts +26 -0
  46. package/dist/rules/lib/context.js +0 -0
  47. package/dist/rules/lib/direction-rule.d.ts +65 -0
  48. package/dist/rules/lib/direction-rule.js +125 -0
  49. package/dist/rules/lib/doors.d.ts +26 -0
  50. package/dist/rules/lib/doors.js +89 -0
  51. package/dist/rules/lib/hooks.d.ts +20 -0
  52. package/dist/rules/lib/hooks.js +21 -0
  53. package/dist/rules/lib/imports.d.ts +52 -0
  54. package/dist/rules/lib/imports.js +25 -0
  55. package/dist/rules/lib/landing.d.ts +50 -0
  56. package/dist/rules/lib/landing.js +111 -0
  57. package/dist/rules/lib/literal-call.d.ts +11 -0
  58. package/dist/rules/lib/literal-call.js +10 -0
  59. package/dist/rules/lib/module-text.d.ts +43 -0
  60. package/dist/{chunk-H7UQNDFE.js → rules/lib/module-text.js} +44 -30
  61. package/dist/rules/lib/mutations.d.ts +19 -0
  62. package/dist/rules/lib/mutations.js +27 -0
  63. package/dist/rules/lib/nodes.d.ts +25 -0
  64. package/dist/rules/lib/nodes.js +71 -0
  65. package/dist/rules/lib/objects.d.ts +17 -0
  66. package/dist/rules/lib/objects.js +35 -0
  67. package/dist/rules/lib/options.d.ts +74 -0
  68. package/dist/rules/lib/options.js +64 -0
  69. package/dist/rules/lib/package-imports.d.ts +6 -0
  70. package/dist/rules/lib/package-imports.js +43 -0
  71. package/dist/rules/lib/paths.d.ts +47 -0
  72. package/dist/rules/lib/paths.js +28 -0
  73. package/dist/rules/lib/pattern-match.d.ts +16 -0
  74. package/dist/rules/lib/pattern-match.js +29 -0
  75. package/dist/rules/lib/probe.d.ts +55 -0
  76. package/dist/rules/lib/probe.js +39 -0
  77. package/dist/rules/lib/reexports.d.ts +20 -0
  78. package/dist/rules/lib/reexports.js +40 -0
  79. package/dist/rules/lib/render-tracking.d.ts +54 -0
  80. package/dist/rules/lib/render-tracking.js +27 -0
  81. package/dist/rules/lib/schema.d.ts +14 -0
  82. package/dist/rules/lib/schema.js +11 -0
  83. package/dist/rules/lib/shared-features.d.ts +24 -0
  84. package/dist/rules/lib/shared-features.js +16 -0
  85. package/dist/rules/lib/steps.d.ts +19 -0
  86. package/dist/rules/lib/steps.js +37 -0
  87. package/dist/rules/lib/styling.d.ts +65 -0
  88. package/dist/rules/lib/styling.js +90 -0
  89. package/dist/rules/lib/tiers.d.ts +31 -0
  90. package/dist/rules/lib/tiers.js +32 -0
  91. package/dist/rules/lib/tissue-entrypoint.d.ts +5 -0
  92. package/dist/rules/lib/tissue-entrypoint.js +15 -0
  93. package/dist/rules/lib/tsconfig-paths.d.ts +5 -0
  94. package/dist/rules/lib/tsconfig-paths.js +109 -0
  95. package/dist/rules/lib/visitors.d.ts +31 -0
  96. package/dist/rules/lib/visitors.js +38 -0
  97. package/dist/rules/list-take-without-order.d.ts +36 -0
  98. package/dist/rules/list-take-without-order.js +84 -0
  99. package/dist/rules/max-comment-density.d.ts +49 -0
  100. package/dist/rules/max-comment-density.js +72 -0
  101. package/dist/rules/molecule-atoms-only.d.ts +21 -0
  102. package/dist/rules/molecule-atoms-only.js +28 -0
  103. package/dist/rules/molecule-must-compose.d.ts +25 -0
  104. package/dist/rules/molecule-must-compose.js +73 -0
  105. package/dist/rules/mutating-step-declares-retry.d.ts +57 -0
  106. package/dist/rules/mutating-step-declares-retry.js +92 -0
  107. package/dist/rules/named-when-block.d.ts +37 -0
  108. package/dist/rules/named-when-block.js +59 -0
  109. package/dist/rules/next-route-segment-is-thin-delegate.d.ts +56 -0
  110. package/dist/rules/next-route-segment-is-thin-delegate.js +194 -0
  111. package/dist/rules/no-brand-names.d.ts +64 -0
  112. package/dist/rules/no-brand-names.js +80 -0
  113. package/dist/rules/no-card-shaped-div.d.ts +67 -0
  114. package/dist/rules/no-card-shaped-div.js +73 -0
  115. package/dist/rules/no-cross-feature-stores.d.ts +21 -0
  116. package/dist/rules/no-cross-feature-stores.js +31 -0
  117. package/dist/rules/no-d1-transaction.d.ts +69 -0
  118. package/dist/rules/no-d1-transaction.js +90 -0
  119. package/dist/rules/no-date-string-compare.d.ts +28 -0
  120. package/dist/rules/no-date-string-compare.js +100 -0
  121. package/dist/rules/no-duplicate-jsx-patterns.d.ts +55 -0
  122. package/dist/rules/no-duplicate-jsx-patterns.js +103 -0
  123. package/dist/rules/no-generic-utility-package.d.ts +38 -0
  124. package/dist/rules/no-generic-utility-package.js +86 -0
  125. package/dist/rules/no-hook-in-component-disguise.d.ts +96 -0
  126. package/dist/rules/no-hook-in-component-disguise.js +229 -0
  127. package/dist/rules/no-index-count-as-exact.d.ts +42 -0
  128. package/dist/rules/no-index-count-as-exact.js +65 -0
  129. package/dist/rules/no-inert-hidden-jsx.d.ts +40 -0
  130. package/dist/rules/no-inert-hidden-jsx.js +75 -0
  131. package/dist/rules/no-inline-data-in-jsx.d.ts +24 -0
  132. package/dist/rules/no-inline-data-in-jsx.js +71 -0
  133. package/dist/rules/no-invalid-feature-folders.d.ts +36 -0
  134. package/dist/rules/no-invalid-feature-folders.js +88 -0
  135. package/dist/rules/no-loader-side-effect-in-index-file.d.ts +55 -0
  136. package/dist/rules/no-loader-side-effect-in-index-file.js +77 -0
  137. package/dist/rules/no-logic-in-component-files.d.ts +49 -0
  138. package/dist/rules/no-logic-in-component-files.js +105 -0
  139. package/dist/rules/no-mock-db-in-integration.d.ts +88 -0
  140. package/dist/rules/no-mock-db-in-integration.js +105 -0
  141. package/dist/rules/no-orm-outside-db.d.ts +21 -0
  142. package/dist/rules/no-orm-outside-db.js +37 -0
  143. package/dist/rules/no-raw-html-atoms.d.ts +82 -0
  144. package/dist/rules/no-raw-html-atoms.js +91 -0
  145. package/dist/rules/no-raw-sql-outside-allowed.d.ts +61 -0
  146. package/dist/rules/no-raw-sql-outside-allowed.js +57 -0
  147. package/dist/rules/no-react-namespace.d.ts +39 -0
  148. package/dist/rules/no-react-namespace.js +46 -0
  149. package/dist/rules/no-renamed-html-props.d.ts +38 -0
  150. package/dist/rules/no-renamed-html-props.js +80 -0
  151. package/dist/rules/no-render-prop-reader.d.ts +67 -0
  152. package/dist/rules/no-render-prop-reader.js +59 -0
  153. package/dist/rules/no-runtime-dead-affordance.d.ts +69 -0
  154. package/dist/rules/no-runtime-dead-affordance.js +86 -0
  155. package/dist/rules/no-swallowed-catch.d.ts +36 -0
  156. package/dist/rules/no-swallowed-catch.js +92 -0
  157. package/dist/rules/no-trivial-wrapper-component.d.ts +61 -0
  158. package/dist/rules/no-trivial-wrapper-component.js +147 -0
  159. package/dist/rules/no-ts-in-bio-folders.d.ts +52 -0
  160. package/dist/rules/no-ts-in-bio-folders.js +58 -0
  161. package/dist/rules/no-type-definitions-in-components.d.ts +33 -0
  162. package/dist/rules/no-type-definitions-in-components.js +48 -0
  163. package/dist/rules/no-unregistered-plugin-dir.d.ts +116 -0
  164. package/dist/rules/no-unregistered-plugin-dir.js +138 -0
  165. package/dist/rules/no-void-port.d.ts +65 -0
  166. package/dist/rules/no-void-port.js +53 -0
  167. package/dist/rules/organelle-dependency.d.ts +21 -0
  168. package/dist/rules/organelle-dependency.js +37 -0
  169. package/dist/rules/organelle-single-source.d.ts +19 -0
  170. package/dist/rules/organelle-single-source.js +97 -0
  171. package/dist/rules/plugin-route-namespaced.d.ts +79 -0
  172. package/dist/rules/plugin-route-namespaced.js +137 -0
  173. package/dist/rules/queries-require-org-scope.d.ts +88 -0
  174. package/dist/rules/queries-require-org-scope.js +83 -0
  175. package/dist/rules/queue-loop-is-the-library.d.ts +28 -0
  176. package/dist/rules/queue-loop-is-the-library.js +35 -0
  177. package/dist/rules/route-no-inline-mutation.d.ts +81 -0
  178. package/dist/rules/route-no-inline-mutation.js +125 -0
  179. package/dist/rules/router-schema-parity.d.ts +60 -0
  180. package/dist/rules/router-schema-parity.js +95 -0
  181. package/dist/rules/service-name-not-reserved.d.ts +47 -0
  182. package/dist/rules/service-name-not-reserved.js +112 -0
  183. package/dist/rules/ssot-no-inline-facts.d.ts +68 -0
  184. package/dist/rules/ssot-no-inline-facts.js +221 -0
  185. package/dist/rules/ssot-no-process-env.d.ts +55 -0
  186. package/dist/rules/ssot-no-process-env.js +51 -0
  187. package/dist/rules/step-declares-compensation-or-none.d.ts +34 -0
  188. package/dist/rules/step-declares-compensation-or-none.js +52 -0
  189. package/dist/rules/step-opens-its-own-cell.d.ts +82 -0
  190. package/dist/rules/step-opens-its-own-cell.js +163 -0
  191. package/dist/rules/store-route-scopes-tenant-data.d.ts +52 -0
  192. package/dist/rules/store-route-scopes-tenant-data.js +150 -0
  193. package/dist/rules/subpath-over-barrel.d.ts +67 -0
  194. package/dist/rules/subpath-over-barrel.js +153 -0
  195. package/dist/rules/subscriber-declares-id.d.ts +39 -0
  196. package/dist/rules/subscriber-declares-id.js +79 -0
  197. package/dist/rules/tables-declare-their-plane.d.ts +44 -0
  198. package/dist/rules/tables-declare-their-plane.js +64 -0
  199. package/dist/rules/tenant-tables-carry-org-id.d.ts +66 -0
  200. package/dist/rules/tenant-tables-carry-org-id.js +64 -0
  201. package/dist/rules/test-no-clock-polling-for-promise-flips.d.ts +42 -0
  202. package/dist/rules/test-no-clock-polling-for-promise-flips.js +130 -0
  203. package/dist/rules/time-through-the-door.d.ts +86 -0
  204. package/dist/rules/time-through-the-door.js +138 -0
  205. package/dist/rules/tissue-must-compose.d.ts +41 -0
  206. package/dist/rules/tissue-must-compose.js +113 -0
  207. package/dist/rules/tissue-no-data-props.d.ts +27 -0
  208. package/dist/rules/tissue-no-data-props.js +148 -0
  209. package/dist/rules/tissue-no-hooks.d.ts +43 -0
  210. package/dist/rules/tissue-no-hooks.js +72 -0
  211. package/dist/rules/tissue-no-organelles.d.ts +21 -0
  212. package/dist/rules/tissue-no-organelles.js +17 -0
  213. package/dist/rules/tissue-no-stores.d.ts +21 -0
  214. package/dist/rules/tissue-no-stores.js +17 -0
  215. package/dist/rules/todo-names-its-plan.d.ts +75 -0
  216. package/dist/rules/todo-names-its-plan.js +68 -0
  217. package/dist/rules/tokens-only-colors.d.ts +100 -0
  218. package/dist/rules/tokens-only-colors.js +129 -0
  219. package/dist/rules/unique-query-step-name.d.ts +50 -0
  220. package/dist/rules/unique-query-step-name.js +130 -0
  221. package/dist/rules/worker-handles-are-scoped.d.ts +65 -0
  222. package/dist/rules/worker-handles-are-scoped.js +97 -0
  223. package/dist/rules/zustand-v5-best-practices.d.ts +65 -0
  224. package/dist/rules/zustand-v5-best-practices.js +107 -0
  225. package/package.json +4 -4
  226. package/dist/chunk-ZY3XIRRE.js +0 -145
package/dist/presets.d.ts CHANGED
@@ -4,8 +4,8 @@
4
4
  * consumer's config the day it ships is a rename nobody adopts — and the reading says so ONCE per
5
5
  * process, whatever door read it and however many rules it resolved.
6
6
  */
7
- declare const RENAMED_TO: Record<string, string>;
8
- type Preset = {
7
+ export declare const RENAMED_TO: Record<string, string>;
8
+ export type Preset = {
9
9
  /** Rule ids that belong to this preset but are not ours — enabled alongside, never instead. */
10
10
  rules: Record<string, string>;
11
11
  };
@@ -20,12 +20,12 @@ type Preset = {
20
20
  * The two step rules that appear in `backend-workflows` as well are deliberately NOT here: 026-W2
21
21
  * measured them reaching both engines' spellings, and a rule that reaches both presumes neither.
22
22
  */
23
- declare const PRESUMED_ENGINES: readonly {
23
+ export declare const PRESUMED_ENGINES: readonly {
24
24
  engine: string;
25
25
  packages: readonly string[];
26
26
  rules: readonly string[];
27
27
  }[];
28
- declare const PRESETS: {
28
+ export declare const PRESETS: {
29
29
  'backend-d1': {
30
30
  rules: Record<string, "error">;
31
31
  };
@@ -73,8 +73,6 @@ declare const PRESETS: {
73
73
  rules: Record<string, "error">;
74
74
  };
75
75
  };
76
- type PresetName = keyof typeof PRESETS;
76
+ export type PresetName = keyof typeof PRESETS;
77
77
  /** The rule names a preset carries, stripped of the plugin namespace. */
78
- declare const rulesOfPreset: (preset: PresetName) => string[];
79
-
80
- export { PRESETS, PRESUMED_ENGINES, type Preset, type PresetName, RENAMED_TO, rulesOfPreset };
78
+ export declare const rulesOfPreset: (preset: PresetName) => string[];
package/dist/presets.js CHANGED
@@ -1,9 +1,140 @@
1
- import {
2
- PRESETS,
3
- PRESUMED_ENGINES,
4
- RENAMED_TO,
5
- rulesOfPreset
6
- } from "./chunk-ZY3XIRRE.js";
1
+ // src/presets.ts
2
+ var FRONTEND = [
3
+ "atom-no-deps",
4
+ "cell-must-be-stateful",
5
+ "cell-must-not-compose-cell",
6
+ "cell-no-cross-feature-organelles",
7
+ "cell-no-tissues",
8
+ "cells-folder-index-is-barrel",
9
+ "compound-must-be-stateless",
10
+ "compound-no-stores",
11
+ "effect-hook-naming",
12
+ "molecule-atoms-only",
13
+ "molecule-must-compose",
14
+ "next-route-segment-is-thin-delegate",
15
+ "no-brand-names",
16
+ "no-card-shaped-div",
17
+ "no-cross-feature-stores",
18
+ "no-duplicate-jsx-patterns",
19
+ "no-hook-in-component-disguise",
20
+ "no-inert-hidden-jsx",
21
+ "no-inline-data-in-jsx",
22
+ "no-invalid-feature-folders",
23
+ "no-logic-in-component-files",
24
+ "no-raw-html-atoms",
25
+ "no-react-namespace",
26
+ "no-renamed-html-props",
27
+ "no-render-prop-reader",
28
+ "no-runtime-dead-affordance",
29
+ "no-trivial-wrapper-component",
30
+ "no-ts-in-bio-folders",
31
+ "no-type-definitions-in-components",
32
+ "organelle-dependency",
33
+ "organelle-single-source",
34
+ "tissue-must-compose",
35
+ "tissue-no-data-props",
36
+ "tissue-no-hooks",
37
+ "tissue-no-organelles",
38
+ "tissue-no-stores",
39
+ "zustand-v5-best-practices"
40
+ ];
41
+ var BACKEND_WORKFLOWS = [
42
+ "boundary-time-is-primitive",
43
+ "constants-in-constants-file",
44
+ "dialect-through-the-seam",
45
+ "durable-body-reads-through-steps",
46
+ "mutating-step-declares-retry",
47
+ "no-date-string-compare",
48
+ "no-orm-outside-db",
49
+ "no-raw-sql-outside-allowed",
50
+ "no-void-port",
51
+ "queue-loop-is-the-library",
52
+ "ssot-no-inline-facts",
53
+ "ssot-no-process-env",
54
+ "step-declares-compensation-or-none",
55
+ "tables-declare-their-plane",
56
+ "time-through-the-door"
57
+ ];
58
+ var BACKEND_D1 = ["no-d1-transaction", "worker-handles-are-scoped"];
59
+ var BACKEND_WORKFLOWS_CF = ["step-opens-its-own-cell"];
60
+ var RENAMED_TO = {
61
+ "backend-sagaflow-cf": "backend-workflows-cf"
62
+ };
63
+ var announced = new Set;
64
+ var announceRename = (from) => {
65
+ if (announced.has(from))
66
+ return;
67
+ announced.add(from);
68
+ process.stderr.write(`biological-architecture: preset "${from}" is now "${RENAMED_TO[from]}" — the old name resolves to the same rules until the next major, then goes.
69
+ `);
70
+ };
71
+ var BACKEND_MEDUSA = [
72
+ "emit-declares-attempts",
73
+ "list-take-without-order",
74
+ "mutating-step-declares-retry",
75
+ "named-when-block",
76
+ "no-index-count-as-exact",
77
+ "no-loader-side-effect-in-index-file",
78
+ "plugin-route-namespaced",
79
+ "route-no-inline-mutation",
80
+ "service-name-not-reserved",
81
+ "step-declares-compensation-or-none",
82
+ "store-route-scopes-tenant-data",
83
+ "subscriber-declares-id",
84
+ "unique-query-step-name"
85
+ ];
86
+ var FAILURE_PATHS = ["no-swallowed-catch"];
87
+ var INTEGRATIONS = ["no-unregistered-plugin-dir"];
88
+ var BACKEND_TRPC = ["router-schema-parity"];
89
+ var TENANT_SCOPING = [
90
+ "queries-require-org-scope",
91
+ "store-route-scopes-tenant-data",
92
+ "tables-declare-their-plane",
93
+ "tenant-tables-carry-org-id"
94
+ ];
95
+ var TOOLING = ["layer-walls", "no-generic-utility-package", "todo-names-its-plan"];
96
+ var THEMEKIT = ["font-roles-only", "tokens-only-colors"];
97
+ var TESTBED = ["no-mock-db-in-integration", "test-no-clock-polling-for-promise-flips"];
98
+ var PACKAGE_SUBPATHS = ["subpath-over-barrel"];
99
+ var RULE_PREFIX = "biological-architecture";
100
+ var asRules = (names) => Object.fromEntries(names.map((name) => [`${RULE_PREFIX}/${name}`, "error"]));
101
+ var COMMENT_CEILING = {
102
+ rules: {
103
+ ...asRules(["max-comment-density"]),
104
+ "capitalized-comments": "error"
105
+ }
106
+ };
107
+ var PRESUMED_ENGINES = [
108
+ {
109
+ engine: "Medusa",
110
+ packages: ["@medusajs/framework", "@medusajs/medusa", "@medusajs/utils"],
111
+ rules: BACKEND_MEDUSA.filter((name) => !BACKEND_WORKFLOWS.includes(name))
112
+ }
113
+ ];
114
+ var PRESETS = {
115
+ "backend-d1": { rules: asRules(BACKEND_D1) },
116
+ "backend-medusa": { rules: asRules(BACKEND_MEDUSA) },
117
+ "backend-sagaflow-cf": {
118
+ get rules() {
119
+ announceRename("backend-sagaflow-cf");
120
+ return asRules(BACKEND_WORKFLOWS_CF);
121
+ }
122
+ },
123
+ "backend-trpc": { rules: asRules(BACKEND_TRPC) },
124
+ "backend-workflows": { rules: asRules(BACKEND_WORKFLOWS) },
125
+ "backend-workflows-cf": { rules: asRules(BACKEND_WORKFLOWS_CF) },
126
+ "comment-ceiling": COMMENT_CEILING,
127
+ "failure-paths": { rules: asRules(FAILURE_PATHS) },
128
+ frontend: { rules: asRules(FRONTEND) },
129
+ integrations: { rules: asRules(INTEGRATIONS) },
130
+ "package-subpaths": { rules: asRules(PACKAGE_SUBPATHS) },
131
+ recommended: { rules: asRules(FRONTEND) },
132
+ "tenant-scoping": { rules: asRules(TENANT_SCOPING) },
133
+ themekit: { rules: asRules(THEMEKIT) },
134
+ testbed: { rules: asRules(TESTBED) },
135
+ tooling: { rules: asRules(TOOLING) }
136
+ };
137
+ var rulesOfPreset = (preset) => Object.keys(PRESETS[preset].rules).filter((id) => id.startsWith(`${RULE_PREFIX}/`)).map((id) => id.slice(RULE_PREFIX.length + 1));
7
138
  export {
8
139
  PRESETS,
9
140
  PRESUMED_ENGINES,
@@ -0,0 +1,21 @@
1
+ declare const atomNoDeps: {
2
+ create(context: {
3
+ filename: string;
4
+ options?: readonly unknown[];
5
+ report: (descriptor: {
6
+ data: Record<string, string>;
7
+ messageId: string;
8
+ node: unknown;
9
+ }) => void;
10
+ }): import('./lib/visitors.js').Visitor;
11
+ fixShape: string;
12
+ meta: {
13
+ docs: {
14
+ description: string;
15
+ };
16
+ messages: Record<string, string>;
17
+ schema: unknown[];
18
+ type: 'problem';
19
+ };
20
+ };
21
+ export default atomNoDeps;
@@ -0,0 +1,29 @@
1
+ // src/rules/atom-no-deps.ts
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
+ ];
13
+ var atomNoDeps = directionRule({
14
+ description: "Atoms cannot import from molecules, compounds, organelles, cells, stores, or domains",
15
+ fixShape: `Raw \`<button>\`, \`<input>\`, or a \`<div>\` with border + background in levels 2-6 belongs in an atom.
16
+ An atom imports nothing above itself — no molecule, compound, organelle, cell, tissue, store or domain,
17
+ and that includes \`export … from\`. If an atom needs a shared constant, the constant moves down to the atom
18
+ tier or into a plain \`lib/\` module, never the other way round.`,
19
+ forbidden: (target) => FORBIDDEN_PATTERNS.some((pattern) => pattern.test(target.path)),
20
+ messages: {
21
+ forbidden: "Atoms cannot import from {{source}}. Atoms are the lowest level and must not depend on higher-level components."
22
+ },
23
+ scope: "atoms",
24
+ typeOnly: "visit"
25
+ });
26
+ var atom_no_deps_default = atomNoDeps;
27
+ export {
28
+ atom_no_deps_default as default
29
+ };
@@ -0,0 +1,56 @@
1
+ import { type RuleContextWithOptions } from './lib/context.js';
2
+ import { type Probe } from './lib/probe.js';
3
+ interface Options {
4
+ /** The modules that may name these types in an exported signature, each written out in full. */
5
+ doors?: string[];
6
+ /** The type names that must not cross an exported boundary. A namespace covers its members. */
7
+ types?: string[];
8
+ }
9
+ declare const boundaryTimeIsPrimitive: {
10
+ create(context: RuleContextWithOptions<Options>): {
11
+ ExportNamedDeclaration?: undefined;
12
+ ExportDefaultDeclaration?: undefined;
13
+ } | {
14
+ ExportNamedDeclaration: (node: {
15
+ declaration?: unknown;
16
+ }) => void;
17
+ ExportDefaultDeclaration: (node: {
18
+ declaration?: unknown;
19
+ }) => void;
20
+ };
21
+ fixShape: string;
22
+ meta: {
23
+ docs: {
24
+ description: string;
25
+ };
26
+ messages: {
27
+ libraryTypeAtBoundary: string;
28
+ };
29
+ schema: {
30
+ additionalProperties: boolean;
31
+ properties: {
32
+ doors: {
33
+ items: {
34
+ type: 'string';
35
+ };
36
+ type: 'array';
37
+ };
38
+ types: {
39
+ items: {
40
+ type: 'string';
41
+ };
42
+ type: 'array';
43
+ };
44
+ };
45
+ type: 'object';
46
+ }[];
47
+ type: 'problem';
48
+ };
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
+ probe(options: readonly unknown[]): Probe;
55
+ };
56
+ export default boundaryTimeIsPrimitive;
@@ -0,0 +1,134 @@
1
+ // src/rules/boundary-time-is-primitive.ts
2
+ import { walkNode } from "./lib/nodes.js";
3
+ import { requireOption } from "./lib/options.js";
4
+ import { isDoor } from "./lib/paths.js";
5
+ import { bagOf, firstOf } from "./lib/probe.js";
6
+ import { optionsBag, STRINGS } from "./lib/schema.js";
7
+ var RULE = "boundary-time-is-primitive";
8
+ var ACCEPTS = "{ types: string[] (type or namespace names), doors: string[] (a path, a specifier, or a regex over the filename; default none) }";
9
+ var asNode = (value) => typeof value === "object" && value !== null ? value : undefined;
10
+ var nameOf = (value) => {
11
+ const name = asNode(value)?.["name"];
12
+ return typeof name === "string" ? name : undefined;
13
+ };
14
+ var referencedType = (reference) => {
15
+ const typeName = asNode(reference["typeName"]);
16
+ if (typeName === undefined)
17
+ return;
18
+ if (typeName.type === "Identifier")
19
+ return nameOf(typeName);
20
+ if (typeName.type !== "TSQualifiedName")
21
+ return;
22
+ const namespace = nameOf(typeName["left"]);
23
+ const member = nameOf(typeName["right"]);
24
+ return namespace === undefined || member === undefined ? undefined : `${namespace}.${member}`;
25
+ };
26
+ var forbids = (types, referenced) => types.includes(referenced) || types.includes(referenced.split(".")[0] ?? referenced);
27
+ var functionSignature = (value) => {
28
+ const fn = asNode(value);
29
+ if (fn?.type !== "ArrowFunctionExpression" && fn?.type !== "FunctionExpression")
30
+ return [];
31
+ return [fn["params"], fn["returnType"]];
32
+ };
33
+ var signatureOf = (declaration) => {
34
+ if (declaration.type === "FunctionDeclaration" || declaration.type === "TSDeclareFunction") {
35
+ return [declaration["params"], declaration["returnType"]];
36
+ }
37
+ if (declaration.type === "VariableDeclaration") {
38
+ const declarators = Array.isArray(declaration["declarations"]) ? declaration["declarations"] : [];
39
+ return declarators.flatMap((one) => [
40
+ asNode(one)?.["id"] === undefined ? undefined : asNode(asNode(one)?.["id"])?.["typeAnnotation"],
41
+ ...functionSignature(asNode(one)?.["init"])
42
+ ]);
43
+ }
44
+ if (declaration.type === "ArrowFunctionExpression" || declaration.type === "FunctionExpression") {
45
+ return functionSignature(declaration);
46
+ }
47
+ if (declaration.type === "TSTypeAliasDeclaration")
48
+ return [declaration["typeAnnotation"]];
49
+ if (declaration.type === "TSInterfaceDeclaration")
50
+ return [declaration["body"]];
51
+ if (declaration.type === "ClassDeclaration") {
52
+ const members = asNode(declaration["body"])?.["body"];
53
+ return (Array.isArray(members) ? members : []).flatMap((member) => [
54
+ asNode(member)?.["typeAnnotation"],
55
+ ...functionSignature(asNode(member)?.["value"])
56
+ ]);
57
+ }
58
+ return [];
59
+ };
60
+ var declaredName = (declaration) => {
61
+ const own = nameOf(declaration["id"]);
62
+ if (own !== undefined)
63
+ return own;
64
+ const declarators = Array.isArray(declaration["declarations"]) ? declaration["declarations"] : [];
65
+ return nameOf(asNode(declarators[0])?.["id"]) ?? "the export";
66
+ };
67
+ var behindADoor = (filename, doors) => doors.some((door) => isDoor(filename, door));
68
+ var boundaryTimeIsPrimitive = {
69
+ create(context) {
70
+ const types = requireOption(RULE, context.options?.[0]?.types, "types", ACCEPTS);
71
+ const doors = context.options?.[0]?.doors ?? [];
72
+ if (behindADoor(context.filename, doors))
73
+ return {};
74
+ const behind = doors.length === 0 ? "the module that owns the library" : doors.join(", ");
75
+ const report = (node) => {
76
+ const declaration = asNode(node.declaration);
77
+ if (declaration === undefined)
78
+ return;
79
+ for (const root of signatureOf(declaration)) {
80
+ walkNode(root, (found) => {
81
+ if (found.type !== "TSTypeReference")
82
+ return;
83
+ const referenced = referencedType(found);
84
+ if (referenced === undefined || !forbids(types, referenced))
85
+ return;
86
+ context.report({
87
+ data: { doors: behind, name: declaredName(declaration), type: referenced },
88
+ messageId: "libraryTypeAtBoundary",
89
+ node: found
90
+ });
91
+ });
92
+ }
93
+ };
94
+ return {
95
+ ExportNamedDeclaration: report,
96
+ ExportDefaultDeclaration: report
97
+ };
98
+ },
99
+ fixShape: `An exported signature carries time as a PRIMITIVE: epoch milliseconds for an instant, an ISO date
100
+ string (\`YYYY-MM-DD\`) for a business date. A \`Date\`, a \`Dayjs\` or a \`Temporal\` type in a parameter,
101
+ a return or an exported shape hands every caller the library and its configuration, and no database
102
+ column, wire message or contract can hold one at all — the boundary is where the conversion belongs.
103
+ Convert at the door the \`doors\` option names; that module is the one place allowed to say the
104
+ library's type out loud, and a display string is produced at the edge from the primitive rather than
105
+ carried across as a formatted value. Only the signature is judged: a \`Date\` a function builds and
106
+ keeps inside its own body is its own business.`,
107
+ meta: {
108
+ docs: {
109
+ description: "A date-library type in an exported signature couples every caller to the library and its configuration. Time crosses a boundary as a primitive — epoch milliseconds or an ISO date string — and the library type stays inside the module the `doors` option names. Enabled without `types` it reports that once a run and judges nothing."
110
+ },
111
+ messages: {
112
+ libraryTypeAtBoundary: '"{{name}}" puts `{{type}}` in an exported signature. Time crosses a boundary as a primitive — epoch milliseconds for an instant, an ISO date string for a business date — and `{{type}}` stays behind {{doors}}.'
113
+ },
114
+ schema: optionsBag({
115
+ doors: STRINGS,
116
+ types: STRINGS
117
+ }),
118
+ type: "problem"
119
+ },
120
+ probe(options) {
121
+ const { doors = [], types = [] } = bagOf(options);
122
+ const type = firstOf(types, []);
123
+ const path = ["geonosis-probe-boundary.ts", "src/geonosis-probe-boundary.ts"].find((candidate) => !behindADoor(candidate, doors));
124
+ if (path === undefined) {
125
+ throw new Error(`biological-architecture/${RULE}: every path a probe could be written at is itself one of the declared \`doors\` (${doors.join(", ")}), so there is nowhere left for this rule to speak.`);
126
+ }
127
+ return { path, source: `export const boundary = (at: ${type}): string => String(at)
128
+ ` };
129
+ }
130
+ };
131
+ var boundary_time_is_primitive_default = boundaryTimeIsPrimitive;
132
+ export {
133
+ boundary_time_is_primitive_default as default
134
+ };
@@ -0,0 +1,22 @@
1
+ import { type RuleContext } from './lib/context.js';
2
+ declare const cellMustBeStateful: {
3
+ create(context: RuleContext): {
4
+ Program?: undefined;
5
+ 'Program:exit'?: undefined;
6
+ } | {
7
+ Program(node: unknown): void;
8
+ 'Program:exit'(): void;
9
+ };
10
+ fixShape: string;
11
+ meta: {
12
+ docs: {
13
+ description: string;
14
+ };
15
+ messages: {
16
+ shouldBeCompound: string;
17
+ };
18
+ schema: never[];
19
+ type: 'problem';
20
+ };
21
+ };
22
+ export default cellMustBeStateful;
@@ -0,0 +1,75 @@
1
+ // src/rules/cell-must-be-stateful.ts
2
+ import * as fs from "node:fs";
3
+ import { normalise } from "./lib/paths.js";
4
+ import { launderedHomesOf } from "./lib/reexports.js";
5
+ var STATE_SIGNATURE = /\buse[A-Z]\w*\s*\(|from\s+['"][^'"]*\/organelles(?:\/|['"])|from\s+['"][^'"]*\/stores?(?:\/|['"])|createContext\s*\(/;
6
+ var SIBLING_SUFFIXES = [
7
+ ".tsx",
8
+ ".parts.tsx",
9
+ ".sections.tsx",
10
+ ".layouts.tsx",
11
+ ".icons.tsx",
12
+ ".sidebar.tsx",
13
+ ".summary.tsx",
14
+ ".form.tsx",
15
+ ".data.tsx",
16
+ ".steps.tsx"
17
+ ];
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 {}
27
+ }
28
+ return false;
29
+ }
30
+ var cellMustBeStateful = {
31
+ create(context) {
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);
35
+ if (!isCellEntrypoint)
36
+ return {};
37
+ const laundered = launderedHomesOf(context.filename);
38
+ if (laundered !== undefined && laundered.length === 0)
39
+ return {};
40
+ const judged = laundered ?? [normalized];
41
+ let programNode = null;
42
+ return {
43
+ Program(node) {
44
+ programNode = node;
45
+ },
46
+ "Program:exit"() {
47
+ if (!judged.every((file) => familyHasState(normalise(file)))) {
48
+ context.report({
49
+ data: { file: base },
50
+ messageId: "shouldBeCompound",
51
+ node: programNode
52
+ });
53
+ }
54
+ }
55
+ };
56
+ },
57
+ fixShape: `A cell OWNS state: a \`use*()\` call, an organelle import, or a store read, somewhere in its family
58
+ (\`x.tsx\` + \`x.parts.tsx\` + \`x.sections.tsx\` + …). A file in \`cells/\` that is props-in / JSX-out with
59
+ no state anywhere in that family is inert chemistry — move it to \`compounds/\`. If it should be
60
+ stateful, put the store read or the organelle in it rather than taking the data as a prop.`,
61
+ meta: {
62
+ docs: {
63
+ description: "A cell must own state (a hook, a state-bearing organelle, or a store) somewhere in its family. A cell whose whole family is stateless props-in/JSX-out is a compound — move it to compounds/."
64
+ },
65
+ messages: {
66
+ shouldBeCompound: 'Cell "{{file}}" holds no state (no hooks, no organelle, no store) anywhere in its family — it is a stateless display and belongs in compounds/, not cells/.'
67
+ },
68
+ schema: [],
69
+ type: "problem"
70
+ }
71
+ };
72
+ var cell_must_be_stateful_default = cellMustBeStateful;
73
+ export {
74
+ cell_must_be_stateful_default as default
75
+ };
@@ -0,0 +1,21 @@
1
+ declare const cellMustNotComposeCell: {
2
+ create(context: {
3
+ filename: string;
4
+ options?: readonly unknown[];
5
+ report: (descriptor: {
6
+ data: Record<string, string>;
7
+ messageId: string;
8
+ node: unknown;
9
+ }) => void;
10
+ }): import('./lib/visitors.js').Visitor;
11
+ fixShape: string;
12
+ meta: {
13
+ docs: {
14
+ description: string;
15
+ };
16
+ messages: Record<string, string>;
17
+ schema: unknown[];
18
+ type: 'problem';
19
+ };
20
+ };
21
+ export default cellMustNotComposeCell;
@@ -0,0 +1,29 @@
1
+ // src/rules/cell-must-not-compose-cell.ts
2
+ import { isCellsBarrel } from "./lib/cells-barrel.js";
3
+ import { directionRule } from "./lib/direction-rule.js";
4
+ 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
+ var cellMustNotComposeCell = directionRule({
7
+ data: (target, importer) => ({ currentFile: importer.file, importedFile: target.file }),
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.",
9
+ fixShape: `A cell never composes another cell — not same-feature, not \`shared/\`, no exception. If you want to,
10
+ one of the two is misclassified: arrangement goes up to a \`tissues/\` file, a stateless display goes
11
+ down to \`compounds/\`, a store adapter goes sideways to \`organelles/\`. A parent that holds state AND
12
+ hosts a cell (a summary card that opens a modal-hosted form) is two cells side by side: the child
13
+ hosts its own modal and reads whether it is open from the store, the parent writes it, and a
14
+ \`tissues/\` file arranges both. Cells coordinate through a store, never through props from one to
15
+ the other. A stateless adapter between cells is a tissue — it may take the data it hands down
16
+ (\`{ collections: Collection[] }\`); it may not take a handler. Private siblings of the SAME
17
+ component (\`invoice-editor.parts.tsx\` from \`invoice-editor.tsx\`) are one cell and are fine. The
18
+ barrels \`cells/index.ts\`, \`cells/dynamic.ts\` and \`cells/dynamic.tsx\` are exempt — re-exporting
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),
21
+ messages: {
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
+ },
24
+ scope: (importer) => IN_CELLS.test(importer.path) && !isCellsBarrel(importer.path)
25
+ });
26
+ var cell_must_not_compose_cell_default = cellMustNotComposeCell;
27
+ export {
28
+ cell_must_not_compose_cell_default as default
29
+ };
@@ -0,0 +1,21 @@
1
+ declare const cellNoCrossFeatureOrganelles: {
2
+ create(context: {
3
+ filename: string;
4
+ options?: readonly unknown[];
5
+ report: (descriptor: {
6
+ data: Record<string, string>;
7
+ messageId: string;
8
+ node: unknown;
9
+ }) => void;
10
+ }): import('./lib/visitors.js').Visitor;
11
+ fixShape: string;
12
+ meta: {
13
+ docs: {
14
+ description: string;
15
+ };
16
+ messages: Record<string, string>;
17
+ schema: unknown[];
18
+ type: 'problem';
19
+ };
20
+ };
21
+ export default cellNoCrossFeatureOrganelles;
@@ -0,0 +1,37 @@
1
+ // src/rules/cell-no-cross-feature-organelles.ts
2
+ import { directionRule } from "./lib/direction-rule.js";
3
+ import {
4
+ crossesFeatureBoundary,
5
+ SHARED_FEATURES_SCHEMA
6
+ } from "./lib/shared-features.js";
7
+ var FEATURE_ORGANELLE = /(?:^|[/@])features\/([^/]+)\/organelles\//;
8
+ var organelleFeatureOf = (path) => FEATURE_ORGANELLE.exec(path)?.[1];
9
+ var cellNoCrossFeatureOrganelles = directionRule({
10
+ data: (target, importer) => ({
11
+ file: importer.file,
12
+ importedFeature: organelleFeatureOf(target.path) ?? "",
13
+ ownFeature: importer.feature ?? "",
14
+ source: target.source
15
+ }),
16
+ description: "Cells must not import another feature's organelles. An organelle is a feature's own state compartment; a cell in features/X/ hosts features/X/organelles/* and the features named in sharedFeatures (default: shared). Another feature's state arrives as props from the tissue above.",
17
+ fixShape: `A cell hosts its OWN feature's organelles. Another feature's organelle is that feature's state
18
+ compartment, and a cell that imports one couples two features through a hook instead of through
19
+ props — take the value as a prop and let the tissue above arrange both, or move the organelle into a
20
+ feature every cell may read (the rule's \`sharedFeatures\` option, default \`shared\`). Relative and
21
+ aliased sources are judged alike: \`../../billing/organelles/totals\` lands where
22
+ \`@/features/billing/organelles/totals\` lands. Type-only imports are exempt; \`export … from\` is not.`,
23
+ forbidden: (target, importer, options) => {
24
+ const importedFeature = organelleFeatureOf(target.path);
25
+ return crossesFeatureBoundary(importedFeature, importer.feature, options);
26
+ },
27
+ messages: {
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
+ },
30
+ optionsFrom: (raw) => raw ?? {},
31
+ scope: "cells",
32
+ schema: SHARED_FEATURES_SCHEMA
33
+ });
34
+ var cell_no_cross_feature_organelles_default = cellNoCrossFeatureOrganelles;
35
+ export {
36
+ cell_no_cross_feature_organelles_default as default
37
+ };
@@ -0,0 +1,21 @@
1
+ declare const cellNoTissues: {
2
+ create(context: {
3
+ filename: string;
4
+ options?: readonly unknown[];
5
+ report: (descriptor: {
6
+ data: Record<string, string>;
7
+ messageId: string;
8
+ node: unknown;
9
+ }) => void;
10
+ }): import('./lib/visitors.js').Visitor;
11
+ fixShape: string;
12
+ meta: {
13
+ docs: {
14
+ description: string;
15
+ };
16
+ messages: Record<string, string>;
17
+ schema: unknown[];
18
+ type: 'problem';
19
+ };
20
+ };
21
+ export default cellNoTissues;