@rnzeus/eslint-plugin 0.1.2 → 0.1.4

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.
package/README.md CHANGED
@@ -1,12 +1,13 @@
1
- # @rnzeus/eslint-plugin-style
1
+ # @rnzeus/eslint-plugin
2
2
 
3
- ESLint plugin for React / React Native projects focused on **style discipline**.
3
+ ESLint plugin for React / React Native projects focused on **style discipline** and **FSD import boundaries**.
4
4
 
5
5
  This plugin is designed to solve real-world problems that appear during refactoring:
6
6
  - unused styles left in `*.styles.ts` files
7
7
  - inconsistent style naming
8
8
  - unsafe dynamic style usage
9
9
  - passing whole `styles` objects to components
10
+ - architectural erosion via unconstrained cross-slice imports (FSD)
10
11
 
11
12
  The plugin is **static**, **runtime-free**, and optimized for **ESLint Flat Config (ESLint v9+)**.
12
13
 
@@ -20,9 +21,10 @@ Ensures that all styles declared in `*.styles.ts(x)` files are actually used in
20
21
  **What it checks:**
21
22
  - detects unused style keys
22
23
  - forbids passing the whole `styles` object (`styles={styles}`)
23
- - supports arrays: `style={[styles.foo, styles.bar]}`
24
+ - supports arrays: `style={[styles.foo, condition && styles.bar]}`
24
25
  - supports conditional styles
25
26
  - supports dynamic styles **only with explicit directive comments**
27
+ - supports additional “style-like” props (configurable): e.g. `contentContainerStyle`
26
28
 
27
29
  **File convention (required):**
28
30
  ```
@@ -46,12 +48,48 @@ item_name: {}
46
48
 
47
49
  ---
48
50
 
51
+ ### ✅ `rnzeus/slice-imports`
52
+ Enforces **FSD import boundaries** for alias imports:
53
+ - **layer order**: lower layers cannot import higher layers
54
+ - **same-slice imports** must be **relative**
55
+ - **cross-slice** imports inside the same layer are allowed only via `@x/<currentSlice>`
56
+
57
+ This rule validates only alias imports starting with `@` (relative imports are ignored).
58
+
59
+ **Assumed structure (defaults):**
60
+ - `srcRoot`: `"src"`
61
+ - `layers`: `shared -> entities -> features -> widgets -> pages -> app`
62
+
63
+ **Examples (same slice must be relative):**
64
+ ```ts
65
+ // file: src/features/auth/ui/Login.tsx
66
+
67
+ // ❌ bad (same slice via alias)
68
+ import { submit } from "@features/auth/model/submit";
69
+
70
+ // ✅ good
71
+ import { submit } from "../model/submit";
72
+ ```
73
+
74
+ **Examples (cross-slice via @x):**
75
+ ```ts
76
+ // file: src/entities/product/ui/ProductCard.tsx
77
+
78
+ // ❌ bad (direct cross-slice import inside same layer)
79
+ import { getCartTotal } from "@entities/cart/model/getCartTotal";
80
+
81
+ // ✅ good (cart exposes cross-slice API specifically for product slice)
82
+ import { getCartTotal } from "@entities/cart/@x/product";
83
+ ```
84
+
85
+ ---
86
+
49
87
  ## Installation
50
88
 
51
89
  ```bash
52
- npm install -D @rnzeus/eslint-plugin-style
90
+ npm install -D @rnzeus/eslint-plugin
53
91
  # or
54
- yarn add -D @rnzeus/eslint-plugin-style
92
+ yarn add -D @rnzeus/eslint-plugin
55
93
  ```
56
94
 
57
95
  > Peer dependency: `eslint >= 9`
@@ -63,10 +101,11 @@ yarn add -D @rnzeus/eslint-plugin-style
63
101
  This plugin exports **ready-to-use flat config presets**.
64
102
  No `.default` access and no manual plugin wiring is required.
65
103
 
66
- ### Import preset
104
+ ### Import presets
67
105
 
68
106
  ```js
69
- const styles = require('@rnzeus/eslint-plugin-style/configs/styles');
107
+ const styles = require("@rnzeus/eslint-plugin/configs/styles");
108
+ const imports = require("@rnzeus/eslint-plugin/configs/imports");
70
109
  ```
71
110
 
72
111
  ### Minimal setup
@@ -74,6 +113,7 @@ const styles = require('@rnzeus/eslint-plugin-style/configs/styles');
74
113
  ```js
75
114
  module.exports = [
76
115
  ...styles,
116
+ ...imports,
77
117
  ];
78
118
  ```
79
119
 
@@ -81,11 +121,71 @@ module.exports = [
81
121
 
82
122
  ```js
83
123
  const rnfsd = require('@rnzeus/themis/eslint/rnfsd');
84
- const styles = require('@rnzeus/eslint-plugin-style/configs/styles');
124
+ const styles = require("@rnzeus/eslint-plugin/configs/styles");
125
+ const imports = require("@rnzeus/eslint-plugin/configs/imports");
85
126
 
86
127
  module.exports = [
87
128
  ...rnfsd,
88
129
  ...styles,
130
+ ...imports,
131
+ ];
132
+ ```
133
+
134
+ ---
135
+
136
+ ## Configure `styles-usage` style props
137
+
138
+ By default, `rnzeus/styles-usage` tracks style usage from these JSX props:
139
+
140
+ - `style`
141
+ - `contentContainerStyle`
142
+
143
+ You can extend or override this list via rule options.
144
+
145
+ ### Merge (default)
146
+
147
+ `type: "merge"` is the default behavior:
148
+ - takes plugin defaults
149
+ - adds your `styleProps`
150
+ - de-duplicates
151
+
152
+ Example (add FlatList prop):
153
+
154
+ ```js
155
+ module.exports = [
156
+ ...styles,
157
+ {
158
+ rules: {
159
+ "rnzeus/styles-usage": [
160
+ "error",
161
+ {
162
+ styleProps: ["columnWrapperStyle"],
163
+ type: "merge", // optional (default)
164
+ },
165
+ ],
166
+ },
167
+ },
168
+ ];
169
+ ```
170
+
171
+ ### Override
172
+
173
+ `type: "override"` ignores plugin defaults and uses **only** your `styleProps`.
174
+
175
+ ```js
176
+ module.exports = [
177
+ ...styles,
178
+ {
179
+ rules: {
180
+ "rnzeus/styles-usage": [
181
+ "error",
182
+ {
183
+ styleProps: ["style"],
184
+ type: "override",
185
+ },
186
+ ],
187
+ },
188
+ },
89
189
  ];
90
190
  ```
91
191
 
@@ -119,6 +219,34 @@ This makes dynamic styles:
119
219
 
120
220
  ---
121
221
 
222
+ ## Configure `slice-imports`
223
+
224
+ `rnzeus/slice-imports` supports these options:
225
+ - `srcRoot` (default: `"src"`): marker folder used to detect layer/slice from absolute filename
226
+ - `layers` (default: `["shared","entities","features","widgets","pages","app"]`): allowed layers in dependency order
227
+
228
+ Example (custom `srcRoot` and layers):
229
+ ```js
230
+ const imports = require("@rnzeus/eslint-plugin/configs/imports");
231
+
232
+ module.exports = [
233
+ ...imports,
234
+ {
235
+ rules: {
236
+ "rnzeus/slice-imports": [
237
+ "error",
238
+ {
239
+ srcRoot: "src",
240
+ layers: ["shared", "entities", "features", "widgets", "pages", "app"],
241
+ },
242
+ ],
243
+ },
244
+ },
245
+ ];
246
+ ```
247
+
248
+ ---
249
+
122
250
  ## Rules
123
251
 
124
252
  ### `rnzeus/styles-usage`
@@ -126,10 +254,11 @@ This makes dynamic styles:
126
254
  | Check | Status |
127
255
  |-----|------|
128
256
  Unused styles | ✅ |
129
- Whole styles object | ❌ |
257
+ Whole styles object (`styles={styles}`) | ❌ |
130
258
  Array styles | ✅ |
131
259
  Conditional styles | ✅ |
132
260
  Dynamic styles | ⚠️ (directive required) |
261
+ Extra style props | ✅ (configurable) |
133
262
 
134
263
  ---
135
264
 
@@ -148,6 +277,17 @@ Regex used:
148
277
 
149
278
  ---
150
279
 
280
+ ### `rnzeus/slice-imports`
281
+
282
+ | Check | Status |
283
+ |-----|------|
284
+ Layer order (lower cannot import higher) | ✅ |
285
+ Same slice must be relative | ✅ |
286
+ Cross-slice via `@x/<currentSlice>` | ✅ |
287
+ Relative imports | Ignored |
288
+
289
+ ---
290
+
151
291
  ## Philosophy
152
292
 
153
293
  This plugin intentionally: