@atlaskit/eslint-plugin-platform 2.7.1 → 2.8.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.
Files changed (125) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cjs/index.js +17 -9
  3. package/dist/cjs/rules/constants.js +1 -1
  4. package/dist/cjs/rules/ensure-critical-dependency-resolutions/index.js +5 -5
  5. package/dist/cjs/rules/ensure-no-private-dependencies/index.js +48 -66
  6. package/dist/cjs/rules/feature-gating/inline-usage/index.js +14 -3
  7. package/dist/cjs/rules/feature-gating/no-alias/index.js +1 -1
  8. package/dist/cjs/rules/feature-gating/no-module-level-eval/index.js +1 -1
  9. package/dist/cjs/rules/feature-gating/no-module-level-eval-nav4/index.js +1 -1
  10. package/dist/cjs/rules/feature-gating/no-preconditioning/index.js +4 -1
  11. package/dist/cjs/rules/feature-gating/prefer-fg/index.js +1 -1
  12. package/dist/cjs/rules/feature-gating/static-feature-flags/index.js +2 -2
  13. package/dist/cjs/rules/feature-gating/use-recommended-utils/index.js +1 -1
  14. package/dist/cjs/rules/feature-gating/valid-gate-name/index.js +60 -0
  15. package/dist/cjs/rules/import/no-barrel-entry-imports/index.js +871 -0
  16. package/dist/cjs/rules/import/no-barrel-entry-jest-mock/index.js +1384 -0
  17. package/dist/cjs/rules/import/no-conversation-assistant-barrel-imports/index.js +43 -0
  18. package/dist/cjs/rules/import/no-jest-mock-barrel-files/index.js +1401 -0
  19. package/dist/cjs/rules/import/no-relative-barrel-file-imports/index.js +777 -0
  20. package/dist/cjs/rules/import/shared/barrel-parsing.js +511 -0
  21. package/dist/cjs/rules/import/shared/file-system.js +186 -0
  22. package/dist/cjs/rules/import/shared/jest-utils.js +191 -0
  23. package/dist/cjs/rules/import/shared/package-registry.js +263 -0
  24. package/dist/cjs/rules/import/shared/package-resolution.js +185 -0
  25. package/dist/cjs/rules/import/shared/perf.js +89 -0
  26. package/dist/cjs/rules/import/shared/types.js +67 -0
  27. package/dist/cjs/rules/no-invalid-storybook-decorator-usage/index.js +1 -1
  28. package/dist/cjs/rules/no-sparse-checkout/index.js +1 -1
  29. package/dist/cjs/rules/prefer-crypto-random-uuid/index.js +87 -0
  30. package/dist/cjs/rules/use-entrypoints-in-examples/index.js +1 -1
  31. package/dist/es2019/index.js +17 -9
  32. package/dist/es2019/rules/constants.js +1 -1
  33. package/dist/es2019/rules/ensure-critical-dependency-resolutions/index.js +5 -5
  34. package/dist/es2019/rules/ensure-no-private-dependencies/index.js +10 -9
  35. package/dist/es2019/rules/feature-gating/inline-usage/index.js +14 -3
  36. package/dist/es2019/rules/feature-gating/no-alias/index.js +1 -1
  37. package/dist/es2019/rules/feature-gating/no-module-level-eval/index.js +1 -1
  38. package/dist/es2019/rules/feature-gating/no-module-level-eval-nav4/index.js +1 -1
  39. package/dist/es2019/rules/feature-gating/no-preconditioning/index.js +4 -1
  40. package/dist/es2019/rules/feature-gating/prefer-fg/index.js +1 -1
  41. package/dist/es2019/rules/feature-gating/static-feature-flags/index.js +2 -2
  42. package/dist/es2019/rules/feature-gating/use-recommended-utils/index.js +1 -1
  43. package/dist/es2019/rules/feature-gating/valid-gate-name/index.js +52 -0
  44. package/dist/es2019/rules/import/no-barrel-entry-imports/index.js +801 -0
  45. package/dist/es2019/rules/import/no-barrel-entry-jest-mock/index.js +1113 -0
  46. package/dist/es2019/rules/import/no-conversation-assistant-barrel-imports/index.js +37 -0
  47. package/dist/es2019/rules/import/no-jest-mock-barrel-files/index.js +1179 -0
  48. package/dist/es2019/rules/import/no-relative-barrel-file-imports/index.js +738 -0
  49. package/dist/es2019/rules/import/shared/barrel-parsing.js +433 -0
  50. package/dist/es2019/rules/import/shared/file-system.js +174 -0
  51. package/dist/es2019/rules/import/shared/jest-utils.js +159 -0
  52. package/dist/es2019/rules/import/shared/package-registry.js +240 -0
  53. package/dist/es2019/rules/import/shared/package-resolution.js +161 -0
  54. package/dist/es2019/rules/import/shared/perf.js +83 -0
  55. package/dist/es2019/rules/import/shared/types.js +57 -0
  56. package/dist/es2019/rules/no-invalid-storybook-decorator-usage/index.js +1 -1
  57. package/dist/es2019/rules/no-sparse-checkout/index.js +1 -1
  58. package/dist/es2019/rules/prefer-crypto-random-uuid/index.js +81 -0
  59. package/dist/es2019/rules/use-entrypoints-in-examples/index.js +1 -1
  60. package/dist/esm/index.js +17 -9
  61. package/dist/esm/rules/constants.js +1 -1
  62. package/dist/esm/rules/ensure-critical-dependency-resolutions/index.js +5 -5
  63. package/dist/esm/rules/ensure-no-private-dependencies/index.js +48 -65
  64. package/dist/esm/rules/feature-gating/inline-usage/index.js +14 -3
  65. package/dist/esm/rules/feature-gating/no-alias/index.js +1 -1
  66. package/dist/esm/rules/feature-gating/no-module-level-eval/index.js +1 -1
  67. package/dist/esm/rules/feature-gating/no-module-level-eval-nav4/index.js +1 -1
  68. package/dist/esm/rules/feature-gating/no-preconditioning/index.js +4 -1
  69. package/dist/esm/rules/feature-gating/prefer-fg/index.js +1 -1
  70. package/dist/esm/rules/feature-gating/static-feature-flags/index.js +2 -2
  71. package/dist/esm/rules/feature-gating/use-recommended-utils/index.js +1 -1
  72. package/dist/esm/rules/feature-gating/valid-gate-name/index.js +53 -0
  73. package/dist/esm/rules/import/no-barrel-entry-imports/index.js +864 -0
  74. package/dist/esm/rules/import/no-barrel-entry-jest-mock/index.js +1375 -0
  75. package/dist/esm/rules/import/no-conversation-assistant-barrel-imports/index.js +37 -0
  76. package/dist/esm/rules/import/no-jest-mock-barrel-files/index.js +1391 -0
  77. package/dist/esm/rules/import/no-relative-barrel-file-imports/index.js +770 -0
  78. package/dist/esm/rules/import/shared/barrel-parsing.js +500 -0
  79. package/dist/esm/rules/import/shared/file-system.js +176 -0
  80. package/dist/esm/rules/import/shared/jest-utils.js +179 -0
  81. package/dist/esm/rules/import/shared/package-registry.js +256 -0
  82. package/dist/esm/rules/import/shared/package-resolution.js +175 -0
  83. package/dist/esm/rules/import/shared/perf.js +80 -0
  84. package/dist/esm/rules/import/shared/types.js +61 -0
  85. package/dist/esm/rules/no-invalid-storybook-decorator-usage/index.js +1 -1
  86. package/dist/esm/rules/no-sparse-checkout/index.js +1 -1
  87. package/dist/esm/rules/prefer-crypto-random-uuid/index.js +81 -0
  88. package/dist/esm/rules/use-entrypoints-in-examples/index.js +1 -1
  89. package/dist/types/index.d.ts +18 -16
  90. package/dist/types/rules/import/no-barrel-entry-imports/index.d.ts +9 -0
  91. package/dist/types/rules/import/no-barrel-entry-jest-mock/index.d.ts +9 -0
  92. package/dist/types/rules/import/no-conversation-assistant-barrel-imports/index.d.ts +3 -0
  93. package/dist/types/rules/import/no-jest-mock-barrel-files/index.d.ts +22 -0
  94. package/dist/types/rules/import/no-relative-barrel-file-imports/index.d.ts +5 -0
  95. package/dist/types/rules/import/shared/barrel-parsing.d.ts +30 -0
  96. package/dist/types/rules/import/shared/file-system.d.ts +38 -0
  97. package/dist/types/rules/import/shared/jest-utils.d.ts +47 -0
  98. package/dist/types/rules/import/shared/package-registry.d.ts +26 -0
  99. package/dist/types/rules/import/shared/package-resolution.d.ts +38 -0
  100. package/dist/types/rules/import/shared/perf.d.ts +13 -0
  101. package/dist/types/rules/import/shared/types.d.ts +131 -0
  102. package/dist/types/rules/prefer-crypto-random-uuid/index.d.ts +3 -0
  103. package/dist/types-ts4.5/index.d.ts +18 -28
  104. package/dist/types-ts4.5/rules/import/no-barrel-entry-imports/index.d.ts +9 -0
  105. package/dist/types-ts4.5/rules/import/no-barrel-entry-jest-mock/index.d.ts +9 -0
  106. package/dist/types-ts4.5/rules/import/no-jest-mock-barrel-files/index.d.ts +22 -0
  107. package/dist/types-ts4.5/rules/import/no-relative-barrel-file-imports/index.d.ts +5 -0
  108. package/dist/types-ts4.5/rules/import/shared/barrel-parsing.d.ts +30 -0
  109. package/dist/types-ts4.5/rules/import/shared/file-system.d.ts +38 -0
  110. package/dist/types-ts4.5/rules/import/shared/jest-utils.d.ts +47 -0
  111. package/dist/types-ts4.5/rules/import/shared/package-registry.d.ts +26 -0
  112. package/dist/types-ts4.5/rules/import/shared/package-resolution.d.ts +38 -0
  113. package/dist/types-ts4.5/rules/import/shared/perf.d.ts +13 -0
  114. package/dist/types-ts4.5/rules/import/shared/types.d.ts +131 -0
  115. package/package.json +4 -5
  116. package/dist/cjs/rules/ensure-feature-flag-prefix/index.js +0 -75
  117. package/dist/cjs/rules/ensure-native-and-af-exports-synced/index.js +0 -158
  118. package/dist/es2019/rules/ensure-feature-flag-prefix/index.js +0 -65
  119. package/dist/es2019/rules/ensure-native-and-af-exports-synced/index.js +0 -146
  120. package/dist/esm/rules/ensure-feature-flag-prefix/index.js +0 -69
  121. package/dist/esm/rules/ensure-native-and-af-exports-synced/index.js +0 -151
  122. /package/dist/types/rules/{ensure-native-and-af-exports-synced → feature-gating/valid-gate-name}/index.d.ts +0 -0
  123. /package/dist/types-ts4.5/rules/{ensure-feature-flag-prefix → feature-gating/valid-gate-name}/index.d.ts +0 -0
  124. /package/dist/types-ts4.5/rules/{ensure-native-and-af-exports-synced → import/no-conversation-assistant-barrel-imports}/index.d.ts +0 -0
  125. /package/dist/{types/rules/ensure-feature-flag-prefix → types-ts4.5/rules/prefer-crypto-random-uuid}/index.d.ts +0 -0
@@ -0,0 +1,770 @@
1
+ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
3
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
4
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
5
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
6
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
7
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
8
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
9
+ import { dirname, relative } from 'path';
10
+ import { hasReExportsFromOtherFiles, parseBarrelExports as parseBarrelExportsFromShared } from '../shared/barrel-parsing';
11
+ import { findWorkspaceRoot, isRelativeImport, resolveImportPath } from '../shared/file-system';
12
+ import { findPackageInRegistry } from '../shared/package-registry';
13
+ import { findExportForSourceFile, parsePackageExports } from '../shared/package-resolution';
14
+ import { realFileSystem } from '../shared/types';
15
+
16
+ /**
17
+ * Specifier with additional metadata for tracking during barrel file resolution.
18
+ */
19
+
20
+ /**
21
+ * Context for barrel file resolution, returned by resolveBarrelFileContext.
22
+ */
23
+
24
+ /**
25
+ * Result of collecting specifiers by their source file.
26
+ */
27
+
28
+ // Cache per source package name to avoid repeated exports parsing during a single lint run.
29
+ // This is keyed by fs instance to avoid test pollution.
30
+ var sourcePackageExportsMapsByFs = new WeakMap();
31
+ function getSourcePackageExportsMaps(fs) {
32
+ var map = sourcePackageExportsMapsByFs.get(fs);
33
+ if (!map) {
34
+ map = new Map();
35
+ sourcePackageExportsMapsByFs.set(fs, map);
36
+ }
37
+ return map;
38
+ }
39
+ function getImportedName(spec) {
40
+ var imported = spec.imported;
41
+ return imported.type === 'Identifier' ? imported.name : String(imported.value);
42
+ }
43
+
44
+ /**
45
+ * Get the exported name from an ExportSpecifier, handling both Identifier and Literal
46
+ */
47
+ function getExportedName(node) {
48
+ return node.type === 'Identifier' ? node.name : String(node.value);
49
+ }
50
+
51
+ /**
52
+ * Convert absolute file path back to relative import path
53
+ */
54
+ function getImportPathForSourceFile(_ref) {
55
+ var _exportInfo$crossPack;
56
+ var sourceFilePath = _ref.sourceFilePath,
57
+ basedir = _ref.basedir,
58
+ originalImportPath = _ref.originalImportPath,
59
+ exportInfo = _ref.exportInfo,
60
+ workspaceRoot = _ref.workspaceRoot,
61
+ fs = _ref.fs;
62
+ var crossPackageName = exportInfo === null || exportInfo === void 0 || (_exportInfo$crossPack = exportInfo.crossPackageSource) === null || _exportInfo$crossPack === void 0 ? void 0 : _exportInfo$crossPack.packageName;
63
+ if (crossPackageName) {
64
+ var sourcePackageExportsMaps = getSourcePackageExportsMaps(fs);
65
+ var exportsMap = sourcePackageExportsMaps.get(crossPackageName);
66
+ if (!exportsMap) {
67
+ var pkgDir = findPackageInRegistry({
68
+ packageName: crossPackageName,
69
+ workspaceRoot: workspaceRoot,
70
+ fs: fs
71
+ });
72
+ if (pkgDir) {
73
+ exportsMap = parsePackageExports({
74
+ packageDir: pkgDir,
75
+ fs: fs
76
+ });
77
+ sourcePackageExportsMaps.set(crossPackageName, exportsMap);
78
+ }
79
+ }
80
+ var targetExportPath = exportsMap ? findExportForSourceFile({
81
+ sourceFilePath: sourceFilePath,
82
+ exportsMap: exportsMap
83
+ }) : null;
84
+ return targetExportPath ? crossPackageName + targetExportPath.slice(1) : crossPackageName;
85
+ }
86
+ return getRelativeImportPath({
87
+ basedir: basedir,
88
+ absolutePath: sourceFilePath,
89
+ originalImportPath: originalImportPath
90
+ });
91
+ }
92
+ function getRelativeImportPath(_ref2) {
93
+ var basedir = _ref2.basedir,
94
+ absolutePath = _ref2.absolutePath,
95
+ originalImportPath = _ref2.originalImportPath;
96
+ if (!absolutePath.startsWith('/') && !absolutePath.match(/^[a-zA-Z]:/)) {
97
+ return absolutePath;
98
+ }
99
+ var relativePath = relative(basedir, absolutePath);
100
+ // Normalize to use forward slashes
101
+ relativePath = relativePath.replace(/\\/g, '/');
102
+
103
+ // Check for extension in original path
104
+ var extMatch = originalImportPath.match(/\.(js|jsx|ts|tsx|mjs|cjs)$/);
105
+ var originalExt = extMatch ? extMatch[0] : '';
106
+
107
+ // Get extension from the resolved absolute path
108
+ var targetExtMatch = absolutePath.match(/\.(js|jsx|ts|tsx|mjs|cjs)$/);
109
+ var targetExt = targetExtMatch ? targetExtMatch[0] : '';
110
+
111
+ // Remove file extension from the target path
112
+ relativePath = relativePath.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/, '');
113
+
114
+ // If original had extension, append it
115
+ if (originalExt) {
116
+ // If original was a TypeScript source extension, use the actual target extension
117
+ if (['.ts', '.tsx'].includes(originalExt) && targetExt) {
118
+ relativePath += targetExt;
119
+ } else {
120
+ relativePath += originalExt;
121
+ }
122
+ } else {
123
+ // Remove /index suffix only if no extension was present
124
+ if (relativePath.endsWith('/index')) {
125
+ relativePath = relativePath.slice(0, -6);
126
+ } else if (relativePath === 'index') {
127
+ relativePath = '.';
128
+ }
129
+ }
130
+
131
+ // Ensure it starts with .. or .
132
+ if (!relativePath.startsWith('.') && !relativePath.startsWith('/')) {
133
+ relativePath = './' + relativePath;
134
+ }
135
+ return relativePath;
136
+ }
137
+
138
+ /**
139
+ * Build an import statement for a set of specifiers
140
+ */
141
+ function buildImportStatement(_ref3) {
142
+ var specs = _ref3.specs,
143
+ path = _ref3.path,
144
+ quoteChar = _ref3.quoteChar,
145
+ _ref3$isTypeImport = _ref3.isTypeImport,
146
+ isTypeImport = _ref3$isTypeImport === void 0 ? false : _ref3$isTypeImport;
147
+ var importNames = specs.map(function (spec) {
148
+ if (spec.type === 'ImportDefaultSpecifier') {
149
+ return spec.local.name;
150
+ } else if (spec.type === 'ImportSpecifier') {
151
+ var imported = getImportedName(spec);
152
+ var local = spec.local.name;
153
+ var isInlineType = spec.importKind === 'type' && !isTypeImport;
154
+ var prefix = isInlineType ? 'type ' : '';
155
+ return imported === local ? "".concat(prefix).concat(imported) : "".concat(prefix).concat(imported, " as ").concat(local);
156
+ }
157
+ return '';
158
+ }).filter(function (name) {
159
+ return name.length > 0;
160
+ });
161
+ if (importNames.length === 0) {
162
+ return '';
163
+ }
164
+ var typeKeyword = isTypeImport ? 'type ' : '';
165
+ var hasDefault = specs.some(function (spec) {
166
+ return spec.type === 'ImportDefaultSpecifier';
167
+ });
168
+ var hasNamed = specs.some(function (spec) {
169
+ return spec.type === 'ImportSpecifier';
170
+ });
171
+ if (hasDefault && hasNamed) {
172
+ var _specs$find;
173
+ var defaultName = (_specs$find = specs.find(function (spec) {
174
+ return spec.type === 'ImportDefaultSpecifier';
175
+ })) === null || _specs$find === void 0 ? void 0 : _specs$find.local.name;
176
+ var namedImports = specs.filter(function (spec) {
177
+ return spec.type === 'ImportSpecifier';
178
+ }).map(function (spec) {
179
+ var imported = getImportedName(spec);
180
+ var local = spec.local.name;
181
+ var isInlineType = spec.importKind === 'type' && !isTypeImport;
182
+ var prefix = isInlineType ? 'type ' : '';
183
+ return imported === local ? "".concat(prefix).concat(imported) : "".concat(prefix).concat(imported, " as ").concat(local);
184
+ }).join(', ');
185
+ return "import ".concat(typeKeyword).concat(defaultName, ", { ").concat(namedImports, " } from ").concat(quoteChar).concat(path).concat(quoteChar, ";");
186
+ } else if (hasDefault) {
187
+ var _specs$find2;
188
+ var _defaultName = (_specs$find2 = specs.find(function (spec) {
189
+ return spec.type === 'ImportDefaultSpecifier';
190
+ })) === null || _specs$find2 === void 0 ? void 0 : _specs$find2.local.name;
191
+ return "import ".concat(typeKeyword).concat(_defaultName, " from ").concat(quoteChar).concat(path).concat(quoteChar, ";");
192
+ } else {
193
+ return "import ".concat(typeKeyword, "{ ").concat(importNames.join(', '), " } from ").concat(quoteChar).concat(path).concat(quoteChar, ";");
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Build an export statement for a set of specifiers
199
+ */
200
+ function buildExportStatement(_ref4) {
201
+ var specs = _ref4.specs,
202
+ path = _ref4.path,
203
+ quoteChar = _ref4.quoteChar,
204
+ _ref4$isTypeExport = _ref4.isTypeExport,
205
+ isTypeExport = _ref4$isTypeExport === void 0 ? false : _ref4$isTypeExport;
206
+ var exportNames = specs.map(function (spec) {
207
+ var isInlineType = spec.kind === 'type' && !isTypeExport;
208
+ var prefix = isInlineType ? 'type ' : '';
209
+ return spec.nameInSource === spec.nameInLocal ? "".concat(prefix).concat(spec.nameInSource) : "".concat(prefix).concat(spec.nameInSource, " as ").concat(spec.nameInLocal);
210
+ }).filter(function (name) {
211
+ return name.length > 0;
212
+ });
213
+ if (exportNames.length === 0) {
214
+ return '';
215
+ }
216
+ var typeKeyword = isTypeExport ? 'type ' : '';
217
+ return "export ".concat(typeKeyword, "{ ").concat(exportNames.join(', '), " } from ").concat(quoteChar).concat(path).concat(quoteChar, ";");
218
+ }
219
+ var ruleMeta = {
220
+ type: 'problem',
221
+ docs: {
222
+ description: 'Warn when imports are from a relative barrel file and provide an auto-fix to split them into specific imports.',
223
+ category: 'Best Practices',
224
+ recommended: false
225
+ },
226
+ fixable: 'code',
227
+ messages: {
228
+ barrelImport: "Import from barrel file '{{path}}' should be split into more specific imports. Use auto-fix to resolve."
229
+ }
230
+ };
231
+
232
+ /**
233
+ * Resolve barrel file context from an import/export node.
234
+ * Returns null if the node should not be checked (not relative, not resolvable, not a barrel).
235
+ */
236
+ function resolveBarrelFileContext(_ref5) {
237
+ var node = _ref5.node,
238
+ context = _ref5.context,
239
+ fs = _ref5.fs;
240
+ if (!node.source) {
241
+ return null;
242
+ }
243
+ var importPath = node.source.value;
244
+ if (!isRelativeImport(importPath)) {
245
+ return null;
246
+ }
247
+ var basedir = dirname(context.filename);
248
+ var resolvedPath = resolveImportPath({
249
+ basedir: basedir,
250
+ importPath: importPath,
251
+ fs: fs
252
+ });
253
+ if (!resolvedPath) {
254
+ return null;
255
+ }
256
+ var workspaceRoot = findWorkspaceRoot({
257
+ startPath: basedir,
258
+ fs: fs
259
+ });
260
+ var exportMap = parseBarrelExportsFromShared({
261
+ barrelFilePath: resolvedPath,
262
+ workspaceRoot: workspaceRoot,
263
+ fs: fs
264
+ });
265
+ if (exportMap.size === 0) {
266
+ return null;
267
+ }
268
+ if (!hasReExportsFromOtherFiles({
269
+ exportMap: exportMap,
270
+ sourceFilePath: resolvedPath
271
+ })) {
272
+ return null;
273
+ }
274
+ return {
275
+ importPath: importPath,
276
+ basedir: basedir,
277
+ resolvedPath: resolvedPath,
278
+ workspaceRoot: workspaceRoot,
279
+ exportMap: exportMap
280
+ };
281
+ }
282
+
283
+ /**
284
+ * Collect specifiers grouped by their source file.
285
+ */
286
+ function collectSpecifiersBySource(_ref6) {
287
+ var specifiers = _ref6.specifiers,
288
+ node = _ref6.node,
289
+ exportMap = _ref6.exportMap;
290
+ var importsBySource = new Map();
291
+ var unmappedSpecifiers = [];
292
+ var hasNamespaceImport = false;
293
+ var _iterator = _createForOfIteratorHelper(specifiers),
294
+ _step;
295
+ try {
296
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
297
+ var spec = _step.value;
298
+ var nameInSource = void 0;
299
+ var nameInLocal = void 0;
300
+ var kind = 'value';
301
+ if (spec.type === 'ImportNamespaceSpecifier') {
302
+ hasNamespaceImport = true;
303
+ continue;
304
+ }
305
+ if (spec.type === 'ImportDefaultSpecifier') {
306
+ nameInSource = 'default';
307
+ nameInLocal = spec.local.name;
308
+ } else if (spec.type === 'ImportSpecifier') {
309
+ nameInSource = getImportedName(spec);
310
+ nameInLocal = spec.local.name;
311
+ var parentImportKind = node.type === 'ImportDeclaration' ? node.importKind : undefined;
312
+ kind = parentImportKind === 'type' || spec.importKind === 'type' ? 'type' : 'value';
313
+ } else if (spec.type === 'ExportSpecifier') {
314
+ nameInSource = spec.local.name;
315
+ nameInLocal = spec.exported.name;
316
+ var parentExportKind = node.type === 'ExportNamedDeclaration' ? node.exportKind : undefined;
317
+ kind = parentExportKind === 'type' || spec.exportKind === 'type' ? 'type' : 'value';
318
+ } else {
319
+ continue;
320
+ }
321
+ var exportInfo = exportMap.get(nameInSource);
322
+ if (exportInfo) {
323
+ if (!importsBySource.has(exportInfo.path)) {
324
+ importsBySource.set(exportInfo.path, []);
325
+ }
326
+ var effectiveKind = kind === 'type' || exportInfo.isTypeOnly ? 'type' : 'value';
327
+ importsBySource.get(exportInfo.path).push({
328
+ spec: spec,
329
+ originalName: exportInfo.originalName,
330
+ exportInfo: exportInfo,
331
+ nameInSource: nameInSource,
332
+ nameInLocal: nameInLocal,
333
+ kind: effectiveKind
334
+ });
335
+ } else {
336
+ unmappedSpecifiers.push(spec);
337
+ }
338
+ }
339
+ } catch (err) {
340
+ _iterator.e(err);
341
+ } finally {
342
+ _iterator.f();
343
+ }
344
+ return {
345
+ importsBySource: importsBySource,
346
+ unmappedSpecifiers: unmappedSpecifiers,
347
+ hasNamespaceImport: hasNamespaceImport
348
+ };
349
+ }
350
+
351
+ /**
352
+ * Find an existing import statement that imports from the same source file.
353
+ */
354
+ function findExistingImportForSourceFile(_ref7) {
355
+ var sourceFile = _ref7.sourceFile,
356
+ allImports = _ref7.allImports,
357
+ basedir = _ref7.basedir,
358
+ fs = _ref7.fs;
359
+ return allImports.find(function (n) {
360
+ var isSourceAbsolute = sourceFile.startsWith('/') || sourceFile.match(/^[a-zA-Z]:/);
361
+ if (!isRelativeImport(sourceFile) && !isSourceAbsolute) {
362
+ return n.source.value === sourceFile;
363
+ }
364
+ if (!isRelativeImport(n.source.value)) {
365
+ return false;
366
+ }
367
+ var existingPath = resolveImportPath({
368
+ basedir: basedir,
369
+ importPath: n.source.value,
370
+ fs: fs
371
+ });
372
+ return existingPath === sourceFile;
373
+ });
374
+ }
375
+
376
+ /**
377
+ * Find an existing export statement that exports from the same source file.
378
+ */
379
+ function findExistingExportForSourceFile(_ref8) {
380
+ var sourceFile = _ref8.sourceFile,
381
+ allExports = _ref8.allExports,
382
+ basedir = _ref8.basedir,
383
+ fs = _ref8.fs;
384
+ return allExports.find(function (n) {
385
+ if (!n.source) {
386
+ return false;
387
+ }
388
+ var isSourceAbsolute = sourceFile.startsWith('/') || sourceFile.match(/^[a-zA-Z]:/);
389
+ if (!isRelativeImport(sourceFile) && !isSourceAbsolute) {
390
+ return n.source.value === sourceFile;
391
+ }
392
+ if (!isRelativeImport(n.source.value)) {
393
+ return false;
394
+ }
395
+ var existingPath = resolveImportPath({
396
+ basedir: basedir,
397
+ importPath: n.source.value,
398
+ fs: fs
399
+ });
400
+ return existingPath === sourceFile;
401
+ });
402
+ }
403
+
404
+ /**
405
+ * Transform import specifiers to handle aliasing when the original name differs.
406
+ */
407
+ function transformImportSpecifiers(_ref9) {
408
+ var specsWithOriginal = _ref9.specsWithOriginal;
409
+ return specsWithOriginal.map(function (_ref0) {
410
+ var spec = _ref0.spec,
411
+ originalName = _ref0.originalName,
412
+ kind = _ref0.kind;
413
+ if (!originalName) {
414
+ return spec;
415
+ }
416
+ if (originalName === 'default') {
417
+ if (spec.type === 'ImportDefaultSpecifier') {
418
+ return spec;
419
+ }
420
+ return {
421
+ type: 'ImportDefaultSpecifier',
422
+ local: spec.local,
423
+ range: spec.range,
424
+ loc: spec.loc,
425
+ parent: spec.parent
426
+ };
427
+ } else {
428
+ return {
429
+ type: 'ImportSpecifier',
430
+ local: spec.local,
431
+ imported: {
432
+ type: 'Identifier',
433
+ name: originalName,
434
+ range: [0, 0],
435
+ loc: {
436
+ start: {
437
+ line: 0,
438
+ column: 0
439
+ },
440
+ end: {
441
+ line: 0,
442
+ column: 0
443
+ }
444
+ }
445
+ },
446
+ importKind: kind,
447
+ range: spec.range,
448
+ loc: spec.loc,
449
+ parent: spec.parent
450
+ };
451
+ }
452
+ });
453
+ }
454
+
455
+ /**
456
+ * Transform export specifiers to use original names from source.
457
+ */
458
+ function transformExportSpecifiers(_ref1) {
459
+ var specsWithOriginal = _ref1.specsWithOriginal;
460
+ return specsWithOriginal.map(function (_ref10) {
461
+ var originalName = _ref10.originalName,
462
+ nameInLocal = _ref10.nameInLocal,
463
+ kind = _ref10.kind;
464
+ return {
465
+ nameInSource: originalName || 'default',
466
+ nameInLocal: nameInLocal,
467
+ kind: kind
468
+ };
469
+ });
470
+ }
471
+ export function createRule(fs) {
472
+ return {
473
+ meta: ruleMeta,
474
+ create: function create(context) {
475
+ var checkNode = function checkNode(rawNode) {
476
+ var node = rawNode;
477
+
478
+ // Resolve barrel file context (handles early exits for non-barrel files)
479
+ var barrelContext = resolveBarrelFileContext({
480
+ node: node,
481
+ context: context,
482
+ fs: fs
483
+ });
484
+ if (!barrelContext) {
485
+ return;
486
+ }
487
+ var importPath = barrelContext.importPath,
488
+ resolvedPath = barrelContext.resolvedPath,
489
+ exportMap = barrelContext.exportMap;
490
+
491
+ // Check if we have any imports from this barrel
492
+ var specifiers = node.specifiers;
493
+ if (specifiers.length === 0) {
494
+ return;
495
+ }
496
+
497
+ // Collect imports by source file
498
+ var _collectSpecifiersByS = collectSpecifiersBySource({
499
+ specifiers: specifiers,
500
+ node: node,
501
+ exportMap: exportMap
502
+ }),
503
+ importsBySource = _collectSpecifiersByS.importsBySource,
504
+ unmappedSpecifiers = _collectSpecifiersByS.unmappedSpecifiers,
505
+ hasNamespaceImport = _collectSpecifiersByS.hasNamespaceImport;
506
+
507
+ // If we have import * as, warn but don't auto-fix (too complex)
508
+ if (hasNamespaceImport) {
509
+ context.report({
510
+ node: node,
511
+ messageId: 'barrelImport',
512
+ data: {
513
+ path: importPath
514
+ }
515
+ });
516
+ return;
517
+ }
518
+
519
+ // Check if we actually found any imports that map to the barrel exports
520
+ // If we found 0 mapped imports (all are unknown or missing), don't warn
521
+ if (importsBySource.size === 0) {
522
+ return;
523
+ }
524
+
525
+ // If all imports map back to the resolved path itself, don't warn.
526
+ // This happens when the file (e.g. index.ts) exports the symbols directly (not re-exports),
527
+ // so it is not acting as a barrel file for these imports.
528
+ if (importsBySource.size === 1 && importsBySource.has(resolvedPath)) {
529
+ return;
530
+ }
531
+
532
+ // Build the report with optional auto-fix
533
+ var reportObj = {
534
+ node: node,
535
+ messageId: 'barrelImport',
536
+ data: {
537
+ path: importPath
538
+ }
539
+ };
540
+
541
+ // Only provide auto-fix if all imports are mapped
542
+ // If there are unmapped specifiers, don't auto-fix to avoid issues
543
+ var nodeSource = node.source;
544
+ if (unmappedSpecifiers.length === 0 && nodeSource) {
545
+ reportObj.fix = function (fixer) {
546
+ var sourceCode = context.getSourceCode();
547
+ var quote = sourceCode.getText(nodeSource)[0]; // Get quote character
548
+ var basedirForFix = dirname(context.filename);
549
+ var fixes = [];
550
+ var newStatementsForBarrelReplacement = [];
551
+
552
+ // Generate new import statements for each source file
553
+ var sourceFileArray = Array.from(importsBySource.entries());
554
+ var _loop = function _loop() {
555
+ var _sourceFileArray$i = _slicedToArray(sourceFileArray[i], 2),
556
+ sourceFile = _sourceFileArray$i[0],
557
+ specsWithOriginal = _sourceFileArray$i[1];
558
+ if (node.type === 'ImportDeclaration') {
559
+ // Transform specifiers if needed (handle aliasing)
560
+ var specs = transformImportSpecifiers({
561
+ specsWithOriginal: specsWithOriginal
562
+ });
563
+
564
+ // Get all existing imports to check for merging
565
+ var allImports = sourceCode.ast.body.filter(function (n) {
566
+ return n.type === 'ImportDeclaration' && n !== node;
567
+ });
568
+
569
+ // Check for existing import
570
+ var existingImport = findExistingImportForSourceFile({
571
+ sourceFile: sourceFile,
572
+ allImports: allImports,
573
+ basedir: basedirForFix,
574
+ fs: fs
575
+ });
576
+
577
+ // Skip merging if existing is namespace import
578
+ var isNamespace = existingImport === null || existingImport === void 0 ? void 0 : existingImport.specifiers.some(function (s) {
579
+ return s.type === 'ImportNamespaceSpecifier';
580
+ });
581
+ if (existingImport && !isNamespace) {
582
+ var _specsWithOriginal$0$, _specsWithOriginal$;
583
+ // Merge!
584
+ var existingSpecs = existingImport.specifiers.map(function (s) {
585
+ // Normalize importKind
586
+ if (existingImport.importKind === 'type') {
587
+ // If the parent declaration is 'type', treat all specifiers as 'type'
588
+ // We cast to AugmentedSpecifier to allow attaching importKind to DefaultSpecifier
589
+ return _objectSpread(_objectSpread({}, s), {}, {
590
+ importKind: 'type'
591
+ });
592
+ }
593
+ return s;
594
+ });
595
+ var newSpecs = specs.map(function (s) {
596
+ if (node.importKind === 'type') {
597
+ return _objectSpread(_objectSpread({}, s), {}, {
598
+ importKind: 'type'
599
+ });
600
+ }
601
+ return s;
602
+ });
603
+ var mergedSpecs = [].concat(_toConsumableArray(existingSpecs), _toConsumableArray(newSpecs));
604
+
605
+ // Determine if we should use 'import type'
606
+ var allType = mergedSpecs.every(function (s) {
607
+ return s.importKind === 'type';
608
+ });
609
+ var relativePath = getImportPathForSourceFile({
610
+ sourceFilePath: sourceFile,
611
+ basedir: basedirForFix,
612
+ originalImportPath: importPath,
613
+ exportInfo: (_specsWithOriginal$0$ = (_specsWithOriginal$ = specsWithOriginal[0]) === null || _specsWithOriginal$ === void 0 ? void 0 : _specsWithOriginal$.exportInfo) !== null && _specsWithOriginal$0$ !== void 0 ? _specsWithOriginal$0$ : null,
614
+ workspaceRoot: findWorkspaceRoot({
615
+ startPath: basedirForFix,
616
+ fs: fs
617
+ }),
618
+ fs: fs
619
+ });
620
+ var newImportStatement = buildImportStatement({
621
+ specs: mergedSpecs,
622
+ path: relativePath,
623
+ quoteChar: quote,
624
+ isTypeImport: allType // Use type import if all are types
625
+ });
626
+ if (newImportStatement.length > 0) {
627
+ fixes.push(fixer.replaceText(existingImport, newImportStatement));
628
+ }
629
+ } else {
630
+ var _specsWithOriginal$0$2, _specsWithOriginal$2;
631
+ // Create new import
632
+ var _relativePath = getImportPathForSourceFile({
633
+ sourceFilePath: sourceFile,
634
+ basedir: basedirForFix,
635
+ originalImportPath: importPath,
636
+ exportInfo: (_specsWithOriginal$0$2 = (_specsWithOriginal$2 = specsWithOriginal[0]) === null || _specsWithOriginal$2 === void 0 ? void 0 : _specsWithOriginal$2.exportInfo) !== null && _specsWithOriginal$0$2 !== void 0 ? _specsWithOriginal$0$2 : null,
637
+ workspaceRoot: findWorkspaceRoot({
638
+ startPath: basedirForFix,
639
+ fs: fs
640
+ }),
641
+ fs: fs
642
+ });
643
+ var isTypeImport = node.importKind === 'type';
644
+ var importStatement = buildImportStatement({
645
+ specs: specs,
646
+ path: _relativePath,
647
+ quoteChar: quote,
648
+ isTypeImport: isTypeImport
649
+ });
650
+ if (importStatement.length > 0) {
651
+ newStatementsForBarrelReplacement.push(importStatement);
652
+ }
653
+ }
654
+ } else if (node.type === 'ExportNamedDeclaration') {
655
+ // Handle ExportNamedDeclaration
656
+ var _specs = transformExportSpecifiers({
657
+ specsWithOriginal: specsWithOriginal
658
+ });
659
+
660
+ // Get all existing exports to check for merging
661
+ var allExports = sourceCode.ast.body.filter(function (n) {
662
+ return n.type === 'ExportNamedDeclaration' && n !== node && !!n.source;
663
+ });
664
+
665
+ // Check for existing export
666
+ var existingExport = findExistingExportForSourceFile({
667
+ sourceFile: sourceFile,
668
+ allExports: allExports,
669
+ basedir: basedirForFix,
670
+ fs: fs
671
+ });
672
+ if (existingExport) {
673
+ var _specsWithOriginal$0$3, _specsWithOriginal$3;
674
+ // Merge!
675
+ var _existingSpecs = existingExport.specifiers.map(function (s) {
676
+ // For `export type { A, B }`, the parent's exportKind is 'type'
677
+ // Individual specifiers have exportKind: 'type' only for inline type (export { type A })
678
+ // If parent is type-only, all specifiers are types
679
+ // Otherwise, check individual specifier's exportKind
680
+ var effectiveKind = existingExport.exportKind === 'type' || s.exportKind === 'type' ? 'type' : 'value';
681
+ return {
682
+ nameInSource: getExportedName(s.local),
683
+ nameInLocal: getExportedName(s.exported),
684
+ kind: effectiveKind
685
+ };
686
+ });
687
+ var _newSpecs = _specs.map(function (s) {
688
+ if (node.exportKind === 'type') {
689
+ return _objectSpread(_objectSpread({}, s), {}, {
690
+ kind: 'type'
691
+ });
692
+ }
693
+ return s;
694
+ });
695
+ var _mergedSpecs = [].concat(_toConsumableArray(_existingSpecs), _toConsumableArray(_newSpecs));
696
+
697
+ // Determine if we should use 'export type'
698
+ var _allType = _mergedSpecs.every(function (s) {
699
+ return s.kind === 'type';
700
+ });
701
+ var _relativePath2 = getImportPathForSourceFile({
702
+ sourceFilePath: sourceFile,
703
+ basedir: basedirForFix,
704
+ originalImportPath: importPath,
705
+ exportInfo: (_specsWithOriginal$0$3 = (_specsWithOriginal$3 = specsWithOriginal[0]) === null || _specsWithOriginal$3 === void 0 ? void 0 : _specsWithOriginal$3.exportInfo) !== null && _specsWithOriginal$0$3 !== void 0 ? _specsWithOriginal$0$3 : null,
706
+ workspaceRoot: findWorkspaceRoot({
707
+ startPath: basedirForFix,
708
+ fs: fs
709
+ }),
710
+ fs: fs
711
+ });
712
+ var newExportStatement = buildExportStatement({
713
+ specs: _mergedSpecs,
714
+ path: _relativePath2,
715
+ quoteChar: quote,
716
+ isTypeExport: _allType
717
+ });
718
+ if (newExportStatement.length > 0) {
719
+ fixes.push(fixer.replaceText(existingExport, newExportStatement));
720
+ }
721
+ } else {
722
+ var _specsWithOriginal$0$4, _specsWithOriginal$4;
723
+ // Create new export
724
+ var _relativePath3 = getImportPathForSourceFile({
725
+ sourceFilePath: sourceFile,
726
+ basedir: basedirForFix,
727
+ originalImportPath: importPath,
728
+ exportInfo: (_specsWithOriginal$0$4 = (_specsWithOriginal$4 = specsWithOriginal[0]) === null || _specsWithOriginal$4 === void 0 ? void 0 : _specsWithOriginal$4.exportInfo) !== null && _specsWithOriginal$0$4 !== void 0 ? _specsWithOriginal$0$4 : null,
729
+ workspaceRoot: findWorkspaceRoot({
730
+ startPath: basedirForFix,
731
+ fs: fs
732
+ }),
733
+ fs: fs
734
+ });
735
+ var isTypeExport = node.exportKind === 'type';
736
+ var exportStatement = buildExportStatement({
737
+ specs: _specs,
738
+ path: _relativePath3,
739
+ quoteChar: quote,
740
+ isTypeExport: isTypeExport
741
+ });
742
+ if (exportStatement.length > 0) {
743
+ newStatementsForBarrelReplacement.push(exportStatement);
744
+ }
745
+ }
746
+ }
747
+ };
748
+ for (var i = 0; i < sourceFileArray.length; i++) {
749
+ _loop();
750
+ }
751
+ if (newStatementsForBarrelReplacement.length > 0) {
752
+ fixes.push(fixer.replaceText(node, newStatementsForBarrelReplacement.join('\n')));
753
+ } else {
754
+ // If all were merged, remove the node
755
+ fixes.push(fixer.remove(node));
756
+ }
757
+ return fixes;
758
+ };
759
+ }
760
+ context.report(reportObj);
761
+ };
762
+ return {
763
+ ImportDeclaration: checkNode,
764
+ ExportNamedDeclaration: checkNode
765
+ };
766
+ }
767
+ };
768
+ }
769
+ var rule = createRule(realFileSystem);
770
+ export default rule;