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/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 === "success") {
65
- for (const [pattern, targets] of Object.entries(configResult.paths)) {
66
- const origin = targets[0];
67
- if (pattern.includes("*")) {
68
- const patternRegex = new RegExp(
69
- `^${pattern.replace("*", "(.*)")}$`
70
- );
71
- const match = rawPath.match(patternRegex);
72
- if (match) {
73
- const [, matchedPath] = match;
74
- const extendedOrigin = origin.replace("*", matchedPath);
75
- const absolutePath = import_path.default.resolve(
76
- `${configResult.absoluteBaseUrl}/${extendedOrigin}`
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
- absolutePath: rawPath,
98
- type: "fail"
99
- };
100
- } catch (e) {
101
- return {
102
- absolutePath: rawPath,
103
- type: "fail"
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
- absoluteImportPath = import_resolve.default.sync(rawImportPath, {
233
- basedir: import_path2.default.dirname(absoluteCurrentFilePath),
234
- extensions: RESOLVE_EXTENSIONS
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 importedOutsideOfTargetPath = !currentFileInEnforceBarrel && importedEnforceBarrelFile;
256
- const invalidImported = !targetPathEntryPointed && importedOutsideOfTargetPath;
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 isolationIndex = absoluteIsolations.findIndex((isolation) => {
378
- const absoluteIsolationPath = isolation.isolationPath;
379
- const closedIsolationPath = absoluteIsolationPath + "/";
380
- return absoluteCurrentFilePath.startsWith(closedIsolationPath);
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 allowedImport = isAllowedImport || isGlobalAllowedImport;
401
- if (!allowedImport) {
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 getExportedModulesFromBarrel(barrelFileDir, sourceCode) {
483
- const exportedModules = [];
484
- const ast = sourceCode.ast;
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
- if (statement.source) {
488
- const exportPath = statement.source.value;
489
- try {
490
- const resolvedPath = import_resolve3.default.sync(exportPath, {
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
- if (statement.source) {
503
- const importPath = statement.source.value;
504
- if (importPath.startsWith(".") || importPath.startsWith("/")) {
505
- try {
506
- const resolvedPath = import_resolve3.default.sync(importPath, {
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 exportedModules;
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 absoluteCurrentFilePath = context.getFilename();
537
- if (!importGraph.has(absoluteCurrentFilePath)) {
538
- importGraph.set(absoluteCurrentFilePath, /* @__PURE__ */ new Set());
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
- if (isBarrelFile(absoluteCurrentFilePath)) {
546
- const barrelFileDir = import_path4.default.dirname(absoluteCurrentFilePath);
547
- const sourceCode = context.getSourceCode();
548
- const exportedModules = getExportedModulesFromBarrel(
549
- barrelFileDir,
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 resolveImportPath(rawImportPath) {
555
- try {
556
- const aliasResult = Alias.resolvePath(
557
- rawImportPath,
558
- import_path4.default.dirname(absoluteCurrentFilePath)
559
- );
560
- if (aliasResult.type === "success") {
561
- const resolvedPath = aliasResult.absolutePath;
562
- try {
563
- const fs = require("fs");
564
- const stats = fs.statSync(resolvedPath);
565
- if (stats.isDirectory()) {
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
- function checker(node) {
596
- if (!node.source) {
597
- return;
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
- const rawImportPath = node.source.value;
600
- const absoluteImportPath = resolveImportPath(rawImportPath);
601
- if (!absoluteImportPath) {
602
- return;
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
- if (isBarrelFile(absoluteCurrentFilePath)) {
605
- const barrelFileDir = import_path4.default.dirname(absoluteCurrentFilePath);
606
- const isInternalModule = absoluteImportPath.startsWith(barrelFileDir + import_path4.default.sep) || absoluteImportPath === barrelFileDir;
607
- if (isInternalModule) {
608
- if (!rawImportPath.startsWith("./") && !rawImportPath.startsWith("../")) {
609
- const relativePath = import_path4.default.relative(
610
- barrelFileDir,
611
- absoluteImportPath
612
- );
613
- const suggestedRelativePath = relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
614
- context.report({
615
- node,
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
- const isBarrelImportingInternal = isBarrelFile(absoluteCurrentFilePath) && absoluteImportPath.startsWith(
626
- import_path4.default.dirname(absoluteCurrentFilePath) + import_path4.default.sep
627
- );
628
- const currentImports = importGraph.get(absoluteCurrentFilePath);
629
- if (currentImports) {
630
- currentImports.add(absoluteImportPath);
631
- if (isBarrelFile(absoluteImportPath)) {
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 (isBarrelImportingInternal) {
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 visited = /* @__PURE__ */ new Set();
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
- const cyclePath = cycle.join(" \u2192 ");
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(node) {
683
- return checker(node);
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
  };