eslint-plugin-fsd-imports-check 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +19 -0
- package/README.md +466 -0
- package/docs/rules/layer-imports.md +188 -0
- package/docs/rules/path-checker.md +207 -0
- package/docs/rules/public-api-imports.md +366 -0
- package/lib/helpers/index.d.ts +13 -0
- package/lib/helpers/index.js +66 -0
- package/lib/helpers/index.js.map +1 -0
- package/lib/index.d.ts +15 -0
- package/lib/index.js +24 -0
- package/lib/index.js.map +1 -0
- package/lib/rules/layer-imports.d.ts +7 -0
- package/lib/rules/layer-imports.js +118 -0
- package/lib/rules/layer-imports.js.map +1 -0
- package/lib/rules/path-checker.d.ts +7 -0
- package/lib/rules/path-checker.js +142 -0
- package/lib/rules/path-checker.js.map +1 -0
- package/lib/rules/public-api-imports.d.ts +7 -0
- package/lib/rules/public-api-imports.js +147 -0
- package/lib/rules/public-api-imports.js.map +1 -0
- package/lib/types/types.d.ts +5 -0
- package/lib/types/types.js +3 -0
- package/lib/types/types.js.map +1 -0
- package/package.json +67 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2026 ALTaww
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to persons to whom the
|
|
8
|
+
Software is furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO: THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTIONB OF ACTION, ACTION, WHETHER IN AN CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
# eslint-plugin-fsd-imports-check
|
|
2
|
+
|
|
3
|
+
ESLint plugin for enforcing import rules in projects that use [Feature-Sliced Design (FSD)](https://feature-sliced.design/).
|
|
4
|
+
|
|
5
|
+
GitLab: https://gitlab.com/ALTaww/eslint-plugin-fsd-imports-check
|
|
6
|
+
|
|
7
|
+
## What does this plugin do?
|
|
8
|
+
|
|
9
|
+
The plugin provides three rules for controlling imports between FSD modules:
|
|
10
|
+
|
|
11
|
+
1. **`path-checker`** prevents absolute imports between files inside the same FSD slice. Such imports must use relative paths.
|
|
12
|
+
|
|
13
|
+
2. **`layer-imports`** enforces the allowed dependency direction between FSD layers. For example, `features` can import from `entities` and `shared`, but cannot import from `widgets`, `pages`, or `app`.
|
|
14
|
+
|
|
15
|
+
3. **`public-api-imports`** requires imports from another FSD module to use its public API instead of accessing internal files directly. The rule can optionally replace deep imports with public API imports.
|
|
16
|
+
|
|
17
|
+
The rules work with both JavaScript and TypeScript source files.
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
Install ESLint:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
npm install eslint --save-dev
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Then install the plugin:
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
npm install eslint-plugin-fsd-imports-check --save-dev
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
### ESLint 9 and 10
|
|
36
|
+
|
|
37
|
+
For modern ESLint versions using flat config, import the plugin and register it under the `plugins` key.
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
import { defineConfig } from "eslint/config";
|
|
41
|
+
import fsdImportsCheck from "eslint-plugin-fsd-imports-check";
|
|
42
|
+
|
|
43
|
+
export default defineConfig([
|
|
44
|
+
{
|
|
45
|
+
plugins: {
|
|
46
|
+
"fsd-imports-check": fsdImportsCheck,
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
rules: {
|
|
50
|
+
"fsd-imports-check/path-checker": "error",
|
|
51
|
+
"fsd-imports-check/layer-imports": "error",
|
|
52
|
+
"fsd-imports-check/public-api-imports": "error",
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
]);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### ESLint 6–8
|
|
59
|
+
|
|
60
|
+
For legacy ESLint configuration, add the plugin to the `plugins` array:
|
|
61
|
+
|
|
62
|
+
```js
|
|
63
|
+
module.exports = {
|
|
64
|
+
plugins: ["fsd-imports-check"],
|
|
65
|
+
|
|
66
|
+
rules: {
|
|
67
|
+
"fsd-imports-check/path-checker": "error",
|
|
68
|
+
"fsd-imports-check/layer-imports": "error",
|
|
69
|
+
"fsd-imports-check/public-api-imports": "error",
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The plugin is distributed as a CommonJS package, so the same package can be used with legacy and flat ESLint configurations.
|
|
75
|
+
|
|
76
|
+
## Configuration example
|
|
77
|
+
|
|
78
|
+
A typical FSD project can use the following configuration:
|
|
79
|
+
|
|
80
|
+
```js
|
|
81
|
+
import { defineConfig } from "eslint/config";
|
|
82
|
+
import fsdImportsCheck from "eslint-plugin-fsd-imports-check";
|
|
83
|
+
|
|
84
|
+
export default defineConfig([
|
|
85
|
+
{
|
|
86
|
+
files: ["**/*.{js,mjs,cjs,ts,tsx}"],
|
|
87
|
+
|
|
88
|
+
plugins: {
|
|
89
|
+
"fsd-imports-check": fsdImportsCheck,
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
rules: {
|
|
93
|
+
"fsd-imports-check/path-checker": [
|
|
94
|
+
"error",
|
|
95
|
+
{
|
|
96
|
+
alias: "@",
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
|
|
100
|
+
"fsd-imports-check/layer-imports": [
|
|
101
|
+
"error",
|
|
102
|
+
{
|
|
103
|
+
alias: "@",
|
|
104
|
+
ignoreImports: ["**/testing"],
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
|
|
108
|
+
"fsd-imports-check/public-api-imports": [
|
|
109
|
+
"error",
|
|
110
|
+
{
|
|
111
|
+
alias: "@",
|
|
112
|
+
autofix: true,
|
|
113
|
+
testFilesPatterns: ["**/*.test.ts", "**/*.stories.*"],
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
]);
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Rules
|
|
122
|
+
|
|
123
|
+
<!-- begin auto-generated rules list -->
|
|
124
|
+
|
|
125
|
+
🔧 Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/use/command-line-interface#fixing-problems).
|
|
126
|
+
|
|
127
|
+
| Name | Description | 🔧 |
|
|
128
|
+
| :----------------------------------------------------- | :----------------------------------------------------------- | :-- |
|
|
129
|
+
| [layer-imports](docs/rules/layer-imports.md) | Checking right layer imports (shared, widgets, pages, etc.). | |
|
|
130
|
+
| [path-checker](docs/rules/path-checker.md) | Feature sliced relative path checker. | 🔧 |
|
|
131
|
+
| [public-api-imports](docs/rules/public-api-imports.md) | Enforces importing from public APIs of FSD modules. | 🔧 |
|
|
132
|
+
|
|
133
|
+
<!-- end auto-generated rules list -->
|
|
134
|
+
|
|
135
|
+
## Rule Examples
|
|
136
|
+
|
|
137
|
+
### `path-checker`
|
|
138
|
+
|
|
139
|
+
Files belonging to the same slice should use relative imports.
|
|
140
|
+
|
|
141
|
+
Invalid:
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
// src/entities/Article/ui/ArticleDetails.ts
|
|
145
|
+
|
|
146
|
+
import { addCommentFormSlice } from "@/entities/Article/model/addCommentFormSlice";
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Valid:
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
import { addCommentFormSlice } from "../../model/addCommentFormSlice";
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
The rule does not restrict imports between different slices:
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
// src/entities/Article/file.ts
|
|
159
|
+
|
|
160
|
+
import { Profile } from "entities/Profile";
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
The rule can optionally fix invalid imports automatically.
|
|
164
|
+
|
|
165
|
+
By default, `autofix` is disabled:
|
|
166
|
+
|
|
167
|
+
```js
|
|
168
|
+
{
|
|
169
|
+
alias: "@",
|
|
170
|
+
autofix: false,
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
To enable automatic fixes:
|
|
175
|
+
|
|
176
|
+
```js
|
|
177
|
+
{
|
|
178
|
+
alias: "@",
|
|
179
|
+
autofix: true,
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### `layer-imports`
|
|
184
|
+
|
|
185
|
+
The rule enforces the following dependency direction:
|
|
186
|
+
|
|
187
|
+
```text
|
|
188
|
+
app
|
|
189
|
+
├── pages
|
|
190
|
+
├── widgets
|
|
191
|
+
├── features
|
|
192
|
+
├── shared
|
|
193
|
+
└── entities
|
|
194
|
+
|
|
195
|
+
pages
|
|
196
|
+
├── widgets
|
|
197
|
+
├── features
|
|
198
|
+
├── shared
|
|
199
|
+
└── entities
|
|
200
|
+
|
|
201
|
+
widgets
|
|
202
|
+
├── features
|
|
203
|
+
├── shared
|
|
204
|
+
└── entities
|
|
205
|
+
|
|
206
|
+
features
|
|
207
|
+
├── shared
|
|
208
|
+
└── entities
|
|
209
|
+
|
|
210
|
+
entities
|
|
211
|
+
└── shared
|
|
212
|
+
|
|
213
|
+
shared
|
|
214
|
+
└── shared
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Invalid:
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
// src/features/Auth/ui/LoginForm.ts
|
|
221
|
+
|
|
222
|
+
import { Header } from "@/widgets/Header";
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Valid:
|
|
226
|
+
|
|
227
|
+
```ts
|
|
228
|
+
import { User } from "@/entities/User";
|
|
229
|
+
import { Button } from "@/shared/Button";
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Relative imports are also checked:
|
|
233
|
+
|
|
234
|
+
```ts
|
|
235
|
+
// src/shared/index.ts
|
|
236
|
+
|
|
237
|
+
import { App } from "../app/App";
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
The import above is invalid because `shared` must not depend on `app`.
|
|
241
|
+
|
|
242
|
+
Imports from external packages are ignored:
|
|
243
|
+
|
|
244
|
+
```ts
|
|
245
|
+
import React from "react";
|
|
246
|
+
import { useLocation } from "react-router-dom";
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Specific source files and imports can also be excluded with `ignoreFiles` and `ignoreImports`.
|
|
250
|
+
|
|
251
|
+
### `public-api-imports`
|
|
252
|
+
|
|
253
|
+
Other FSD modules should normally be imported through their public API.
|
|
254
|
+
|
|
255
|
+
Invalid:
|
|
256
|
+
|
|
257
|
+
```ts
|
|
258
|
+
import { ArticleDetails } from "@/entities/Article/ui/ArticleDetails/ArticleDetails";
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Valid:
|
|
262
|
+
|
|
263
|
+
```ts
|
|
264
|
+
import { ArticleDetails } from "@/entities/Article";
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
By default, `autofix` is disabled. When enabled, ESLint can automatically replace deep imports with public API imports:
|
|
268
|
+
|
|
269
|
+
```sh
|
|
270
|
+
npx eslint src --fix
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
The rule also supports a testing public API:
|
|
274
|
+
|
|
275
|
+
```ts
|
|
276
|
+
import { testHelper } from "@/entities/Article/testing";
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
This import is allowed only in files matching `testFilesPatterns`.
|
|
280
|
+
|
|
281
|
+
For example:
|
|
282
|
+
|
|
283
|
+
```js
|
|
284
|
+
{
|
|
285
|
+
alias: "@",
|
|
286
|
+
testFilesPatterns: [
|
|
287
|
+
"**/*.test.ts",
|
|
288
|
+
"**/*.stories.*",
|
|
289
|
+
],
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
A custom testing Public API name can be configured with `testingFilename`:
|
|
294
|
+
|
|
295
|
+
```js
|
|
296
|
+
{
|
|
297
|
+
alias: "@",
|
|
298
|
+
testingFilename: "test-utils",
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Then the testing Public API becomes:
|
|
303
|
+
|
|
304
|
+
```ts
|
|
305
|
+
import { testHelper } from "@/entities/Article/test-utils";
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
## Options
|
|
309
|
+
|
|
310
|
+
### `alias`
|
|
311
|
+
|
|
312
|
+
Specifies the alias used for absolute imports.
|
|
313
|
+
|
|
314
|
+
```js
|
|
315
|
+
{
|
|
316
|
+
alias: "@",
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
For example:
|
|
321
|
+
|
|
322
|
+
```ts
|
|
323
|
+
import { Article } from "@/entities/Article";
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
Without an alias, imports such as this are also supported:
|
|
327
|
+
|
|
328
|
+
```ts
|
|
329
|
+
import { Article } from "entities/Article";
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### `ignoreFiles`
|
|
333
|
+
|
|
334
|
+
Used by all three rules to exclude source files from validation.
|
|
335
|
+
|
|
336
|
+
```js
|
|
337
|
+
{
|
|
338
|
+
ignoreFiles: [
|
|
339
|
+
"**/*.test.ts",
|
|
340
|
+
"**/*.stories.*",
|
|
341
|
+
],
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
A matching source file is completely ignored by the rule.
|
|
346
|
+
|
|
347
|
+
### `ignoreImports`
|
|
348
|
+
|
|
349
|
+
Used by `path-checker`, `layer-imports`, and `public-api-imports` to exclude specific import paths from validation.
|
|
350
|
+
|
|
351
|
+
```js
|
|
352
|
+
{
|
|
353
|
+
alias: "@",
|
|
354
|
+
ignoreImports: [
|
|
355
|
+
"@/entities/Legacy/**",
|
|
356
|
+
"**/testing",
|
|
357
|
+
],
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
Matching imports are ignored.
|
|
362
|
+
|
|
363
|
+
### `autofix`
|
|
364
|
+
|
|
365
|
+
Used by `path-checker` and `public-api-imports` to enable automatic source code fixes.
|
|
366
|
+
|
|
367
|
+
The default value is `false`.
|
|
368
|
+
|
|
369
|
+
For example:
|
|
370
|
+
|
|
371
|
+
```js
|
|
372
|
+
{
|
|
373
|
+
alias: "@",
|
|
374
|
+
autofix: true,
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
For `path-checker`, absolute imports inside the same slice are replaced with relative imports.
|
|
379
|
+
|
|
380
|
+
For `public-api-imports`, deep imports are replaced with imports from the slice public API.
|
|
381
|
+
|
|
382
|
+
### `testFilesPatterns`
|
|
383
|
+
|
|
384
|
+
Used by `public-api-imports` to define files that are allowed to import a testing public API.
|
|
385
|
+
|
|
386
|
+
```js
|
|
387
|
+
{
|
|
388
|
+
alias: "@",
|
|
389
|
+
testFilesPatterns: [
|
|
390
|
+
"**/*.test.ts",
|
|
391
|
+
"**/*.stories.*",
|
|
392
|
+
],
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
Only matching files can import:
|
|
397
|
+
|
|
398
|
+
```ts
|
|
399
|
+
import { testHelper } from "@/entities/Article/testing";
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### `testingFilename`
|
|
403
|
+
|
|
404
|
+
Used by `public-api-imports` to change the name of the testing Public API path segment.
|
|
405
|
+
|
|
406
|
+
The default value is `testing`.
|
|
407
|
+
|
|
408
|
+
For example:
|
|
409
|
+
|
|
410
|
+
```js
|
|
411
|
+
{
|
|
412
|
+
alias: "@",
|
|
413
|
+
testingFilename: "test-utils",
|
|
414
|
+
}
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
allows:
|
|
418
|
+
|
|
419
|
+
```ts
|
|
420
|
+
import { testHelper } from "@/entities/Article/test-utils";
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
## Auto-fix
|
|
424
|
+
|
|
425
|
+
The following rules provide automatic fixes when `autofix: true` is configured:
|
|
426
|
+
|
|
427
|
+
- `path-checker`
|
|
428
|
+
- `public-api-imports`
|
|
429
|
+
|
|
430
|
+
Run ESLint with:
|
|
431
|
+
|
|
432
|
+
```sh
|
|
433
|
+
npx eslint . --fix
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
`layer-imports` only reports architecture violations and does not modify source code.
|
|
437
|
+
|
|
438
|
+
## Requirements
|
|
439
|
+
|
|
440
|
+
The plugin declares ESLint as a peer dependency and can be used with supported ESLint versions that satisfy the package configuration.
|
|
441
|
+
|
|
442
|
+
Modern ESLint versions use flat configuration:
|
|
443
|
+
|
|
444
|
+
```text
|
|
445
|
+
eslint.config.js
|
|
446
|
+
eslint.config.mjs
|
|
447
|
+
eslint.config.cjs
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
Older ESLint versions can use:
|
|
451
|
+
|
|
452
|
+
```text
|
|
453
|
+
.eslintrc.js
|
|
454
|
+
.eslintrc.json
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
The plugin itself is implemented in TypeScript and distributed as compiled JavaScript.
|
|
458
|
+
|
|
459
|
+
## Documentation
|
|
460
|
+
|
|
461
|
+
Detailed documentation for each rule:
|
|
462
|
+
|
|
463
|
+
- [layer-imports](docs/rules/layer-imports.md)
|
|
464
|
+
- [path-checker](docs/rules/path-checker.md)
|
|
465
|
+
- [public-api-imports](docs/rules/public-api-imports.md)
|
|
466
|
+
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# fsd-imports-check/layer-imports
|
|
2
|
+
|
|
3
|
+
📝 Checking right layer imports (shared, widgets, pages, etc.).
|
|
4
|
+
|
|
5
|
+
<!-- end auto-generated rule header -->
|
|
6
|
+
|
|
7
|
+
The rule enforces the dependency direction between layers in a Feature-Sliced Design (FSD) project.
|
|
8
|
+
|
|
9
|
+
A layer can import only from the layers located below it in the project architecture. Imports that violate this dependency direction are reported as errors.
|
|
10
|
+
|
|
11
|
+
The rule supports both absolute imports, such as `@/shared/Button`, and relative imports, such as `../../shared/Button`. Relative imports are resolved against the current file before the target layer is determined.
|
|
12
|
+
|
|
13
|
+
Imports from external packages such as `react` or `react-router-dom` are ignored because they do not belong to the FSD layer structure.
|
|
14
|
+
|
|
15
|
+
## Rule Details
|
|
16
|
+
|
|
17
|
+
The following layer dependencies are allowed:
|
|
18
|
+
|
|
19
|
+
| Current layer | Allowed imports |
|
|
20
|
+
| :------------ | :--------------------------------------------------- |
|
|
21
|
+
| `app` | `pages`, `widgets`, `features`, `shared`, `entities` |
|
|
22
|
+
| `pages` | `widgets`, `features`, `shared`, `entities` |
|
|
23
|
+
| `widgets` | `features`, `shared`, `entities` |
|
|
24
|
+
| `features` | `shared`, `entities` |
|
|
25
|
+
| `entities` | `shared`, `entities` |
|
|
26
|
+
| `shared` | `shared` |
|
|
27
|
+
|
|
28
|
+
For example, `features` can import from `entities` and `shared`, but cannot import from `widgets`, `pages`, or `app`.
|
|
29
|
+
|
|
30
|
+
Examples of **incorrect** code for this rule:
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
// src/features/Auth/ui/LoginForm.ts
|
|
34
|
+
|
|
35
|
+
import { Header } from "@/widgets/Header";
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
// src/shared/index.ts
|
|
40
|
+
|
|
41
|
+
import { App } from "../app/App";
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
// src/entities/Article/ui/ArticleDetails.ts
|
|
46
|
+
|
|
47
|
+
import { Auth } from "@/features/Auth";
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
In these examples, the current layer imports from a layer that is not allowed by the FSD dependency direction.
|
|
51
|
+
|
|
52
|
+
Examples of **correct** code for this rule:
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
// src/features/Auth/ui/LoginForm.ts
|
|
56
|
+
|
|
57
|
+
import { User } from "@/entities/User";
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
// src/features/Auth/ui/LoginForm.ts
|
|
62
|
+
|
|
63
|
+
import { Button } from "@/shared/Button";
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
// src/entities/Article/ui/ArticleDetails.ts
|
|
68
|
+
|
|
69
|
+
import { Button } from "../../shared/Button";
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Relative imports are also checked when they point to another FSD layer:
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
// src/entities/Article/file.ts
|
|
76
|
+
|
|
77
|
+
import { Button } from "../../shared/Button";
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Here the relative path resolves to the `shared` layer, which is allowed for `entities`.
|
|
81
|
+
|
|
82
|
+
External dependencies are ignored:
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import React from "react";
|
|
86
|
+
import { useLocation } from "react-router-dom";
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Options
|
|
90
|
+
|
|
91
|
+
<!-- begin auto-generated rule options list -->
|
|
92
|
+
|
|
93
|
+
| Name | Description | Type | Default |
|
|
94
|
+
| :-------------- | :----------------------------------------------------- | :------- | :------ |
|
|
95
|
+
| `alias` | Alias used for absolute imports, for example '@'. | String | `` |
|
|
96
|
+
| `ignoreFiles` | Glob patterns for source files that should be ignored. | String[] | `[]` |
|
|
97
|
+
| `ignoreImports` | Glob patterns for imports that should be ignored. | String[] | `[]` |
|
|
98
|
+
|
|
99
|
+
<!-- end auto-generated rule options list -->
|
|
100
|
+
|
|
101
|
+
### `alias`
|
|
102
|
+
|
|
103
|
+
The `alias` option specifies the alias used for absolute project imports.
|
|
104
|
+
|
|
105
|
+
For example:
|
|
106
|
+
|
|
107
|
+
```js
|
|
108
|
+
{
|
|
109
|
+
alias: "@";
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
the following import is treated as an import from the `shared` layer:
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
import { Button } from "@/shared/Button";
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Without an alias, imports such as the following are also supported:
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
import { Button } from "shared/Button";
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### `ignoreFiles`
|
|
126
|
+
|
|
127
|
+
The `ignoreFiles` option allows entire source files to be excluded from layer checking.
|
|
128
|
+
|
|
129
|
+
Patterns use glob syntax.
|
|
130
|
+
|
|
131
|
+
For example:
|
|
132
|
+
|
|
133
|
+
```js
|
|
134
|
+
{
|
|
135
|
+
alias: "@",
|
|
136
|
+
ignoreFiles: [
|
|
137
|
+
"**/*.stories.tsx",
|
|
138
|
+
"**/*.test.ts"
|
|
139
|
+
]
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
With this configuration, imports inside matching files are not checked by `layer-imports`.
|
|
144
|
+
|
|
145
|
+
This can be useful for Storybook files, tests, generated files, or other parts of the project that intentionally do not follow the regular layer dependency rules.
|
|
146
|
+
|
|
147
|
+
### `ignoreImports`
|
|
148
|
+
|
|
149
|
+
The `ignoreImports` option allows individual imports to be excluded from layer checking.
|
|
150
|
+
|
|
151
|
+
Patterns use glob syntax.
|
|
152
|
+
|
|
153
|
+
For example:
|
|
154
|
+
|
|
155
|
+
```js
|
|
156
|
+
{
|
|
157
|
+
alias: "@",
|
|
158
|
+
ignoreImports: [
|
|
159
|
+
"**/testing",
|
|
160
|
+
"**/testing/**",
|
|
161
|
+
"**/*.module.scss"
|
|
162
|
+
]
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
The following imports will then be ignored by the rule:
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
import { testHelper } from "@/features/Auth/testing";
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
import styles from "@/features/Auth/ui/LoginForm.module.scss";
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Unlike `ignoreFiles`, this option does not disable checking for the entire file. Other imports in the same file are still checked.
|
|
177
|
+
|
|
178
|
+
## When Not To Use It
|
|
179
|
+
|
|
180
|
+
Do not use this rule if the project does not follow Feature-Sliced Design or intentionally allows dependencies between layers that violate the standard FSD dependency direction.
|
|
181
|
+
|
|
182
|
+
It may also be inappropriate for projects with a different architectural model or for parts of the codebase where layer boundaries are intentionally relaxed.
|
|
183
|
+
|
|
184
|
+
## Further Reading
|
|
185
|
+
|
|
186
|
+
- [Feature-Sliced Design](https://feature-sliced.design/)
|
|
187
|
+
- [Feature-Sliced Design: Layers](https://feature-sliced.design/docs/reference/layers)
|
|
188
|
+
|