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