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