eslint-plugin-barrel-rules 1.4.3 → 1.4.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.ko.md +1 -1
- package/README.md +1 -1
- package/dist/index.cjs +310 -263
- package/dist/index.js +310 -270
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -55,54 +55,124 @@ var Glob = class {
|
|
|
55
55
|
// src/utils/alias.ts
|
|
56
56
|
var import_tsconfig_paths = require("tsconfig-paths");
|
|
57
57
|
var import_path = __toESM(require("path"), 1);
|
|
58
|
-
var Alias = class {
|
|
58
|
+
var Alias = class _Alias {
|
|
59
59
|
constructor() {
|
|
60
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Resolves an alias path to an absolute file path
|
|
63
|
+
*
|
|
64
|
+
* @param rawPath - The alias path to resolve (e.g., "@entities/user", "@utils")
|
|
65
|
+
* @param currentFileDir - The directory of the current file (used to find tsconfig.json)
|
|
66
|
+
* @returns Result object with absolutePath and type ("success" or "fail")
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* // With wildcard alias: "@entities/*" -> "src/entities/*"
|
|
70
|
+
* Alias.resolvePath("@entities/user", "/project/src/features")
|
|
71
|
+
* // Returns: { absolutePath: "/project/src/entities/user", type: "success" }
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* // Without wildcard: "@utils" -> "src/utils/index"
|
|
75
|
+
* Alias.resolvePath("@utils", "/project/src/features")
|
|
76
|
+
* // Returns: { absolutePath: "/project/src/utils/index", type: "success" }
|
|
77
|
+
*/
|
|
61
78
|
static resolvePath(rawPath, currentFileDir) {
|
|
62
79
|
try {
|
|
63
80
|
const configResult = (0, import_tsconfig_paths.loadConfig)(currentFileDir);
|
|
64
|
-
if (configResult.resultType
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return {
|
|
79
|
-
absolutePath,
|
|
80
|
-
type: "success"
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
} else {
|
|
84
|
-
if (rawPath === pattern) {
|
|
85
|
-
const absolutePath = import_path.default.resolve(
|
|
86
|
-
`${configResult.absoluteBaseUrl}/${origin}`
|
|
87
|
-
);
|
|
88
|
-
return {
|
|
89
|
-
absolutePath,
|
|
90
|
-
type: "success"
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
}
|
|
81
|
+
if (configResult.resultType !== "success") {
|
|
82
|
+
return this.createFailResult(rawPath);
|
|
83
|
+
}
|
|
84
|
+
const { paths, absoluteBaseUrl } = configResult;
|
|
85
|
+
for (const [aliasPattern, targetPaths] of Object.entries(paths)) {
|
|
86
|
+
const targetPath = targetPaths[0];
|
|
87
|
+
const matchResult = this.tryMatchPattern(
|
|
88
|
+
rawPath,
|
|
89
|
+
aliasPattern,
|
|
90
|
+
targetPath,
|
|
91
|
+
absoluteBaseUrl
|
|
92
|
+
);
|
|
93
|
+
if (matchResult) {
|
|
94
|
+
return matchResult;
|
|
94
95
|
}
|
|
95
96
|
}
|
|
96
|
-
return
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
97
|
+
return _Alias.createFailResult(rawPath);
|
|
98
|
+
} catch (error) {
|
|
99
|
+
return _Alias.createFailResult(rawPath);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Attempts to match a raw path against an alias pattern
|
|
104
|
+
*
|
|
105
|
+
* @param rawPath - The path to match (e.g., "@entities/user")
|
|
106
|
+
* @param aliasPattern - The alias pattern from tsconfig (e.g., "@entities/*")
|
|
107
|
+
* @param targetPath - The target path from tsconfig (e.g., "src/entities/*")
|
|
108
|
+
* @param baseUrl - The absolute base URL from tsconfig
|
|
109
|
+
* @returns Success result if matched, null otherwise
|
|
110
|
+
*/
|
|
111
|
+
static tryMatchPattern(rawPath, aliasPattern, targetPath, baseUrl) {
|
|
112
|
+
const hasWildcard = aliasPattern.includes("*");
|
|
113
|
+
if (hasWildcard) {
|
|
114
|
+
return this.matchWildcardPattern(
|
|
115
|
+
rawPath,
|
|
116
|
+
aliasPattern,
|
|
117
|
+
targetPath,
|
|
118
|
+
baseUrl
|
|
119
|
+
);
|
|
120
|
+
} else {
|
|
121
|
+
return this.matchExactPattern(rawPath, aliasPattern, targetPath, baseUrl);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Matches a wildcard alias pattern (e.g., "@entities/*")
|
|
126
|
+
*
|
|
127
|
+
* Pattern: "@entities/*" -> Target: "src/entities/*"
|
|
128
|
+
* Input: "@entities/user" -> Matches: "user" -> Output: "src/entities/user"
|
|
129
|
+
*
|
|
130
|
+
* Note: The original implementation uses simple string replacement for regex,
|
|
131
|
+
* which works because alias patterns typically don't contain special regex chars.
|
|
132
|
+
* We maintain this behavior for compatibility.
|
|
133
|
+
*/
|
|
134
|
+
static matchWildcardPattern(rawPath, aliasPattern, targetPath, baseUrl) {
|
|
135
|
+
const regexPattern = `^${aliasPattern.replace(/\*/g, "(.*)")}$`;
|
|
136
|
+
const regex = new RegExp(regexPattern);
|
|
137
|
+
const match = rawPath.match(regex);
|
|
138
|
+
if (!match) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
const capturedPath = match[1];
|
|
142
|
+
const resolvedTargetPath = targetPath.replace(/\*/g, capturedPath);
|
|
143
|
+
const absolutePath = import_path.default.resolve(`${baseUrl}/${resolvedTargetPath}`);
|
|
144
|
+
return _Alias.createSuccessResult(absolutePath);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Matches an exact alias pattern (no wildcard)
|
|
148
|
+
*
|
|
149
|
+
* Pattern: "@utils" -> Target: "src/utils/index"
|
|
150
|
+
* Input: "@utils" -> Output: "src/utils/index"
|
|
151
|
+
*/
|
|
152
|
+
static matchExactPattern(rawPath, aliasPattern, targetPath, baseUrl) {
|
|
153
|
+
if (rawPath !== aliasPattern) {
|
|
154
|
+
return null;
|
|
105
155
|
}
|
|
156
|
+
const absolutePath = import_path.default.resolve(`${baseUrl}/${targetPath}`);
|
|
157
|
+
return _Alias.createSuccessResult(absolutePath);
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Creates a success result
|
|
161
|
+
*/
|
|
162
|
+
static createSuccessResult(absolutePath) {
|
|
163
|
+
return {
|
|
164
|
+
absolutePath,
|
|
165
|
+
type: "success"
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Creates a fail result
|
|
170
|
+
*/
|
|
171
|
+
static createFailResult(originalPath) {
|
|
172
|
+
return {
|
|
173
|
+
absolutePath: originalPath,
|
|
174
|
+
type: "fail"
|
|
175
|
+
};
|
|
106
176
|
}
|
|
107
177
|
};
|
|
108
178
|
|
|
@@ -229,16 +299,16 @@ var enforceBarrelPattern = {
|
|
|
229
299
|
if (!rawImportPath.startsWith(".") && !rawImportPath.startsWith("/") || rawImportPath.includes("/node_modules/")) {
|
|
230
300
|
return;
|
|
231
301
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
302
|
+
try {
|
|
303
|
+
absoluteImportPath = import_resolve.default.sync(rawImportPath, {
|
|
304
|
+
basedir: import_path2.default.dirname(absoluteCurrentFilePath),
|
|
305
|
+
extensions: RESOLVE_EXTENSIONS
|
|
306
|
+
});
|
|
307
|
+
} catch (e) {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
236
310
|
}
|
|
237
311
|
} catch (e) {
|
|
238
|
-
context.report({
|
|
239
|
-
node,
|
|
240
|
-
messageId: "TransformedAliasResolveFailed"
|
|
241
|
-
});
|
|
242
312
|
return;
|
|
243
313
|
}
|
|
244
314
|
{
|
|
@@ -252,8 +322,8 @@ var enforceBarrelPattern = {
|
|
|
252
322
|
const targetPathEntryPointed = targetPathEntryPoints.includes(absoluteImportPath);
|
|
253
323
|
const importedEnforceBarrelFile = absoluteImportPath.startsWith(closedTargetPath);
|
|
254
324
|
const currentFileInEnforceBarrel = absoluteCurrentFilePath.startsWith(closedTargetPath);
|
|
255
|
-
const
|
|
256
|
-
const invalidImported = !targetPathEntryPointed &&
|
|
325
|
+
const importedOutsideOfBarrel = !currentFileInEnforceBarrel && importedEnforceBarrelFile;
|
|
326
|
+
const invalidImported = !targetPathEntryPointed && importedOutsideOfBarrel;
|
|
257
327
|
if (invalidImported) {
|
|
258
328
|
matchedLatestTargetPath = absoluteTargetPath;
|
|
259
329
|
}
|
|
@@ -359,7 +429,7 @@ var isolateBarrelFile = {
|
|
|
359
429
|
return;
|
|
360
430
|
}
|
|
361
431
|
} else {
|
|
362
|
-
if (!rawImportPath.startsWith(".") && !rawImportPath.startsWith("/")) {
|
|
432
|
+
if (!rawImportPath.startsWith(".") && !rawImportPath.startsWith("/") || rawImportPath.includes("/node_modules/")) {
|
|
363
433
|
return;
|
|
364
434
|
}
|
|
365
435
|
absoluteImportPath = import_resolve2.default.sync(rawImportPath, {
|
|
@@ -374,31 +444,26 @@ var isolateBarrelFile = {
|
|
|
374
444
|
});
|
|
375
445
|
return;
|
|
376
446
|
}
|
|
377
|
-
const
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
});
|
|
382
|
-
const matchedIsolation = absoluteIsolations[isolationIndex];
|
|
383
|
-
if (!matchedIsolation) return;
|
|
384
|
-
const isAllowedImport = matchedIsolation.allowedPaths.some(
|
|
385
|
-
(allowedPath) => {
|
|
386
|
-
const same = absoluteImportPath === allowedPath;
|
|
387
|
-
const closedAllowedPath = allowedPath + "/";
|
|
388
|
-
const sub = absoluteImportPath.startsWith(closedAllowedPath);
|
|
389
|
-
return same || sub;
|
|
390
|
-
}
|
|
391
|
-
);
|
|
392
|
-
const isGlobalAllowedImport = absoluteGlobalAllowPaths.some(
|
|
393
|
-
(allowedPath) => {
|
|
394
|
-
const same = absoluteImportPath === allowedPath;
|
|
395
|
-
const closedAllowedPath = allowedPath + "/";
|
|
396
|
-
const sub = absoluteImportPath.startsWith(closedAllowedPath);
|
|
397
|
-
return same || sub;
|
|
447
|
+
const matchedIsolationIndex = absoluteIsolations.findIndex(
|
|
448
|
+
(isolation) => {
|
|
449
|
+
const closedIsolationPath = isolation.isolationPath + "/";
|
|
450
|
+
return absoluteCurrentFilePath.startsWith(closedIsolationPath);
|
|
398
451
|
}
|
|
399
452
|
);
|
|
400
|
-
const
|
|
401
|
-
if (!
|
|
453
|
+
const matchedIsolation = absoluteIsolations[matchedIsolationIndex];
|
|
454
|
+
if (!matchedIsolation) return;
|
|
455
|
+
const isAllowedImport = [
|
|
456
|
+
//global allowed import paths
|
|
457
|
+
...absoluteGlobalAllowPaths,
|
|
458
|
+
//allowed import paths in the matched isolation
|
|
459
|
+
...matchedIsolation.allowedPaths
|
|
460
|
+
].some((allowedPath) => {
|
|
461
|
+
const same = absoluteImportPath === allowedPath;
|
|
462
|
+
const closedAllowedPath = allowedPath + "/";
|
|
463
|
+
const sub = absoluteImportPath.startsWith(closedAllowedPath);
|
|
464
|
+
return same || sub;
|
|
465
|
+
});
|
|
466
|
+
if (!isAllowedImport) {
|
|
402
467
|
context.report({
|
|
403
468
|
node,
|
|
404
469
|
messageId: "IsolatedBarrelImportDisallowed"
|
|
@@ -450,73 +515,128 @@ var noWildcard = {
|
|
|
450
515
|
// src/rules/no-cycle.ts
|
|
451
516
|
var import_types4 = require("@typescript-eslint/types");
|
|
452
517
|
var import_path4 = __toESM(require("path"), 1);
|
|
518
|
+
var import_fs = __toESM(require("fs"), 1);
|
|
453
519
|
var import_resolve3 = __toESM(require("resolve"), 1);
|
|
454
520
|
var importGraph = /* @__PURE__ */ new Map();
|
|
455
|
-
var fileToImports = /* @__PURE__ */ new Map();
|
|
456
521
|
var barrelExportsCache = /* @__PURE__ */ new Map();
|
|
457
|
-
function detectCycle(currentFile, visited, recStack, path5) {
|
|
458
|
-
visited.add(currentFile);
|
|
459
|
-
recStack.add(currentFile);
|
|
460
|
-
path5.push(currentFile);
|
|
461
|
-
const imports = importGraph.get(currentFile) || /* @__PURE__ */ new Set();
|
|
462
|
-
for (const importedFile of imports) {
|
|
463
|
-
if (!visited.has(importedFile)) {
|
|
464
|
-
const cycle = detectCycle(importedFile, visited, recStack, [...path5]);
|
|
465
|
-
if (cycle) {
|
|
466
|
-
return cycle;
|
|
467
|
-
}
|
|
468
|
-
} else if (recStack.has(importedFile)) {
|
|
469
|
-
const cycleStart = path5.indexOf(importedFile);
|
|
470
|
-
return [...path5.slice(cycleStart), importedFile];
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
recStack.delete(currentFile);
|
|
474
|
-
return null;
|
|
475
|
-
}
|
|
476
522
|
function isBarrelFile(filePath) {
|
|
477
523
|
const fileName = import_path4.default.basename(filePath);
|
|
478
524
|
return BARREL_ENTRY_POINT_FILE_NAMES.includes(
|
|
479
525
|
fileName
|
|
480
526
|
);
|
|
481
527
|
}
|
|
482
|
-
function
|
|
483
|
-
|
|
484
|
-
|
|
528
|
+
function isExternalImport(rawPath) {
|
|
529
|
+
if (!rawPath.startsWith(".") && !rawPath.startsWith("/")) {
|
|
530
|
+
return true;
|
|
531
|
+
}
|
|
532
|
+
if (rawPath.includes("/node_modules/")) {
|
|
533
|
+
return true;
|
|
534
|
+
}
|
|
535
|
+
return false;
|
|
536
|
+
}
|
|
537
|
+
function resolveImportPath(rawImportPath, currentFileDir) {
|
|
538
|
+
try {
|
|
539
|
+
const aliasResult = Alias.resolvePath(rawImportPath, currentFileDir);
|
|
540
|
+
if (aliasResult.type === "success") {
|
|
541
|
+
return resolveAliasPath(aliasResult.absolutePath, currentFileDir);
|
|
542
|
+
}
|
|
543
|
+
if (isExternalImport(rawImportPath)) {
|
|
544
|
+
return null;
|
|
545
|
+
}
|
|
546
|
+
return import_resolve3.default.sync(rawImportPath, {
|
|
547
|
+
basedir: currentFileDir,
|
|
548
|
+
extensions: RESOLVE_EXTENSIONS
|
|
549
|
+
});
|
|
550
|
+
} catch (e) {
|
|
551
|
+
return null;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
function resolveAliasPath(resolvedPath, currentFileDir) {
|
|
555
|
+
try {
|
|
556
|
+
const stats = import_fs.default.statSync(resolvedPath);
|
|
557
|
+
if (stats.isDirectory()) {
|
|
558
|
+
return import_resolve3.default.sync("index", {
|
|
559
|
+
basedir: resolvedPath,
|
|
560
|
+
extensions: RESOLVE_EXTENSIONS
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
return resolvedPath;
|
|
564
|
+
} catch (e) {
|
|
565
|
+
try {
|
|
566
|
+
return import_resolve3.default.sync(resolvedPath, {
|
|
567
|
+
basedir: currentFileDir,
|
|
568
|
+
extensions: RESOLVE_EXTENSIONS
|
|
569
|
+
});
|
|
570
|
+
} catch (e2) {
|
|
571
|
+
return resolvedPath;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
function getBarrelExports(barrelFileDir, ast) {
|
|
576
|
+
const exports2 = [];
|
|
485
577
|
for (const statement of ast.body) {
|
|
486
|
-
if (statement.type === "ExportNamedDeclaration" || statement.type === "ExportAllDeclaration") {
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
basedir: barrelFileDir,
|
|
492
|
-
extensions: RESOLVE_EXTENSIONS
|
|
493
|
-
});
|
|
494
|
-
if (!exportedModules.includes(resolvedPath)) {
|
|
495
|
-
exportedModules.push(resolvedPath);
|
|
496
|
-
}
|
|
497
|
-
} catch (e) {
|
|
498
|
-
}
|
|
578
|
+
if ((statement.type === "ExportNamedDeclaration" || statement.type === "ExportAllDeclaration") && statement.source) {
|
|
579
|
+
const exportPath = statement.source.value;
|
|
580
|
+
const resolved = tryResolve(exportPath, barrelFileDir);
|
|
581
|
+
if (resolved && !exports2.includes(resolved)) {
|
|
582
|
+
exports2.push(resolved);
|
|
499
583
|
}
|
|
500
584
|
}
|
|
501
|
-
if (statement.type === "ImportDeclaration") {
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
basedir: barrelFileDir,
|
|
508
|
-
extensions: RESOLVE_EXTENSIONS
|
|
509
|
-
});
|
|
510
|
-
if (!exportedModules.includes(resolvedPath)) {
|
|
511
|
-
exportedModules.push(resolvedPath);
|
|
512
|
-
}
|
|
513
|
-
} catch (e) {
|
|
514
|
-
}
|
|
585
|
+
if (statement.type === "ImportDeclaration" && statement.source) {
|
|
586
|
+
const importPath = statement.source.value;
|
|
587
|
+
if (importPath.startsWith(".") || importPath.startsWith("/")) {
|
|
588
|
+
const resolved = tryResolve(importPath, barrelFileDir);
|
|
589
|
+
if (resolved && !exports2.includes(resolved)) {
|
|
590
|
+
exports2.push(resolved);
|
|
515
591
|
}
|
|
516
592
|
}
|
|
517
593
|
}
|
|
518
594
|
}
|
|
519
|
-
return
|
|
595
|
+
return exports2;
|
|
596
|
+
}
|
|
597
|
+
function tryResolve(importPath, basedir) {
|
|
598
|
+
try {
|
|
599
|
+
return import_resolve3.default.sync(importPath, {
|
|
600
|
+
basedir,
|
|
601
|
+
extensions: RESOLVE_EXTENSIONS
|
|
602
|
+
});
|
|
603
|
+
} catch (e) {
|
|
604
|
+
return null;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
function detectCycle(startFile, visited, recStack, currentPath) {
|
|
608
|
+
visited.add(startFile);
|
|
609
|
+
recStack.add(startFile);
|
|
610
|
+
currentPath.push(startFile);
|
|
611
|
+
const imports = importGraph.get(startFile) || /* @__PURE__ */ new Set();
|
|
612
|
+
for (const importedFile of imports) {
|
|
613
|
+
if (!visited.has(importedFile)) {
|
|
614
|
+
const cycle = detectCycle(importedFile, visited, recStack, [
|
|
615
|
+
...currentPath
|
|
616
|
+
]);
|
|
617
|
+
if (cycle) return cycle;
|
|
618
|
+
} else if (recStack.has(importedFile)) {
|
|
619
|
+
const cycleStart = currentPath.indexOf(importedFile);
|
|
620
|
+
return [...currentPath.slice(cycleStart), importedFile];
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
recStack.delete(startFile);
|
|
624
|
+
return null;
|
|
625
|
+
}
|
|
626
|
+
function hasBidirectionalCycle(fileA, fileB) {
|
|
627
|
+
var _a;
|
|
628
|
+
const bImports = importGraph.get(fileB);
|
|
629
|
+
return (_a = bImports == null ? void 0 : bImports.has(fileA)) != null ? _a : false;
|
|
630
|
+
}
|
|
631
|
+
function hasCycleThroughBarrel(currentFile, exportedModules) {
|
|
632
|
+
for (const exportedModule of exportedModules) {
|
|
633
|
+
if (exportedModule === currentFile) continue;
|
|
634
|
+
const moduleImports = importGraph.get(exportedModule);
|
|
635
|
+
if (moduleImports == null ? void 0 : moduleImports.has(currentFile)) {
|
|
636
|
+
return exportedModule;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
return null;
|
|
520
640
|
}
|
|
521
641
|
var noCycle = {
|
|
522
642
|
meta: {
|
|
@@ -533,161 +653,88 @@ var noCycle = {
|
|
|
533
653
|
},
|
|
534
654
|
defaultOptions: [],
|
|
535
655
|
create(context) {
|
|
536
|
-
const
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
const currentImportsSet = importGraph.get(absoluteCurrentFilePath);
|
|
541
|
-
currentImportsSet.clear();
|
|
542
|
-
if (!fileToImports.has(absoluteCurrentFilePath)) {
|
|
543
|
-
fileToImports.set(absoluteCurrentFilePath, /* @__PURE__ */ new Set());
|
|
656
|
+
const currentFile = context.getFilename();
|
|
657
|
+
const currentDir = import_path4.default.dirname(currentFile);
|
|
658
|
+
if (!importGraph.has(currentFile)) {
|
|
659
|
+
importGraph.set(currentFile, /* @__PURE__ */ new Set());
|
|
544
660
|
}
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
const
|
|
548
|
-
const
|
|
549
|
-
|
|
550
|
-
sourceCode
|
|
551
|
-
);
|
|
552
|
-
barrelExportsCache.set(absoluteCurrentFilePath, exportedModules);
|
|
661
|
+
importGraph.get(currentFile).clear();
|
|
662
|
+
if (isBarrelFile(currentFile)) {
|
|
663
|
+
const ast = context.getSourceCode().ast;
|
|
664
|
+
const exports2 = getBarrelExports(currentDir, ast);
|
|
665
|
+
barrelExportsCache.set(currentFile, exports2);
|
|
553
666
|
}
|
|
554
|
-
function
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
return import_resolve3.default.sync("index", {
|
|
567
|
-
basedir: resolvedPath,
|
|
568
|
-
extensions: RESOLVE_EXTENSIONS
|
|
569
|
-
});
|
|
570
|
-
}
|
|
571
|
-
} catch (e) {
|
|
572
|
-
try {
|
|
573
|
-
return import_resolve3.default.sync(resolvedPath, {
|
|
574
|
-
basedir: import_path4.default.dirname(absoluteCurrentFilePath),
|
|
575
|
-
extensions: RESOLVE_EXTENSIONS
|
|
576
|
-
});
|
|
577
|
-
} catch (e2) {
|
|
578
|
-
return resolvedPath;
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
return resolvedPath;
|
|
582
|
-
} else {
|
|
583
|
-
if (!rawImportPath.startsWith(".") && !rawImportPath.startsWith("/") || rawImportPath.includes("/node_modules/")) {
|
|
584
|
-
return null;
|
|
585
|
-
}
|
|
586
|
-
return import_resolve3.default.sync(rawImportPath, {
|
|
587
|
-
basedir: import_path4.default.dirname(absoluteCurrentFilePath),
|
|
588
|
-
extensions: RESOLVE_EXTENSIONS
|
|
667
|
+
function checkImport(node) {
|
|
668
|
+
if (!node.source) return;
|
|
669
|
+
const rawPath = node.source.value;
|
|
670
|
+
const absolutePath = resolveImportPath(rawPath, currentDir);
|
|
671
|
+
if (!absolutePath) return;
|
|
672
|
+
if (isBarrelFile(currentFile)) {
|
|
673
|
+
const error = checkBarrelInternalImport(rawPath, absolutePath);
|
|
674
|
+
if (error) {
|
|
675
|
+
context.report({
|
|
676
|
+
node,
|
|
677
|
+
messageId: "BarrelInternalImportDisallowed",
|
|
678
|
+
data: { relativePath: error }
|
|
589
679
|
});
|
|
680
|
+
return;
|
|
590
681
|
}
|
|
591
|
-
} catch (e) {
|
|
592
|
-
return null;
|
|
593
682
|
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
if (
|
|
597
|
-
|
|
683
|
+
const isBarrelInternal = isBarrelFile(currentFile) && absolutePath.startsWith(currentDir + import_path4.default.sep);
|
|
684
|
+
addToGraph(absolutePath);
|
|
685
|
+
if (isBarrelInternal) return;
|
|
686
|
+
const cycleError = checkForCycles(absolutePath);
|
|
687
|
+
if (cycleError) {
|
|
688
|
+
context.report({
|
|
689
|
+
node,
|
|
690
|
+
messageId: "CircularDependency",
|
|
691
|
+
data: { cyclePath: cycleError }
|
|
692
|
+
});
|
|
598
693
|
}
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
694
|
+
}
|
|
695
|
+
function checkBarrelInternalImport(rawPath, absolutePath) {
|
|
696
|
+
const isInternal = absolutePath.startsWith(currentDir + import_path4.default.sep) || absolutePath === currentDir;
|
|
697
|
+
if (!isInternal) return null;
|
|
698
|
+
if (rawPath.startsWith("./") || rawPath.startsWith("../")) {
|
|
699
|
+
return null;
|
|
603
700
|
}
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
messageId: "BarrelInternalImportDisallowed",
|
|
617
|
-
data: {
|
|
618
|
-
relativePath: suggestedRelativePath.replace(/\\/g, "/")
|
|
619
|
-
}
|
|
620
|
-
});
|
|
621
|
-
return;
|
|
701
|
+
const relative = import_path4.default.relative(currentDir, absolutePath);
|
|
702
|
+
const suggested = relative.startsWith(".") ? relative : `./${relative}`;
|
|
703
|
+
return suggested.replace(/\\/g, "/");
|
|
704
|
+
}
|
|
705
|
+
function addToGraph(absolutePath) {
|
|
706
|
+
const imports = importGraph.get(currentFile);
|
|
707
|
+
imports.add(absolutePath);
|
|
708
|
+
if (isBarrelFile(absolutePath)) {
|
|
709
|
+
const exports2 = barrelExportsCache.get(absolutePath) || [];
|
|
710
|
+
for (const exp of exports2) {
|
|
711
|
+
if (exp !== currentFile) {
|
|
712
|
+
imports.add(exp);
|
|
622
713
|
}
|
|
623
714
|
}
|
|
624
715
|
}
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
)
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
const exportedModules = barrelExportsCache.get(absoluteImportPath) || [];
|
|
633
|
-
for (const exportedModule of exportedModules) {
|
|
634
|
-
if (exportedModule !== absoluteCurrentFilePath) {
|
|
635
|
-
currentImports.add(exportedModule);
|
|
636
|
-
const exportedModuleImports = importGraph.get(exportedModule);
|
|
637
|
-
if (exportedModuleImports && exportedModuleImports.has(absoluteCurrentFilePath)) {
|
|
638
|
-
const cyclePath = `${absoluteCurrentFilePath} \u2192 ${absoluteImportPath} \u2192 ${exportedModule} \u2192 ${absoluteImportPath} \u2192 ${absoluteCurrentFilePath}`;
|
|
639
|
-
context.report({
|
|
640
|
-
node,
|
|
641
|
-
messageId: "CircularDependency",
|
|
642
|
-
data: {
|
|
643
|
-
cyclePath
|
|
644
|
-
}
|
|
645
|
-
});
|
|
646
|
-
return;
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
}
|
|
716
|
+
}
|
|
717
|
+
function checkForCycles(absolutePath) {
|
|
718
|
+
if (isBarrelFile(absolutePath)) {
|
|
719
|
+
const exports2 = barrelExportsCache.get(absolutePath) || [];
|
|
720
|
+
const cycleModule = hasCycleThroughBarrel(currentFile, exports2);
|
|
721
|
+
if (cycleModule) {
|
|
722
|
+
return `${currentFile} \u2192 ${absolutePath} \u2192 ${cycleModule} \u2192 ${absolutePath} \u2192 ${currentFile}`;
|
|
650
723
|
}
|
|
651
724
|
}
|
|
652
|
-
if (
|
|
653
|
-
return
|
|
654
|
-
}
|
|
655
|
-
const importedFileImports = importGraph.get(absoluteImportPath);
|
|
656
|
-
if (importedFileImports && importedFileImports.has(absoluteCurrentFilePath)) {
|
|
657
|
-
const cyclePath = `${absoluteCurrentFilePath} \u2192 ${absoluteImportPath} \u2192 ${absoluteCurrentFilePath}`;
|
|
658
|
-
context.report({
|
|
659
|
-
node,
|
|
660
|
-
messageId: "CircularDependency",
|
|
661
|
-
data: {
|
|
662
|
-
cyclePath
|
|
663
|
-
}
|
|
664
|
-
});
|
|
665
|
-
return;
|
|
725
|
+
if (hasBidirectionalCycle(currentFile, absolutePath)) {
|
|
726
|
+
return `${currentFile} \u2192 ${absolutePath} \u2192 ${currentFile}`;
|
|
666
727
|
}
|
|
667
|
-
const
|
|
668
|
-
const recStack = /* @__PURE__ */ new Set();
|
|
669
|
-
const cycle = detectCycle(absoluteCurrentFilePath, visited, recStack, []);
|
|
728
|
+
const cycle = detectCycle(currentFile, /* @__PURE__ */ new Set(), /* @__PURE__ */ new Set(), []);
|
|
670
729
|
if (cycle && cycle.length > 0) {
|
|
671
|
-
|
|
672
|
-
context.report({
|
|
673
|
-
node,
|
|
674
|
-
messageId: "CircularDependency",
|
|
675
|
-
data: {
|
|
676
|
-
cyclePath
|
|
677
|
-
}
|
|
678
|
-
});
|
|
730
|
+
return cycle.join(" \u2192 ");
|
|
679
731
|
}
|
|
732
|
+
return null;
|
|
680
733
|
}
|
|
681
734
|
return {
|
|
682
|
-
ImportDeclaration
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
ExportNamedDeclaration(node) {
|
|
686
|
-
return checker(node);
|
|
687
|
-
},
|
|
688
|
-
ExportAllDeclaration(node) {
|
|
689
|
-
return checker(node);
|
|
690
|
-
}
|
|
735
|
+
ImportDeclaration: checkImport,
|
|
736
|
+
ExportNamedDeclaration: checkImport,
|
|
737
|
+
ExportAllDeclaration: checkImport
|
|
691
738
|
};
|
|
692
739
|
}
|
|
693
740
|
};
|