eslint-plugin-import-boundaries 0.2.1 → 0.3.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/README.md +209 -36
- package/eslint-plugin-import-boundaries.js +4 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[](https://www.npmjs.com/package/eslint-plugin-import-boundaries)
|
|
6
6
|
[](https://opensource.org/licenses/ISC)
|
|
7
7
|
|
|
8
|
-
**Note: This is
|
|
8
|
+
**Note: This is an alpha release, originally developed for a personal project. It is not yet stable and may have breaking changes.**
|
|
9
9
|
|
|
10
10
|
An opinionated ESLint rule that enforces architectural boundaries using deterministic import path rules. This rule determines when to use alias vs relative imports based on your architecture, rather than enforcing a single pattern for all imports.
|
|
11
11
|
|
|
@@ -20,6 +20,7 @@ An opinionated ESLint rule that enforces architectural boundaries using determin
|
|
|
20
20
|
- **Auto-fixable**: Legal import paths are auto-fixable and will always converge to the correct import string.
|
|
21
21
|
- **Zero I/O**: Pure path math and AST analysis - fast even on large codebases
|
|
22
22
|
- **Type-aware**: Different rules for type-only imports vs value imports
|
|
23
|
+
- **Test-ready**: Flexible configuration for test files (skip boundary rules while maintaining path format)
|
|
23
24
|
- **Circular Dependency Prevention**: Blocks ancestor barrel imports
|
|
24
25
|
- **Configurable**: Works with any architectural pattern
|
|
25
26
|
|
|
@@ -29,6 +30,8 @@ An opinionated ESLint rule that enforces architectural boundaries using determin
|
|
|
29
30
|
npm install --save-dev eslint-plugin-import-boundaries
|
|
30
31
|
```
|
|
31
32
|
|
|
33
|
+
### Using Alias Paths (Default)
|
|
34
|
+
|
|
32
35
|
```javascript
|
|
33
36
|
// eslint.config.js
|
|
34
37
|
import importBoundaries from "eslint-plugin-import-boundaries";
|
|
@@ -42,6 +45,7 @@ export default {
|
|
|
42
45
|
"error",
|
|
43
46
|
{
|
|
44
47
|
rootDir: "src",
|
|
48
|
+
crossBoundaryStyle: "alias", // Default: use alias paths
|
|
45
49
|
boundaries: [
|
|
46
50
|
{ dir: "domain", alias: "@domain" },
|
|
47
51
|
{ dir: "application", alias: "@application" },
|
|
@@ -53,6 +57,21 @@ export default {
|
|
|
53
57
|
};
|
|
54
58
|
```
|
|
55
59
|
|
|
60
|
+
**Import patterns with aliases:**
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
// Cross-boundary imports → use alias
|
|
64
|
+
import { Entity } from "@domain"; // ✅
|
|
65
|
+
import { UseCase } from "@application"; // ✅
|
|
66
|
+
|
|
67
|
+
// Same-boundary, close imports → use relative
|
|
68
|
+
import { helper } from "./helper"; // ✅ Same directory
|
|
69
|
+
import { utils } from "../utils"; // ✅ Parent's sibling
|
|
70
|
+
|
|
71
|
+
// Same-boundary, distant imports → use alias
|
|
72
|
+
import { useCase } from "@application/use-cases"; // ✅ Distant in same boundary
|
|
73
|
+
```
|
|
74
|
+
|
|
56
75
|
## What Problem Does This Solve?
|
|
57
76
|
|
|
58
77
|
Most projects suffer from inconsistent import patterns that create ambiguity and technical debt:
|
|
@@ -104,8 +123,8 @@ import { helper } from "./helper"; // ✅
|
|
|
104
123
|
// Parent's sibling (cousin, max one ../)
|
|
105
124
|
import { utils } from "../utils"; // ✅
|
|
106
125
|
|
|
107
|
-
//
|
|
108
|
-
import { useCase } from "@application/
|
|
126
|
+
// Distant within same boundary → Use alias (with subpath allowed for same-boundary imports)
|
|
127
|
+
import { useCase } from "@application/use-cases"; // ✅ Same boundary, distant location
|
|
109
128
|
```
|
|
110
129
|
|
|
111
130
|
### 3. Architectural Boundary Enforcement
|
|
@@ -116,8 +135,8 @@ Prevent violations of your architecture:
|
|
|
116
135
|
{
|
|
117
136
|
dir: 'application',
|
|
118
137
|
alias: '@application',
|
|
119
|
-
allowImportsFrom: ['@domain'], // Only allow imports from @domain
|
|
120
|
-
|
|
138
|
+
allowImportsFrom: ['@domain'], // Only allow imports from @domain (deny-all by default)
|
|
139
|
+
// Note: denyImportsFrom is redundant here - anything not in allowImportsFrom is already denied
|
|
121
140
|
}
|
|
122
141
|
```
|
|
123
142
|
|
|
@@ -132,38 +151,85 @@ import { Database } from "@infrastructure";
|
|
|
132
151
|
|
|
133
152
|
#### Nested Boundaries
|
|
134
153
|
|
|
135
|
-
Boundaries can be nested, and each boundary must explicitly declare its import rules:
|
|
154
|
+
Boundaries can be nested, and each boundary must explicitly declare its import rules. Each nested boundary has its own independent rules (no inheritance from parent boundaries):
|
|
136
155
|
|
|
137
156
|
```javascript
|
|
138
157
|
{
|
|
139
158
|
boundaries: [
|
|
140
159
|
{
|
|
141
|
-
dir: '
|
|
142
|
-
alias: '@
|
|
143
|
-
allowImportsFrom: ['@domain'],
|
|
160
|
+
dir: 'interface',
|
|
161
|
+
alias: '@interface',
|
|
162
|
+
allowImportsFrom: ['@application', '@domain'], // @interface can import from @application and @domain
|
|
163
|
+
// Implicitly denies all other boundaries (including @infrastructure, @composition, etc.)
|
|
144
164
|
},
|
|
145
165
|
{
|
|
146
|
-
dir: '
|
|
147
|
-
alias: '@
|
|
148
|
-
allowImportsFrom: ['@
|
|
166
|
+
dir: 'interface/api',
|
|
167
|
+
alias: '@api',
|
|
168
|
+
allowImportsFrom: ['@domain', '@public-use-cases'],
|
|
169
|
+
// @api (public REST API) only allows public use cases, not all of @application
|
|
170
|
+
// This demonstrates selective access within an allowed parent boundary
|
|
171
|
+
// Note: @public-use-cases and @internal-use-cases would be separate boundaries
|
|
172
|
+
// defined elsewhere in your boundaries array
|
|
173
|
+
denyImportsFrom: ['@internal-use-cases'],
|
|
149
174
|
},
|
|
150
175
|
{
|
|
151
|
-
dir: 'interface',
|
|
152
|
-
alias: '@
|
|
153
|
-
allowImportsFrom: ['@application', '@
|
|
154
|
-
|
|
176
|
+
dir: 'interface/graphql',
|
|
177
|
+
alias: '@graphql',
|
|
178
|
+
allowImportsFrom: ['@application', '@domain'],
|
|
179
|
+
// @graphql can import from all of @application (different rules than @api sibling)
|
|
180
|
+
// This shows how sibling boundaries can have different rules
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
dir: 'composition',
|
|
184
|
+
alias: '@composition',
|
|
185
|
+
allowImportsFrom: ['@domain', '@application', '@infrastructure', '@interface'],
|
|
186
|
+
// @composition can import from all boundaries (wiring layer)
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
dir: 'composition/di',
|
|
190
|
+
alias: '@di',
|
|
191
|
+
allowImportsFrom: ['@domain', '@application', '@infrastructure'],
|
|
192
|
+
// @di (dependency injection setup) doesn't need @interface
|
|
193
|
+
// This shows how nested boundaries can be more restrictive than parent
|
|
155
194
|
},
|
|
156
195
|
],
|
|
157
196
|
}
|
|
158
197
|
```
|
|
159
198
|
|
|
199
|
+
**Example behavior:**
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
// File: interface/api/user-controller.ts
|
|
203
|
+
import { Entity } from "@domain"; // ✅ Allowed: @api can import from @domain
|
|
204
|
+
import { CreateUser } from "@public-use-cases"; // ✅ Allowed: @api can import from @public-use-cases
|
|
205
|
+
import { InternalAudit } from "@internal-use-cases"; // ❌ Violation: @api explicitly denies @internal-use-cases
|
|
206
|
+
|
|
207
|
+
// File: interface/graphql/user-resolver.ts
|
|
208
|
+
import { Entity } from "@domain"; // ✅ Allowed: @graphql can import from @domain
|
|
209
|
+
import { CreateUser } from "@public-use-cases"; // ✅ Allowed: @graphql can import from any @application code
|
|
210
|
+
import { InternalAudit } from "@internal-use-cases"; // ✅ Allowed: @graphql has different rules than @api sibling
|
|
211
|
+
|
|
212
|
+
// File: composition/di/container.ts
|
|
213
|
+
import { Repository } from "@infrastructure"; // ✅ Allowed: @di can import from @infrastructure for wiring
|
|
214
|
+
import { UseCase } from "@application"; // ✅ Allowed: @di can import from @application
|
|
215
|
+
import { Controller } from "@interface"; // ❌ Violation: @di cannot import from @interface (more restrictive than parent)
|
|
216
|
+
```
|
|
217
|
+
|
|
160
218
|
**Key behaviors:**
|
|
161
219
|
|
|
162
|
-
- Each boundary
|
|
163
|
-
-
|
|
220
|
+
- Each boundary has rules: explicit (via `allowImportsFrom`/`denyImportsFrom`) or implicit "deny all" (if neither is specified)
|
|
221
|
+
- Each boundary uses its own rules directly (no inheritance from parent boundaries)
|
|
164
222
|
- Rules work the same regardless of nesting depth (flat rule checking)
|
|
165
223
|
- You can selectively allow/deny specific nested boundaries
|
|
166
|
-
-
|
|
224
|
+
- Files resolve to their most specific boundary (longest matching path), which determines the rules to apply
|
|
225
|
+
|
|
226
|
+
**Rule semantics:**
|
|
227
|
+
|
|
228
|
+
- If both `allowImportsFrom` and `denyImportsFrom` exist: `allowImportsFrom` takes precedence (items in allow list are allowed even if also in deny list)
|
|
229
|
+
- If only `allowImportsFrom`: deny-all by default (only items in allow list are allowed)
|
|
230
|
+
- If only `denyImportsFrom`: allow-all by default (everything except deny list is allowed)
|
|
231
|
+
- If neither: deny-all by default (strictest)
|
|
232
|
+
- **Important**: When `allowImportsFrom` is specified, `denyImportsFrom` can deny specific sub-boundaries (e.g. deny `@utils` within allowed `@application`), but is otherwise redundant since anything not in the allow list is already denied by default. Note that this works recursively: It is possible to allow a boundary within a denied boundary within an allowed boundary, and so on.
|
|
167
233
|
|
|
168
234
|
### 4. Type-Only Imports
|
|
169
235
|
|
|
@@ -201,27 +267,23 @@ import { something } from "@application"; // When inside @application boundary
|
|
|
201
267
|
|
|
202
268
|
### Basic Configuration
|
|
203
269
|
|
|
270
|
+
Here's a complete configuration example with all boundary rules:
|
|
271
|
+
|
|
204
272
|
```javascript
|
|
205
273
|
{
|
|
206
|
-
rootDir: 'src', // Root directory (default: 'src')
|
|
207
|
-
crossBoundaryStyle: 'alias', // 'alias' | 'absolute' (default: 'alias')
|
|
208
|
-
defaultSeverity: 'error', // 'error' | 'warn' (default: 'error')
|
|
209
|
-
allowUnknownBoundaries: false, // Allow imports outside boundaries (default: false)
|
|
210
|
-
skipBoundaryRulesForTestFiles: true, // Skip boundary rules for tests (default: true)
|
|
211
|
-
barrelFileName: 'index', // Barrel file name without extension (default: 'index')
|
|
212
|
-
fileExtensions: ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'], // Extensions to recognize (default: all common JS/TS extensions)
|
|
274
|
+
rootDir: 'src', // Required: Root directory (default: 'src')
|
|
213
275
|
boundaries: [ // Required: Array of boundary definitions
|
|
214
276
|
{
|
|
215
277
|
dir: 'domain', // Required: Relative directory path
|
|
216
|
-
alias: '@domain', // Required
|
|
217
|
-
denyImportsFrom: ['@application', '@infrastructure', '@interface', '@composition'], // Domain is pure
|
|
278
|
+
alias: '@domain', // Required: Import alias (e.g., '@domain')
|
|
279
|
+
denyImportsFrom: ['@application', '@infrastructure', '@interface', '@composition'], // Domain is pure - denies all other boundaries
|
|
218
280
|
severity: 'error', // Optional: 'error' | 'warn' (overrides defaultSeverity for this boundary)
|
|
219
281
|
},
|
|
220
282
|
{
|
|
221
283
|
dir: 'application',
|
|
222
284
|
alias: '@application',
|
|
223
|
-
allowImportsFrom: ['@domain'], // Application uses domain
|
|
224
|
-
|
|
285
|
+
allowImportsFrom: ['@domain'], // Application uses domain (deny-all by default)
|
|
286
|
+
// Note: denyImportsFrom is redundant here - anything not in allowImportsFrom is already denied
|
|
225
287
|
},
|
|
226
288
|
{
|
|
227
289
|
dir: 'infrastructure',
|
|
@@ -230,34 +292,92 @@ import { something } from "@application"; // When inside @application boundary
|
|
|
230
292
|
allowTypeImportsFrom: ['@application'], // Infrastructure implements application ports (types only)
|
|
231
293
|
},
|
|
232
294
|
],
|
|
295
|
+
// Optional configuration options (all have sensible defaults):
|
|
296
|
+
defaultSeverity: 'error', // 'error' | 'warn' (default: 'error')
|
|
297
|
+
enforceBoundaries: true, // Enforce boundary rules (default: true)
|
|
298
|
+
allowUnknownBoundaries: false, // Allow imports outside boundaries (default: false)
|
|
299
|
+
barrelFileName: 'index', // Barrel file name without extension (default: 'index')
|
|
300
|
+
fileExtensions: ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'], // Extensions to recognize (default: all common JS/TS extensions)
|
|
233
301
|
}
|
|
234
302
|
```
|
|
235
303
|
|
|
304
|
+
**Important:** The `enforceBoundaries` option applies globally to all files when set. To have different behavior for test files vs regular files, you must use ESLint's file matching (see Test Files Configuration below).
|
|
305
|
+
|
|
236
306
|
### Test Files Configuration
|
|
237
307
|
|
|
238
|
-
|
|
308
|
+
**How test exclusion works:** When `enforceBoundaries: false`, the rule skips boundary rule checking (allow/deny rules) but still enforces path format (alias vs relative). This allows test files to import from any boundary while maintaining consistent import path patterns. The default is `true` (boundary rules are enforced by default).
|
|
309
|
+
|
|
310
|
+
**Why skip boundary rules for tests?** Test files often need to:
|
|
311
|
+
|
|
312
|
+
- Import from multiple boundaries to set up test scenarios (e.g., mocking infrastructure while testing application logic)
|
|
313
|
+
- Use test helper libraries or mocks that don't fit clean architectural boundaries
|
|
314
|
+
- Access internal implementation details for thorough testing
|
|
315
|
+
- Create test fixtures that span multiple boundaries
|
|
316
|
+
|
|
317
|
+
By setting `enforceBoundaries: false` for test files, you maintain architectural boundaries in production code while giving tests the flexibility they need. Path format (alias vs relative) is still enforced, keeping import paths consistent and readable.
|
|
318
|
+
|
|
319
|
+
**Alternative approach:** You can also define separate boundaries for test directories (e.g., `test/domain`, `test/application`) with their own import rules, but this has two downsides: it discourages test collocation (tests must live in separate test directories rather than alongside source files), and it requires much more configuration overhead than most projects need. The `enforceBoundaries: false` approach is simpler and sufficient for most use cases.
|
|
320
|
+
|
|
321
|
+
**Configuration pattern:** Use ESLint's file matching to apply different configs to test files vs regular files. Define boundaries once and reuse them in both config blocks:
|
|
239
322
|
|
|
240
323
|
```javascript
|
|
324
|
+
import importBoundaries from "eslint-plugin-import-boundaries";
|
|
325
|
+
|
|
326
|
+
// Define boundaries once - shared between regular files and test files
|
|
327
|
+
const boundaries = [
|
|
328
|
+
{
|
|
329
|
+
dir: "domain",
|
|
330
|
+
alias: "@domain",
|
|
331
|
+
// No imports allowed by default
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
dir: "application",
|
|
335
|
+
alias: "@application",
|
|
336
|
+
allowImportsFrom: ["@domain"],
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
dir: "infrastructure",
|
|
340
|
+
alias: "@infrastructure",
|
|
341
|
+
allowImportsFrom: ["@domain"],
|
|
342
|
+
},
|
|
343
|
+
];
|
|
344
|
+
|
|
241
345
|
export default [
|
|
346
|
+
// Test files - skip boundary rules but keep path format enforcement
|
|
347
|
+
// Put test files first so they take precedence over regular file patterns
|
|
242
348
|
{
|
|
243
|
-
files: [
|
|
349
|
+
files: [
|
|
350
|
+
"**/*.test.{ts,js}",
|
|
351
|
+
"**/*.spec.{ts,js}",
|
|
352
|
+
"**/__tests__/**/*.{ts,js}",
|
|
353
|
+
],
|
|
244
354
|
rules: {
|
|
245
355
|
"import-boundaries/enforce": [
|
|
246
356
|
"error",
|
|
247
357
|
{
|
|
248
|
-
|
|
358
|
+
rootDir: "src",
|
|
359
|
+
enforceBoundaries: false, // Tests can import from any boundary
|
|
360
|
+
boundaries, // Same boundaries - needed for path format calculation
|
|
249
361
|
},
|
|
250
362
|
],
|
|
251
363
|
},
|
|
252
364
|
},
|
|
365
|
+
// Regular source files - enforce boundary rules
|
|
366
|
+
// Excludes test files via ignores to prevent overlap
|
|
253
367
|
{
|
|
254
|
-
files: ["
|
|
368
|
+
files: ["src/**/*.ts", "src/**/*.tsx"],
|
|
369
|
+
ignores: [
|
|
370
|
+
"**/*.test.{ts,js}",
|
|
371
|
+
"**/*.spec.{ts,js}",
|
|
372
|
+
"**/__tests__/**/*.{ts,js}",
|
|
373
|
+
],
|
|
255
374
|
rules: {
|
|
256
375
|
"import-boundaries/enforce": [
|
|
257
376
|
"error",
|
|
258
377
|
{
|
|
259
|
-
|
|
260
|
-
//
|
|
378
|
+
rootDir: "src",
|
|
379
|
+
enforceBoundaries: true, // Enforce boundary rules
|
|
380
|
+
boundaries,
|
|
261
381
|
},
|
|
262
382
|
],
|
|
263
383
|
},
|
|
@@ -265,6 +385,59 @@ export default [
|
|
|
265
385
|
];
|
|
266
386
|
```
|
|
267
387
|
|
|
388
|
+
**What gets checked in test files:**
|
|
389
|
+
|
|
390
|
+
- ✅ Path format (alias vs relative) - still enforced
|
|
391
|
+
- ✅ Barrel file imports - still enforced
|
|
392
|
+
- ✅ Ancestor barrel prevention - still enforced
|
|
393
|
+
- ❌ Boundary allow/deny rules - **skipped** (tests can import from any boundary)
|
|
394
|
+
|
|
395
|
+
**What gets checked in regular files:**
|
|
396
|
+
|
|
397
|
+
- ✅ Path format (alias vs relative)
|
|
398
|
+
- ✅ Barrel file imports
|
|
399
|
+
- ✅ Ancestor barrel prevention
|
|
400
|
+
- ✅ Boundary allow/deny rules - **enforced**
|
|
401
|
+
|
|
402
|
+
### Using Absolute Paths
|
|
403
|
+
|
|
404
|
+
By default, the rule uses alias paths (e.g., `@domain`). If your build configuration doesn't support path aliases, or you prefer absolute paths, you can use `crossBoundaryStyle: 'absolute'`:
|
|
405
|
+
|
|
406
|
+
```javascript
|
|
407
|
+
{
|
|
408
|
+
rootDir: 'src',
|
|
409
|
+
crossBoundaryStyle: 'absolute', // Use absolute paths instead of aliases
|
|
410
|
+
boundaries: [
|
|
411
|
+
{ dir: 'domain' }, // No alias required when using absolute paths
|
|
412
|
+
{ dir: 'application' },
|
|
413
|
+
{ dir: 'infrastructure' },
|
|
414
|
+
],
|
|
415
|
+
}
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
**Import patterns with absolute paths:**
|
|
419
|
+
|
|
420
|
+
```typescript
|
|
421
|
+
// Cross-boundary imports → use absolute path
|
|
422
|
+
import { Entity } from "src/domain"; // ✅
|
|
423
|
+
import { UseCase } from "src/application"; // ✅
|
|
424
|
+
|
|
425
|
+
// Same-boundary, close imports → use relative (same as alias style)
|
|
426
|
+
import { helper } from "./helper"; // ✅ Same directory
|
|
427
|
+
import { utils } from "../utils"; // ✅ Parent's sibling
|
|
428
|
+
|
|
429
|
+
// Same-boundary, distant imports → use absolute path
|
|
430
|
+
import { useCase } from "src/application/use-cases"; // ✅ Distant in same boundary
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
**When to use absolute paths:**
|
|
434
|
+
|
|
435
|
+
- Your build configuration doesn't support path aliases (e.g., some bundlers or older tooling)
|
|
436
|
+
- You prefer explicit paths over aliases for clarity
|
|
437
|
+
- You're working in a codebase that already uses absolute paths
|
|
438
|
+
|
|
439
|
+
**Note:** Alias paths are recommended for readability, especially for boundaries defined at deeper directory levels (e.g., `@entities/user` vs `src/hexagonal/domain/entities/user`). However, this rule does not require them since not all build configurations support path aliases. When using `crossBoundaryStyle: 'absolute'`, the `alias` property in boundary definitions becomes optional, and the rule will use paths like `src/domain` instead of `@domain`.
|
|
440
|
+
|
|
268
441
|
## How It Works
|
|
269
442
|
|
|
270
443
|
The rule uses pure path math - no file I/O, just deterministic algorithms:
|
|
@@ -100,22 +100,6 @@ function resolveToBoundary(filename, boundaries) {
|
|
|
100
100
|
return null;
|
|
101
101
|
}
|
|
102
102
|
/**
|
|
103
|
-
* Resolve a file to the nearest boundary that has rules specified.
|
|
104
|
-
* If no boundaries with rules are found, returns null.
|
|
105
|
-
* Used for file boundaries - allows inheritance from ancestors with rules.
|
|
106
|
-
*
|
|
107
|
-
* @param filename - Absolute filename
|
|
108
|
-
* @param boundaries - Array of all boundaries
|
|
109
|
-
* @returns The nearest boundary with rules, or null if none found
|
|
110
|
-
*/
|
|
111
|
-
function resolveToSpecifiedBoundary(filename, boundaries) {
|
|
112
|
-
const specifiedBoundaries = boundaries.filter((b) => isInsideDir(b.absDir, filename)).filter((b) => b.allowImportsFrom !== void 0 || b.denyImportsFrom !== void 0 || b.allowTypeImportsFrom !== void 0);
|
|
113
|
-
if (specifiedBoundaries.length > 0) return specifiedBoundaries.sort((a, b) => b.absDir.length - a.absDir.length)[0];
|
|
114
|
-
const ancestors = boundaries.filter((b) => b.allowImportsFrom !== void 0 || b.denyImportsFrom !== void 0 || b.allowTypeImportsFrom !== void 0).filter((b) => isInsideDir(b.absDir, filename));
|
|
115
|
-
if (ancestors.length > 0) return ancestors.sort((a, b) => b.absDir.length - a.absDir.length)[0];
|
|
116
|
-
return null;
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
103
|
* Get metadata about the current file being linted.
|
|
120
104
|
* Results are cached per file to avoid recomputation.
|
|
121
105
|
*
|
|
@@ -128,7 +112,7 @@ function getFileData(filename, boundaries) {
|
|
|
128
112
|
return {
|
|
129
113
|
isValid: true,
|
|
130
114
|
fileDir: path.dirname(filename),
|
|
131
|
-
fileBoundary:
|
|
115
|
+
fileBoundary: resolveToBoundary(filename, boundaries)
|
|
132
116
|
};
|
|
133
117
|
}
|
|
134
118
|
|
|
@@ -513,7 +497,7 @@ const rule = {
|
|
|
513
497
|
type: "boolean",
|
|
514
498
|
default: false
|
|
515
499
|
},
|
|
516
|
-
|
|
500
|
+
enforceBoundaries: {
|
|
517
501
|
type: "boolean",
|
|
518
502
|
default: true
|
|
519
503
|
},
|
|
@@ -545,7 +529,7 @@ const rule = {
|
|
|
545
529
|
},
|
|
546
530
|
create(context) {
|
|
547
531
|
if (!context.options || context.options.length === 0) throw new Error("boundary-alias-vs-relative requires boundaries configuration");
|
|
548
|
-
const { rootDir = "src", boundaries, crossBoundaryStyle = "alias", defaultSeverity, allowUnknownBoundaries = false,
|
|
532
|
+
const { rootDir = "src", boundaries, crossBoundaryStyle = "alias", defaultSeverity, allowUnknownBoundaries = false, enforceBoundaries = true, barrelFileName = "index", fileExtensions = [
|
|
549
533
|
".ts",
|
|
550
534
|
".tsx",
|
|
551
535
|
".js",
|
|
@@ -608,7 +592,7 @@ const rule = {
|
|
|
608
592
|
defaultSeverity,
|
|
609
593
|
allowUnknownBoundaries,
|
|
610
594
|
isTypeOnly,
|
|
611
|
-
skipBoundaryRules:
|
|
595
|
+
skipBoundaryRules: !enforceBoundaries,
|
|
612
596
|
barrelFileName,
|
|
613
597
|
fileExtensions
|
|
614
598
|
});
|
package/package.json
CHANGED