@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,1401 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ var _typeof3 = require("@babel/runtime/helpers/typeof");
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.createRule = createRule;
9
+ exports.default = void 0;
10
+ exports.validateAndResolveBarrelFile = validateAndResolveBarrelFile;
11
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
12
+ var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
13
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
14
+ var _path = require("path");
15
+ var ts = _interopRequireWildcard(require("typescript"));
16
+ var _barrelParsing = require("../shared/barrel-parsing");
17
+ var _fileSystem = require("../shared/file-system");
18
+ var _jestUtils = require("../shared/jest-utils");
19
+ var _packageRegistry = require("../shared/package-registry");
20
+ var _packageResolution = require("../shared/package-resolution");
21
+ var _types = require("../shared/types");
22
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof3(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
23
+ 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; } } }; }
24
+ 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; } }
25
+ 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; }
26
+ // Cache per source package name to avoid repeated exports parsing during a single lint run.
27
+ // This is keyed by fs instance to avoid test pollution.
28
+ var sourcePackageExportsMapsByFs = new WeakMap();
29
+ function getSourcePackageExportsMaps(fs) {
30
+ var map = sourcePackageExportsMapsByFs.get(fs);
31
+ if (!map) {
32
+ map = new Map();
33
+ sourcePackageExportsMapsByFs.set(fs, map);
34
+ }
35
+ return map;
36
+ }
37
+
38
+ /**
39
+ * Information about a mock factory's preamble (statements before the return)
40
+ */
41
+
42
+ /**
43
+ * Extract identifiers defined by a statement (e.g., variable declarations)
44
+ * Uses TypeScript AST to find declared identifiers.
45
+ */
46
+ function extractDefinedIdentifiers(statementText) {
47
+ var identifiers = new Set();
48
+ try {
49
+ // Parse the statement as a mini source file
50
+ var sourceFile = ts.createSourceFile('temp.ts', statementText, ts.ScriptTarget.Latest, true);
51
+ var _visit = function visit(node) {
52
+ if (ts.isVariableStatement(node)) {
53
+ var _iterator = _createForOfIteratorHelper(node.declarationList.declarations),
54
+ _step;
55
+ try {
56
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
57
+ var decl = _step.value;
58
+ if (ts.isIdentifier(decl.name)) {
59
+ identifiers.add(decl.name.text);
60
+ } else if (ts.isObjectBindingPattern(decl.name)) {
61
+ // Handle destructuring: const { a, b } = ...
62
+ var _iterator2 = _createForOfIteratorHelper(decl.name.elements),
63
+ _step2;
64
+ try {
65
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
66
+ var element = _step2.value;
67
+ if (ts.isBindingElement(element) && ts.isIdentifier(element.name)) {
68
+ identifiers.add(element.name.text);
69
+ }
70
+ }
71
+ } catch (err) {
72
+ _iterator2.e(err);
73
+ } finally {
74
+ _iterator2.f();
75
+ }
76
+ } else if (ts.isArrayBindingPattern(decl.name)) {
77
+ // Handle array destructuring: const [a, b] = ...
78
+ var _iterator3 = _createForOfIteratorHelper(decl.name.elements),
79
+ _step3;
80
+ try {
81
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
82
+ var _element = _step3.value;
83
+ if (ts.isBindingElement(_element) && ts.isIdentifier(_element.name)) {
84
+ identifiers.add(_element.name.text);
85
+ }
86
+ }
87
+ } catch (err) {
88
+ _iterator3.e(err);
89
+ } finally {
90
+ _iterator3.f();
91
+ }
92
+ }
93
+ }
94
+ } catch (err) {
95
+ _iterator.e(err);
96
+ } finally {
97
+ _iterator.f();
98
+ }
99
+ } else if (ts.isFunctionDeclaration(node) && node.name) {
100
+ identifiers.add(node.name.text);
101
+ } else if (ts.isClassDeclaration(node) && node.name) {
102
+ identifiers.add(node.name.text);
103
+ }
104
+ ts.forEachChild(node, _visit);
105
+ };
106
+ ts.forEachChild(sourceFile, _visit);
107
+ } catch (_unused) {
108
+ // Ignore parsing errors
109
+ }
110
+ return identifiers;
111
+ }
112
+
113
+ /**
114
+ * Find all identifiers used in a given text string.
115
+ * Uses a simple regex approach to find potential identifier references.
116
+ */
117
+ function findUsedIdentifiers(text, potentialIdentifiers) {
118
+ var used = new Set();
119
+ var _iterator4 = _createForOfIteratorHelper(potentialIdentifiers),
120
+ _step4;
121
+ try {
122
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
123
+ var identifier = _step4.value;
124
+ // Use word boundary matching to find identifier usage
125
+ // This matches the identifier as a whole word (not part of another word)
126
+ var regex = new RegExp("\\b".concat(escapeRegExpForIdentifier(identifier), "\\b"));
127
+ if (regex.test(text)) {
128
+ used.add(identifier);
129
+ }
130
+ }
131
+ } catch (err) {
132
+ _iterator4.e(err);
133
+ } finally {
134
+ _iterator4.f();
135
+ }
136
+ return used;
137
+ }
138
+
139
+ /**
140
+ * Escape special regex characters for identifier matching
141
+ */
142
+ function escapeRegExpForIdentifier(str) {
143
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
144
+ }
145
+
146
+ /**
147
+ * Filter preamble statements to only include those whose defined identifiers
148
+ * are used in the given property texts.
149
+ */
150
+ function filterPreambleForProperties(preamble, propertyTexts) {
151
+ if (!preamble.hasPreamble || preamble.statements.length === 0) {
152
+ return preamble;
153
+ }
154
+
155
+ // Collect all identifiers defined in the preamble
156
+ var allDefinedIdentifiers = new Set();
157
+ var _iterator5 = _createForOfIteratorHelper(preamble.statements),
158
+ _step5;
159
+ try {
160
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
161
+ var stmt = _step5.value;
162
+ var _iterator7 = _createForOfIteratorHelper(stmt.definedIdentifiers),
163
+ _step7;
164
+ try {
165
+ for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
166
+ var id = _step7.value;
167
+ allDefinedIdentifiers.add(id);
168
+ }
169
+ } catch (err) {
170
+ _iterator7.e(err);
171
+ } finally {
172
+ _iterator7.f();
173
+ }
174
+ }
175
+
176
+ // Find which identifiers are used in the property texts
177
+ } catch (err) {
178
+ _iterator5.e(err);
179
+ } finally {
180
+ _iterator5.f();
181
+ }
182
+ var combinedPropertyText = propertyTexts.join('\n');
183
+ var usedIdentifiers = findUsedIdentifiers(combinedPropertyText, allDefinedIdentifiers);
184
+
185
+ // Filter statements to only those that define used identifiers
186
+ var filteredStatements = preamble.statements.filter(function (stmt) {
187
+ // Include statement if any of its defined identifiers are used
188
+ var _iterator6 = _createForOfIteratorHelper(stmt.definedIdentifiers),
189
+ _step6;
190
+ try {
191
+ for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
192
+ var id = _step6.value;
193
+ if (usedIdentifiers.has(id)) {
194
+ return true;
195
+ }
196
+ }
197
+ } catch (err) {
198
+ _iterator6.e(err);
199
+ } finally {
200
+ _iterator6.f();
201
+ }
202
+ return false;
203
+ });
204
+ if (filteredStatements.length === 0) {
205
+ return {
206
+ text: '',
207
+ hasPreamble: false,
208
+ statements: []
209
+ };
210
+ }
211
+ return {
212
+ text: filteredStatements.map(function (s) {
213
+ return s.text;
214
+ }).join('\n\t'),
215
+ hasPreamble: true,
216
+ statements: filteredStatements
217
+ };
218
+ }
219
+
220
+ /**
221
+ * Convert absolute file path to an import path, handling cross-package resolution.
222
+ * If the export comes from a cross-package source, returns the package path (e.g., '@atlassian/package-b/utils').
223
+ * Otherwise, returns a relative path.
224
+ */
225
+ function getImportPathForSourceFile(_ref) {
226
+ var _exportInfo$crossPack;
227
+ var sourceFilePath = _ref.sourceFilePath,
228
+ basedir = _ref.basedir,
229
+ originalImportPath = _ref.originalImportPath,
230
+ exportInfo = _ref.exportInfo,
231
+ workspaceRoot = _ref.workspaceRoot,
232
+ fs = _ref.fs;
233
+ var crossPackageName = exportInfo === null || exportInfo === void 0 || (_exportInfo$crossPack = exportInfo.crossPackageSource) === null || _exportInfo$crossPack === void 0 ? void 0 : _exportInfo$crossPack.packageName;
234
+ if (crossPackageName) {
235
+ var sourcePackageExportsMaps = getSourcePackageExportsMaps(fs);
236
+ var exportsMap = sourcePackageExportsMaps.get(crossPackageName);
237
+ if (!exportsMap) {
238
+ var pkgDir = (0, _packageRegistry.findPackageInRegistry)({
239
+ packageName: crossPackageName,
240
+ workspaceRoot: workspaceRoot,
241
+ fs: fs
242
+ });
243
+ if (pkgDir) {
244
+ exportsMap = (0, _packageResolution.parsePackageExports)({
245
+ packageDir: pkgDir,
246
+ fs: fs
247
+ });
248
+ sourcePackageExportsMaps.set(crossPackageName, exportsMap);
249
+ }
250
+ }
251
+ var targetExportPath = exportsMap ? (0, _packageResolution.findExportForSourceFile)({
252
+ sourceFilePath: sourceFilePath,
253
+ exportsMap: exportsMap
254
+ }) : null;
255
+ return targetExportPath ? crossPackageName + targetExportPath.slice(1) : crossPackageName;
256
+ }
257
+ return getRelativeImportPath({
258
+ basedir: basedir,
259
+ absolutePath: sourceFilePath,
260
+ originalImportPath: originalImportPath
261
+ });
262
+ }
263
+
264
+ /**
265
+ * Convert absolute file path back to relative import path
266
+ */
267
+ function getRelativeImportPath(_ref2) {
268
+ var basedir = _ref2.basedir,
269
+ absolutePath = _ref2.absolutePath,
270
+ originalImportPath = _ref2.originalImportPath;
271
+ var relativePath = (0, _path.relative)(basedir, absolutePath);
272
+ // Normalize to use forward slashes
273
+ relativePath = relativePath.replace(/\\/g, '/');
274
+
275
+ // Check for extension in original path
276
+ var extMatch = originalImportPath.match(/\.(js|jsx|ts|tsx|mjs|cjs)$/);
277
+ var originalExt = extMatch ? extMatch[0] : '';
278
+
279
+ // Get extension from the resolved absolute path
280
+ var targetExtMatch = absolutePath.match(/\.(js|jsx|ts|tsx|mjs|cjs)$/);
281
+ var targetExt = targetExtMatch ? targetExtMatch[0] : '';
282
+
283
+ // Remove file extension from the target path
284
+ relativePath = relativePath.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/, '');
285
+
286
+ // If original had extension, append it
287
+ if (originalExt) {
288
+ // If original was a TypeScript source extension, use the actual target extension
289
+ if (['.ts', '.tsx'].includes(originalExt) && targetExt) {
290
+ relativePath += targetExt;
291
+ } else {
292
+ relativePath += originalExt;
293
+ }
294
+ } else {
295
+ // Remove /index suffix only if no extension was present
296
+ if (relativePath.endsWith('/index')) {
297
+ relativePath = relativePath.slice(0, -6);
298
+ } else if (relativePath === 'index') {
299
+ relativePath = '.';
300
+ }
301
+ }
302
+
303
+ // Ensure it starts with .. or .
304
+ if (!relativePath.startsWith('.') && !relativePath.startsWith('/')) {
305
+ relativePath = './' + relativePath;
306
+ }
307
+ return relativePath;
308
+ }
309
+
310
+ /**
311
+ * Check if a node is an Object.assign call
312
+ */
313
+ function isObjectAssignCall(node) {
314
+ if (node.type !== 'CallExpression') {
315
+ return false;
316
+ }
317
+ var callee = node.callee;
318
+ if (callee.type === 'MemberExpression') {
319
+ return callee.object.type === 'Identifier' && callee.object.name === 'Object' && callee.property.type === 'Identifier' && callee.property.name === 'assign';
320
+ }
321
+ return false;
322
+ }
323
+
324
+ /**
325
+ * Extract mock object from Object.assign pattern
326
+ * Pattern: Object.assign({}, jest.requireActual(...), { mockProps })
327
+ * Returns the properties object and whether it has requireActual
328
+ */
329
+ function extractObjectAssignMock(node) {
330
+ var args = node.arguments;
331
+
332
+ // Object.assign typically has at least 2 arguments: target and source(s)
333
+ // Pattern: Object.assign({}, jest.requireActual(...), { mockProps })
334
+ // or: Object.assign({}, jest.requireActual(...), { mockProps1 }, { mockProps2 })
335
+ if (args.length < 2) {
336
+ return {
337
+ propertiesObject: null,
338
+ hasRequireActual: false
339
+ };
340
+ }
341
+ var hasRequireActual = false;
342
+ var lastObjectExpression = null;
343
+
344
+ // Scan through arguments to find jest.requireActual and the last object literal
345
+ var _iterator8 = _createForOfIteratorHelper(args),
346
+ _step8;
347
+ try {
348
+ for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
349
+ var arg = _step8.value;
350
+ if ((0, _jestUtils.isJestRequireActual)(arg)) {
351
+ hasRequireActual = true;
352
+ }
353
+ if (arg.type === 'ObjectExpression') {
354
+ // Skip empty objects (the first {} in Object.assign({}, ...))
355
+ if (arg.properties.length > 0) {
356
+ lastObjectExpression = arg;
357
+ }
358
+ }
359
+ }
360
+ } catch (err) {
361
+ _iterator8.e(err);
362
+ } finally {
363
+ _iterator8.f();
364
+ }
365
+ return {
366
+ propertiesObject: lastObjectExpression,
367
+ hasRequireActual: hasRequireActual
368
+ };
369
+ }
370
+
371
+ /**
372
+ * Extract mock object properties from jest.mock call
373
+ * Returns a map of property name -> { node, text } and whether there's a jest.requireActual spread
374
+ */
375
+ function extractMockProperties(_ref3) {
376
+ var sourceCode = _ref3.sourceCode,
377
+ mockObjectNode = _ref3.mockObjectNode;
378
+ var properties = new Map();
379
+ var hasRequireActual = false;
380
+
381
+ // Handle Object.assign pattern: Object.assign({}, jest.requireActual(...), { props })
382
+ if (isObjectAssignCall(mockObjectNode)) {
383
+ var _extractObjectAssignM = extractObjectAssignMock(mockObjectNode),
384
+ propertiesObject = _extractObjectAssignM.propertiesObject,
385
+ objectAssignHasRequireActual = _extractObjectAssignM.hasRequireActual;
386
+ if (propertiesObject) {
387
+ // Recursively extract properties from the properties object
388
+ var result = extractMockProperties({
389
+ sourceCode: sourceCode,
390
+ mockObjectNode: propertiesObject
391
+ });
392
+ return {
393
+ properties: result.properties,
394
+ hasRequireActual: objectAssignHasRequireActual || result.hasRequireActual
395
+ };
396
+ }
397
+ return {
398
+ properties: properties,
399
+ hasRequireActual: objectAssignHasRequireActual
400
+ };
401
+ }
402
+ if (mockObjectNode.type === 'ObjectExpression') {
403
+ var _iterator9 = _createForOfIteratorHelper(mockObjectNode.properties),
404
+ _step9;
405
+ try {
406
+ for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) {
407
+ var prop = _step9.value;
408
+ if (prop.type === 'SpreadElement') {
409
+ // Check if this is ...jest.requireActual(...)
410
+ if ((0, _jestUtils.isJestRequireActual)(prop.argument)) {
411
+ hasRequireActual = true;
412
+ }
413
+ } else if (prop.type === 'Property') {
414
+ var keyName = void 0;
415
+ if (prop.key.type === 'Identifier') {
416
+ keyName = prop.key.name;
417
+ } else if (prop.key.type === 'Literal') {
418
+ keyName = String(prop.key.value);
419
+ } else {
420
+ continue;
421
+ }
422
+ var propText = sourceCode.getText(prop);
423
+ var valueText = sourceCode.getText(prop.value);
424
+ properties.set(keyName, {
425
+ node: prop,
426
+ text: propText,
427
+ valueText: valueText
428
+ });
429
+ }
430
+ }
431
+ } catch (err) {
432
+ _iterator9.e(err);
433
+ } finally {
434
+ _iterator9.f();
435
+ }
436
+ }
437
+ return {
438
+ properties: properties,
439
+ hasRequireActual: hasRequireActual
440
+ };
441
+ }
442
+
443
+ /**
444
+ * Validate and resolve a barrel file from an import path
445
+ * Returns null if not a valid relative barrel import
446
+ */
447
+ function validateAndResolveBarrelFile(_ref4) {
448
+ var importPath = _ref4.importPath,
449
+ basedir = _ref4.basedir,
450
+ workspaceRoot = _ref4.workspaceRoot,
451
+ fs = _ref4.fs;
452
+ if (!(0, _fileSystem.isRelativeImport)(importPath)) {
453
+ return null;
454
+ }
455
+ var resolvedPath = (0, _fileSystem.resolveImportPath)({
456
+ basedir: basedir,
457
+ importPath: importPath,
458
+ fs: fs
459
+ });
460
+ if (!resolvedPath) {
461
+ return null;
462
+ }
463
+ var exportMap = (0, _barrelParsing.parseBarrelExports)({
464
+ barrelFilePath: resolvedPath,
465
+ workspaceRoot: workspaceRoot,
466
+ fs: fs
467
+ });
468
+ if (exportMap.size === 0) {
469
+ return null;
470
+ }
471
+
472
+ // A file is considered a barrel file if it has re-exports from other files.
473
+ // This is the semantic check - we don't care about the filename.
474
+ if (!(0, _barrelParsing.hasReExportsFromOtherFiles)({
475
+ exportMap: exportMap,
476
+ sourceFilePath: resolvedPath
477
+ })) {
478
+ return null;
479
+ }
480
+ return {
481
+ resolvedPath: resolvedPath,
482
+ exportMap: exportMap
483
+ };
484
+ }
485
+
486
+ /**
487
+ * Extract the mock implementation object from the jest.mock call
488
+ */
489
+ function extractMockImplementation(mockImpl) {
490
+ if (mockImpl.type === 'ArrowFunctionExpression') {
491
+ if (mockImpl.body.type === 'ObjectExpression') {
492
+ return mockImpl.body;
493
+ }
494
+ // Handle arrow functions that return a call expression directly (e.g., Object.assign)
495
+ if (mockImpl.body.type === 'CallExpression') {
496
+ return mockImpl.body;
497
+ }
498
+ if (mockImpl.body.type === 'BlockStatement') {
499
+ var returnStmt = mockImpl.body.body.find(function (s) {
500
+ return s.type === 'ReturnStatement';
501
+ });
502
+ if (returnStmt !== null && returnStmt !== void 0 && returnStmt.argument) {
503
+ return returnStmt.argument;
504
+ }
505
+ }
506
+ }
507
+ if (mockImpl.type === 'FunctionExpression' && mockImpl.body.type === 'BlockStatement') {
508
+ var _returnStmt = mockImpl.body.body.find(function (s) {
509
+ return s.type === 'ReturnStatement';
510
+ });
511
+ if (_returnStmt !== null && _returnStmt !== void 0 && _returnStmt.argument) {
512
+ return _returnStmt.argument;
513
+ }
514
+ }
515
+ return mockImpl;
516
+ }
517
+
518
+ /**
519
+ * Extract the preamble (statements before the return) from a mock factory function.
520
+ * This captures variable declarations, assignments, etc. that need to be preserved.
521
+ */
522
+ function extractMockFactoryPreamble(_ref5) {
523
+ var mockImpl = _ref5.mockImpl,
524
+ sourceCode = _ref5.sourceCode;
525
+ var emptyPreamble = {
526
+ text: '',
527
+ hasPreamble: false,
528
+ statements: []
529
+ };
530
+
531
+ // Get the block statement body from the mock factory
532
+ var blockBody = null;
533
+ if ((mockImpl.type === 'ArrowFunctionExpression' || mockImpl.type === 'FunctionExpression') && mockImpl.body.type === 'BlockStatement') {
534
+ blockBody = mockImpl.body.body;
535
+ }
536
+ if (!blockBody) {
537
+ return emptyPreamble;
538
+ }
539
+
540
+ // Find the return statement index
541
+ var returnIndex = blockBody.findIndex(function (s) {
542
+ return s.type === 'ReturnStatement';
543
+ });
544
+ if (returnIndex <= 0) {
545
+ // No preamble (return is first statement or not found)
546
+ return emptyPreamble;
547
+ }
548
+
549
+ // Extract all statements before the return
550
+ var preambleStatements = blockBody.slice(0, returnIndex);
551
+ var statementsWithIdentifiers = preambleStatements.map(function (stmt) {
552
+ var text = sourceCode.getText(stmt);
553
+ var definedIdentifiers = extractDefinedIdentifiers(text);
554
+ return {
555
+ text: text,
556
+ definedIdentifiers: definedIdentifiers
557
+ };
558
+ });
559
+ var preambleTexts = statementsWithIdentifiers.map(function (s) {
560
+ return s.text;
561
+ });
562
+ return {
563
+ text: preambleTexts.join('\n\t'),
564
+ hasPreamble: true,
565
+ statements: statementsWithIdentifiers
566
+ };
567
+ }
568
+
569
+ /**
570
+ * Rewrite jest.requireActual paths in a text string from the original barrel path to a new path.
571
+ */
572
+ function rewriteRequireActualPaths(_ref6) {
573
+ var text = _ref6.text,
574
+ originalPath = _ref6.originalPath,
575
+ newPath = _ref6.newPath,
576
+ quote = _ref6.quote;
577
+ // Match jest.requireActual('originalPath') or jest.requireActual("originalPath")
578
+ // Also handle the 'as Object' or 'as any' type assertions
579
+ var patterns = [
580
+ // With single quotes
581
+ new RegExp("jest\\.requireActual\\(\\s*'".concat(escapeRegExp(originalPath), "'\\s*\\)(?:\\s+as\\s+\\w+)?"), 'g'),
582
+ // With double quotes
583
+ new RegExp("jest\\.requireActual\\(\\s*\"".concat(escapeRegExp(originalPath), "\"\\s*\\)(?:\\s+as\\s+\\w+)?"), 'g')];
584
+ var result = text;
585
+ for (var _i = 0, _patterns = patterns; _i < _patterns.length; _i++) {
586
+ var pattern = _patterns[_i];
587
+ result = result.replace(pattern, "jest.requireActual(".concat(quote).concat(newPath).concat(quote, ")"));
588
+ }
589
+ return result;
590
+ }
591
+
592
+ /**
593
+ * Escape special regex characters in a string
594
+ */
595
+ function escapeRegExp(str) {
596
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
597
+ }
598
+
599
+ /**
600
+ * Group mocked properties by their source file
601
+ */
602
+ function groupPropertiesBySource(_ref7) {
603
+ var mockProperties = _ref7.mockProperties,
604
+ exportMap = _ref7.exportMap;
605
+ var propertiesBySource = new Map();
606
+ var _iterator0 = _createForOfIteratorHelper(mockProperties),
607
+ _step0;
608
+ try {
609
+ for (_iterator0.s(); !(_step0 = _iterator0.n()).done;) {
610
+ var _step0$value = (0, _slicedToArray2.default)(_step0.value, 1),
611
+ propName = _step0$value[0];
612
+ var exportInfo = exportMap.get(propName);
613
+ if (!exportInfo) {
614
+ continue;
615
+ }
616
+ if (!propertiesBySource.has(exportInfo.path)) {
617
+ propertiesBySource.set(exportInfo.path, []);
618
+ }
619
+ propertiesBySource.get(exportInfo.path).push(propName);
620
+ }
621
+ } catch (err) {
622
+ _iterator0.e(err);
623
+ } finally {
624
+ _iterator0.f();
625
+ }
626
+ return propertiesBySource;
627
+ }
628
+
629
+ /**
630
+ * Determine if we should report a barrel mock violation
631
+ */
632
+ function shouldReportBarrelMock(_ref8) {
633
+ var propertiesBySource = _ref8.propertiesBySource,
634
+ barrelFilePath = _ref8.barrelFilePath;
635
+ // Report if any mocked property is a re-export (comes from a different file than the barrel)
636
+ // This catches both:
637
+ // 1. Properties from multiple source files
638
+ // 2. Properties from a single source file that isn't the barrel itself
639
+ var _iterator1 = _createForOfIteratorHelper(propertiesBySource.keys()),
640
+ _step1;
641
+ try {
642
+ for (_iterator1.s(); !(_step1 = _iterator1.n()).done;) {
643
+ var sourcePath = _step1.value;
644
+ if (sourcePath !== barrelFilePath) {
645
+ return true;
646
+ }
647
+ }
648
+ } catch (err) {
649
+ _iterator1.e(err);
650
+ } finally {
651
+ _iterator1.f();
652
+ }
653
+ return false;
654
+ }
655
+
656
+ /**
657
+ * Generate auto-fix for auto-mock case (no mock implementation)
658
+ */
659
+ function generateAutoMockFix(_ref9) {
660
+ var exportMap = _ref9.exportMap,
661
+ basedir = _ref9.basedir,
662
+ importPath = _ref9.importPath,
663
+ quote = _ref9.quote,
664
+ workspaceRoot = _ref9.workspaceRoot,
665
+ fs = _ref9.fs;
666
+ // Group exports by source file, filtering out type-only source files
667
+ // Also track the ExportInfo for cross-package resolution
668
+ var sourceFilesWithInfo = new Map();
669
+ var _iterator10 = _createForOfIteratorHelper(exportMap),
670
+ _step10;
671
+ try {
672
+ for (_iterator10.s(); !(_step10 = _iterator10.n()).done;) {
673
+ var _step10$value = (0, _slicedToArray2.default)(_step10.value, 2),
674
+ info = _step10$value[1];
675
+ if (!info.isTypeOnly && !sourceFilesWithInfo.has(info.path)) {
676
+ sourceFilesWithInfo.set(info.path, info);
677
+ }
678
+ }
679
+ } catch (err) {
680
+ _iterator10.e(err);
681
+ } finally {
682
+ _iterator10.f();
683
+ }
684
+ var sourceFileArray = Array.from(sourceFilesWithInfo.entries());
685
+ return sourceFileArray.map(function (_ref0) {
686
+ var _ref1 = (0, _slicedToArray2.default)(_ref0, 2),
687
+ sourceFile = _ref1[0],
688
+ exportInfo = _ref1[1];
689
+ var mockPath = getImportPathForSourceFile({
690
+ sourceFilePath: sourceFile,
691
+ basedir: basedir,
692
+ originalImportPath: importPath,
693
+ exportInfo: exportInfo,
694
+ workspaceRoot: workspaceRoot,
695
+ fs: fs
696
+ });
697
+ return "jest.mock(".concat(quote).concat(mockPath).concat(quote, ")");
698
+ }).join(';\n');
699
+ }
700
+
701
+ /**
702
+ * Normalize a path for comparison (resolve to absolute path)
703
+ */
704
+ function normalizePathForComparison(_ref10) {
705
+ var basedir = _ref10.basedir,
706
+ importPath = _ref10.importPath,
707
+ fs = _ref10.fs;
708
+ if (!(0, _fileSystem.isRelativeImport)(importPath)) {
709
+ // For non-relative imports, just return as-is for comparison
710
+ return importPath;
711
+ }
712
+ var resolved = (0, _fileSystem.resolveImportPath)({
713
+ basedir: basedir,
714
+ importPath: importPath,
715
+ fs: fs
716
+ });
717
+ return resolved || importPath;
718
+ }
719
+
720
+ /**
721
+ * Scan the entire file for all existing jest.mock calls
722
+ * Returns a map of normalized path -> { node, properties, hasRequireActual }
723
+ */
724
+ function findAllJestMocksInFile(_ref11) {
725
+ var context = _ref11.context,
726
+ basedir = _ref11.basedir,
727
+ fs = _ref11.fs;
728
+ var allMocks = new Map();
729
+ var sourceCode = context.getSourceCode();
730
+ var ast = sourceCode.ast;
731
+
732
+ // Use a visited set to prevent infinite recursion
733
+ var visited = new Set();
734
+
735
+ // Properties to skip to avoid circular references
736
+ var skipKeys = new Set(['parent', 'loc', 'range', 'tokens', 'comments']);
737
+ function visitNode(node) {
738
+ // Prevent revisiting nodes
739
+ if (visited.has(node)) {
740
+ return;
741
+ }
742
+ visited.add(node);
743
+ if (node.type === 'CallExpression' && (0, _jestUtils.isJestMockCall)(node)) {
744
+ var importPath = (0, _jestUtils.extractImportPath)(node);
745
+ if (importPath) {
746
+ var normalizedPath = normalizePathForComparison({
747
+ basedir: basedir,
748
+ importPath: importPath,
749
+ fs: fs
750
+ });
751
+ var mockImpl = node.arguments[1];
752
+ if (mockImpl) {
753
+ var mockObjectNode = extractMockImplementation(mockImpl);
754
+ var _extractMockPropertie = extractMockProperties({
755
+ sourceCode: sourceCode,
756
+ mockObjectNode: mockObjectNode
757
+ }),
758
+ properties = _extractMockPropertie.properties,
759
+ hasRequireActual = _extractMockPropertie.hasRequireActual;
760
+ allMocks.set(normalizedPath, {
761
+ node: node,
762
+ importPath: importPath,
763
+ properties: properties,
764
+ hasRequireActual: hasRequireActual
765
+ });
766
+ }
767
+ }
768
+ }
769
+
770
+ // Recursively visit child nodes
771
+ for (var key in node) {
772
+ if (skipKeys.has(key)) {
773
+ continue;
774
+ }
775
+ var value = node[key];
776
+ if (value && (0, _typeof2.default)(value) === 'object') {
777
+ if (Array.isArray(value)) {
778
+ value.forEach(function (child) {
779
+ if (child && (0, _typeof2.default)(child) === 'object' && 'type' in child) {
780
+ visitNode(child);
781
+ }
782
+ });
783
+ } else if ('type' in value) {
784
+ visitNode(value);
785
+ }
786
+ }
787
+ }
788
+ }
789
+ visitNode(ast);
790
+ return allMocks;
791
+ }
792
+
793
+ /**
794
+ * Merge mock properties from multiple sources for the same file
795
+ */
796
+ function mergeMockProperties(_ref12) {
797
+ var existingProperties = _ref12.existingProperties,
798
+ newProperties = _ref12.newProperties;
799
+ var merged = new Map(existingProperties);
800
+ var _iterator11 = _createForOfIteratorHelper(newProperties),
801
+ _step11;
802
+ try {
803
+ for (_iterator11.s(); !(_step11 = _iterator11.n()).done;) {
804
+ var _step11$value = (0, _slicedToArray2.default)(_step11.value, 2),
805
+ key = _step11$value[0],
806
+ value = _step11$value[1];
807
+ merged.set(key, value);
808
+ }
809
+ } catch (err) {
810
+ _iterator11.e(err);
811
+ } finally {
812
+ _iterator11.f();
813
+ }
814
+ return merged;
815
+ }
816
+
817
+ /**
818
+ * Generate mock call text for a specific file with given properties
819
+ */
820
+ function generateMockCallText(_ref13) {
821
+ var relativePath = _ref13.relativePath,
822
+ properties = _ref13.properties,
823
+ hasRequireActual = _ref13.hasRequireActual,
824
+ quote = _ref13.quote,
825
+ exportMap = _ref13.exportMap,
826
+ sourceFile = _ref13.sourceFile,
827
+ preamble = _ref13.preamble,
828
+ originalImportPath = _ref13.originalImportPath;
829
+ var propNames = Array.from(properties.keys());
830
+
831
+ // Separate props by whether they're from default exports
832
+ var defaultExportProps = [];
833
+ var namedExportProps = [];
834
+ var _loop = function _loop() {
835
+ var prop = _propNames[_i2];
836
+ var exportInfo = Array.from(exportMap.entries()).find(function (_ref14) {
837
+ var _ref15 = (0, _slicedToArray2.default)(_ref14, 2),
838
+ exportName = _ref15[0],
839
+ info = _ref15[1];
840
+ return exportName === prop && info.path === sourceFile;
841
+ });
842
+ if (exportInfo && exportInfo[1].isDefaultExport) {
843
+ defaultExportProps.push(prop);
844
+ } else {
845
+ namedExportProps.push(prop);
846
+ }
847
+ };
848
+ for (var _i2 = 0, _propNames = propNames; _i2 < _propNames.length; _i2++) {
849
+ _loop();
850
+ }
851
+
852
+ // Collect all property texts for filtering the preamble
853
+ var allPropertyTexts = [];
854
+ for (var _i3 = 0, _namedExportProps = namedExportProps; _i3 < _namedExportProps.length; _i3++) {
855
+ var _properties$get;
856
+ var prop = _namedExportProps[_i3];
857
+ var propText = (_properties$get = properties.get(prop)) === null || _properties$get === void 0 ? void 0 : _properties$get.text;
858
+ if (propText) {
859
+ allPropertyTexts.push(propText);
860
+ }
861
+ }
862
+ for (var _i4 = 0, _defaultExportProps = defaultExportProps; _i4 < _defaultExportProps.length; _i4++) {
863
+ var _properties$get2;
864
+ var _prop = _defaultExportProps[_i4];
865
+ var _propText = (_properties$get2 = properties.get(_prop)) === null || _properties$get2 === void 0 ? void 0 : _properties$get2.valueText;
866
+ if (_propText) {
867
+ allPropertyTexts.push(_propText);
868
+ }
869
+ }
870
+
871
+ // Filter preamble to only include statements used by this mock's properties
872
+ var filteredPreamble = preamble ? filterPreambleForProperties(preamble, allPropertyTexts) : undefined;
873
+
874
+ // If we have a preamble, we need to use block body syntax with return statement
875
+ if (filteredPreamble !== null && filteredPreamble !== void 0 && filteredPreamble.hasPreamble) {
876
+ // Rewrite any jest.requireActual paths in the preamble
877
+ var preambleText = filteredPreamble.text;
878
+ if (originalImportPath) {
879
+ preambleText = rewriteRequireActualPaths({
880
+ text: preambleText,
881
+ originalPath: originalImportPath,
882
+ newPath: relativePath,
883
+ quote: quote
884
+ });
885
+ }
886
+
887
+ // Rewrite any jest.requireActual paths in property values
888
+ var rewrittenMockObjectProps = namedExportProps.map(function (p) {
889
+ var _properties$get3;
890
+ var propText = (_properties$get3 = properties.get(p)) === null || _properties$get3 === void 0 ? void 0 : _properties$get3.text;
891
+ if (propText && originalImportPath) {
892
+ propText = rewriteRequireActualPaths({
893
+ text: propText,
894
+ originalPath: originalImportPath,
895
+ newPath: relativePath,
896
+ quote: quote
897
+ });
898
+ }
899
+ return propText;
900
+ }).filter(function (p) {
901
+ return !!p;
902
+ });
903
+ var mockContentLines = [];
904
+ if (hasRequireActual) {
905
+ mockContentLines.push("...jest.requireActual(".concat(quote).concat(relativePath).concat(quote, ")"));
906
+ }
907
+ mockContentLines.push.apply(mockContentLines, (0, _toConsumableArray2.default)(rewrittenMockObjectProps));
908
+ var formattedContent = mockContentLines.map(function (line) {
909
+ return "\t\t".concat(line, ",");
910
+ }).join('\n');
911
+ return "jest.mock(".concat(quote).concat(relativePath).concat(quote, ", () => {\n\t").concat(preambleText, "\n\treturn {\n").concat(formattedContent, "\n\t};\n})");
912
+ }
913
+
914
+ // Generate the mock (original logic for simple cases without preamble)
915
+ var mockCall;
916
+ if (defaultExportProps.length > 0 && namedExportProps.length === 0) {
917
+ // All props are from default export
918
+ if (defaultExportProps.length === 1) {
919
+ var _properties$get4;
920
+ // Single default export - use __esModule pattern
921
+ var mockText = ((_properties$get4 = properties.get(defaultExportProps[0])) === null || _properties$get4 === void 0 ? void 0 : _properties$get4.valueText) || '';
922
+ mockCall = "jest.mock(".concat(quote).concat(relativePath).concat(quote, ", () => ({\n\t__esModule: true,\n\tdefault: ").concat(mockText, "\n}))");
923
+ } else {
924
+ // Multiple props from same default - shouldn't happen, but handle it
925
+ var mockTexts = defaultExportProps.map(function (p) {
926
+ var _properties$get5;
927
+ return (_properties$get5 = properties.get(p)) === null || _properties$get5 === void 0 ? void 0 : _properties$get5.text;
928
+ }).join(',\n\t');
929
+ mockCall = "jest.mock(".concat(quote).concat(relativePath).concat(quote, ", () => ({\n\t").concat(mockTexts, "\n}))");
930
+ }
931
+ } else if (defaultExportProps.length === 0 && namedExportProps.length > 0) {
932
+ // All props are named exports
933
+ var mockObjectProps = namedExportProps.map(function (p) {
934
+ var _properties$get6;
935
+ return (_properties$get6 = properties.get(p)) === null || _properties$get6 === void 0 ? void 0 : _properties$get6.text;
936
+ }).filter(function (p) {
937
+ return !!p;
938
+ });
939
+ var _mockContentLines = [];
940
+ if (hasRequireActual) {
941
+ _mockContentLines.push("...jest.requireActual(".concat(quote).concat(relativePath).concat(quote, ")"));
942
+ }
943
+ _mockContentLines.push.apply(_mockContentLines, (0, _toConsumableArray2.default)(mockObjectProps));
944
+ if (_mockContentLines.length === 1 && _mockContentLines[0].length < 60) {
945
+ mockCall = "jest.mock(".concat(quote).concat(relativePath).concat(quote, ", () => ({ ").concat(_mockContentLines[0], " }))");
946
+ } else {
947
+ var _formattedContent = _mockContentLines.map(function (line) {
948
+ return "\t".concat(line, ",");
949
+ }).join('\n');
950
+ mockCall = "jest.mock(".concat(quote).concat(relativePath).concat(quote, ", () => ({\n").concat(_formattedContent, "\n}))");
951
+ }
952
+ } else {
953
+ // Mixed: has both default and named exports
954
+ var defaultMock = defaultExportProps.map(function (p) {
955
+ var _properties$get7;
956
+ return (_properties$get7 = properties.get(p)) === null || _properties$get7 === void 0 ? void 0 : _properties$get7.valueText;
957
+ }).join(', ');
958
+ var namedMocks = namedExportProps.map(function (p) {
959
+ var _properties$get8;
960
+ return (_properties$get8 = properties.get(p)) === null || _properties$get8 === void 0 ? void 0 : _properties$get8.text;
961
+ }).filter(function (p) {
962
+ return !!p;
963
+ });
964
+ var _mockContentLines2 = ["__esModule: true", "default: ".concat(defaultMock)].concat((0, _toConsumableArray2.default)(namedMocks));
965
+ if (hasRequireActual) {
966
+ _mockContentLines2.unshift("...jest.requireActual(".concat(quote).concat(relativePath).concat(quote, ")"));
967
+ }
968
+ var _formattedContent2 = _mockContentLines2.map(function (line) {
969
+ return "\t".concat(line, ",");
970
+ }).join('\n');
971
+ mockCall = "jest.mock(".concat(quote).concat(relativePath).concat(quote, ", () => ({\n").concat(_formattedContent2, "\n}))");
972
+ }
973
+ return mockCall;
974
+ }
975
+
976
+ /**
977
+ * Generate auto-fix for mock with implementation
978
+ */
979
+ function generateMockImplementationFix(_ref16) {
980
+ var propertiesBySource = _ref16.propertiesBySource,
981
+ mockProperties = _ref16.mockProperties,
982
+ hasRequireActual = _ref16.hasRequireActual,
983
+ basedir = _ref16.basedir,
984
+ importPath = _ref16.importPath,
985
+ quote = _ref16.quote,
986
+ exportMap = _ref16.exportMap,
987
+ context = _ref16.context,
988
+ currentNode = _ref16.currentNode,
989
+ preamble = _ref16.preamble,
990
+ workspaceRoot = _ref16.workspaceRoot,
991
+ fs = _ref16.fs;
992
+ var sourceFilesToMock = Array.from(propertiesBySource.entries());
993
+
994
+ // Find all existing jest.mock calls in the file
995
+ var allExistingMocks = findAllJestMocksInFile({
996
+ context: context,
997
+ basedir: basedir,
998
+ fs: fs
999
+ });
1000
+
1001
+ // Track which nodes we need to remove and what mock calls to generate
1002
+ var nodesToRemove = new Set();
1003
+ var mergedMocks = new Map();
1004
+
1005
+ // Always remove the current barrel mock node
1006
+ nodesToRemove.add(currentNode);
1007
+
1008
+ // Process each source file we're creating mocks for
1009
+ var _loop2 = function _loop2() {
1010
+ var _sourceFilesToMock$_i = (0, _slicedToArray2.default)(_sourceFilesToMock[_i5], 2),
1011
+ sourceFile = _sourceFilesToMock$_i[0],
1012
+ props = _sourceFilesToMock$_i[1];
1013
+ // Find the ExportInfo for this source file to get cross-package info
1014
+ var exportInfoForSource = Array.from(exportMap.values()).find(function (info) {
1015
+ return info.path === sourceFile;
1016
+ });
1017
+ var mockPath = getImportPathForSourceFile({
1018
+ sourceFilePath: sourceFile,
1019
+ basedir: basedir,
1020
+ originalImportPath: importPath,
1021
+ exportInfo: exportInfoForSource !== null && exportInfoForSource !== void 0 ? exportInfoForSource : null,
1022
+ workspaceRoot: workspaceRoot,
1023
+ fs: fs
1024
+ });
1025
+ var normalizedPath = normalizePathForComparison({
1026
+ basedir: basedir,
1027
+ importPath: mockPath,
1028
+ fs: fs
1029
+ });
1030
+
1031
+ // Get properties for this source file from the barrel mock
1032
+ var newProperties = new Map();
1033
+ var _iterator12 = _createForOfIteratorHelper(props),
1034
+ _step12;
1035
+ try {
1036
+ for (_iterator12.s(); !(_step12 = _iterator12.n()).done;) {
1037
+ var prop = _step12.value;
1038
+ var propInfo = mockProperties.get(prop);
1039
+ if (propInfo) {
1040
+ newProperties.set(prop, propInfo);
1041
+ }
1042
+ }
1043
+
1044
+ // Check if there's already a mock for this path
1045
+ } catch (err) {
1046
+ _iterator12.e(err);
1047
+ } finally {
1048
+ _iterator12.f();
1049
+ }
1050
+ var existingMock = allExistingMocks.get(normalizedPath);
1051
+ if (existingMock && existingMock.node !== currentNode) {
1052
+ // Merge properties from existing mock with new properties
1053
+ var mergedProperties = mergeMockProperties({
1054
+ existingProperties: existingMock.properties,
1055
+ newProperties: newProperties
1056
+ });
1057
+ mergedMocks.set(normalizedPath, {
1058
+ mockPath: mockPath,
1059
+ properties: mergedProperties,
1060
+ hasRequireActual: existingMock.hasRequireActual || hasRequireActual
1061
+ });
1062
+ // Mark the existing mock node for removal
1063
+ nodesToRemove.add(existingMock.node);
1064
+ } else {
1065
+ // No existing mock, just use the new properties
1066
+ // For newly created mocks from barrel file splits, always include jest.requireActual.
1067
+ // This ensures that any properties not explicitly mocked will still be included from the original module.
1068
+ mergedMocks.set(normalizedPath, {
1069
+ mockPath: mockPath,
1070
+ properties: newProperties,
1071
+ hasRequireActual: true
1072
+ });
1073
+ }
1074
+ };
1075
+ for (var _i5 = 0, _sourceFilesToMock = sourceFilesToMock; _i5 < _sourceFilesToMock.length; _i5++) {
1076
+ _loop2();
1077
+ }
1078
+
1079
+ // Generate mock calls for all merged mocks
1080
+ var replacementParts = [];
1081
+ var _iterator13 = _createForOfIteratorHelper(mergedMocks),
1082
+ _step13;
1083
+ try {
1084
+ for (_iterator13.s(); !(_step13 = _iterator13.n()).done;) {
1085
+ var _step13$value = (0, _slicedToArray2.default)(_step13.value, 2),
1086
+ mockInfo = _step13$value[1];
1087
+ // Find the source file for this mock path (may be relative or cross-package)
1088
+ // For cross-package paths (starting with @), we don't need to resolve
1089
+ var isCrossPackagePath = mockInfo.mockPath.startsWith('@');
1090
+ var absolutePath = isCrossPackagePath ? null : (0, _fileSystem.resolveImportPath)({
1091
+ basedir: basedir,
1092
+ importPath: mockInfo.mockPath,
1093
+ fs: fs
1094
+ });
1095
+ if (!isCrossPackagePath && !absolutePath) {
1096
+ continue;
1097
+ }
1098
+ var mockCall = generateMockCallText({
1099
+ relativePath: mockInfo.mockPath,
1100
+ properties: mockInfo.properties,
1101
+ hasRequireActual: mockInfo.hasRequireActual,
1102
+ quote: quote,
1103
+ exportMap: exportMap,
1104
+ sourceFile: absolutePath !== null && absolutePath !== void 0 ? absolutePath : mockInfo.mockPath,
1105
+ preamble: preamble,
1106
+ originalImportPath: importPath
1107
+ });
1108
+ replacementParts.push(mockCall);
1109
+ }
1110
+ } catch (err) {
1111
+ _iterator13.e(err);
1112
+ } finally {
1113
+ _iterator13.f();
1114
+ }
1115
+ var replacementText = replacementParts.join(';\n');
1116
+
1117
+ // Build a map of symbol name -> new mock path for jest.requireMock() rewriting
1118
+ var symbolToNewMockPath = new Map();
1119
+ var _iterator14 = _createForOfIteratorHelper(mergedMocks),
1120
+ _step14;
1121
+ try {
1122
+ for (_iterator14.s(); !(_step14 = _iterator14.n()).done;) {
1123
+ var _step14$value = (0, _slicedToArray2.default)(_step14.value, 2),
1124
+ _mockInfo = _step14$value[1];
1125
+ var _iterator16 = _createForOfIteratorHelper(_mockInfo.properties.keys()),
1126
+ _step16;
1127
+ try {
1128
+ for (_iterator16.s(); !(_step16 = _iterator16.n()).done;) {
1129
+ var propName = _step16.value;
1130
+ symbolToNewMockPath.set(propName, _mockInfo.mockPath);
1131
+ }
1132
+ } catch (err) {
1133
+ _iterator16.e(err);
1134
+ } finally {
1135
+ _iterator16.f();
1136
+ }
1137
+ }
1138
+
1139
+ // Create fixes: remove all nodes except the first, replace the first with merged mocks
1140
+ } catch (err) {
1141
+ _iterator14.e(err);
1142
+ } finally {
1143
+ _iterator14.f();
1144
+ }
1145
+ var fixes = [];
1146
+ var sortedNodesToRemove = Array.from(nodesToRemove).sort(function (a, b) {
1147
+ var _a$range$, _a$range, _b$range$, _b$range;
1148
+ return ((_a$range$ = (_a$range = a.range) === null || _a$range === void 0 ? void 0 : _a$range[0]) !== null && _a$range$ !== void 0 ? _a$range$ : 0) - ((_b$range$ = (_b$range = b.range) === null || _b$range === void 0 ? void 0 : _b$range[0]) !== null && _b$range$ !== void 0 ? _b$range$ : 0);
1149
+ });
1150
+ if (sortedNodesToRemove.length > 0) {
1151
+ // Replace the first node with all the merged mocks
1152
+ var firstNode = sortedNodesToRemove[0];
1153
+ fixes.push({
1154
+ range: firstNode.range,
1155
+ text: replacementText
1156
+ });
1157
+
1158
+ // Remove all other nodes (subsequent duplicates)
1159
+ for (var i = 1; i < sortedNodesToRemove.length; i++) {
1160
+ var nodeToRemove = sortedNodesToRemove[i];
1161
+ // Find the statement that contains this node to remove the entire line
1162
+ var sourceCode = context.getSourceCode();
1163
+ var tokenAfter = sourceCode.getTokenAfter(nodeToRemove);
1164
+
1165
+ // Try to remove the entire statement including semicolon and newline
1166
+ var startPos = nodeToRemove.range[0];
1167
+ var endPos = nodeToRemove.range[1];
1168
+
1169
+ // Include trailing semicolon if present
1170
+ if (tokenAfter && tokenAfter.type === 'Punctuator' && tokenAfter.value === ';') {
1171
+ endPos = tokenAfter.range[1];
1172
+ }
1173
+
1174
+ // Include trailing/leading whitespace and newlines
1175
+ var text = sourceCode.getText();
1176
+ while (endPos < text.length && /[\s\n]/.test(text[endPos])) {
1177
+ endPos++;
1178
+ }
1179
+ fixes.push({
1180
+ range: [startPos, endPos],
1181
+ text: ''
1182
+ });
1183
+ }
1184
+ }
1185
+
1186
+ // Fix jest.requireMock() calls that reference the old barrel path.
1187
+ // When we split a jest.mock('./barrel') into jest.mock('./specific-file'),
1188
+ // any jest.requireMock('./barrel') calls also need to be updated.
1189
+ var ast = context.getSourceCode().ast;
1190
+ var normalizedTarget = normalizePathForComparison({
1191
+ basedir: basedir,
1192
+ importPath: importPath,
1193
+ fs: fs
1194
+ });
1195
+ var requireMockCalls = (0, _jestUtils.findJestRequireMockCalls)({
1196
+ ast: ast,
1197
+ matchPath: function matchPath(candidatePath) {
1198
+ return normalizePathForComparison({
1199
+ basedir: basedir,
1200
+ importPath: candidatePath,
1201
+ fs: fs
1202
+ }) === normalizedTarget;
1203
+ }
1204
+ });
1205
+ var _iterator15 = _createForOfIteratorHelper(requireMockCalls),
1206
+ _step15;
1207
+ try {
1208
+ for (_iterator15.s(); !(_step15 = _iterator15.n()).done;) {
1209
+ var requireMockNode = _step15.value;
1210
+ var requireMockArg = requireMockNode.arguments[0];
1211
+ if (!requireMockArg) {
1212
+ continue;
1213
+ }
1214
+ var newPath = (0, _jestUtils.resolveNewPathForRequireMock)({
1215
+ requireMockNode: requireMockNode,
1216
+ symbolToNewPath: symbolToNewMockPath
1217
+ });
1218
+ if (newPath) {
1219
+ fixes.push({
1220
+ range: requireMockArg.range,
1221
+ text: "".concat(quote).concat(newPath).concat(quote)
1222
+ });
1223
+ }
1224
+ }
1225
+ } catch (err) {
1226
+ _iterator15.e(err);
1227
+ } finally {
1228
+ _iterator15.f();
1229
+ }
1230
+ return fixes;
1231
+ }
1232
+
1233
+ /**
1234
+ * Metadata for the ESLint rule
1235
+ */
1236
+ var ruleMeta = {
1237
+ type: 'problem',
1238
+ docs: {
1239
+ description: 'Warn when jest.mock is used on a relative import path from a barrel file, and provide an auto-fix to split mocks by source file.',
1240
+ category: 'Best Practices',
1241
+ recommended: false
1242
+ },
1243
+ fixable: 'code',
1244
+ messages: {
1245
+ barrelMock: "jest.mock('{{path}}') is mocking a barrel file. This should be split into separate mocks for each source file to improve performance. Use auto-fix to resolve."
1246
+ }
1247
+ };
1248
+
1249
+ /**
1250
+ * Factory function to create the ESLint rule with a given file system.
1251
+ * This enables testing with mock file systems.
1252
+ */
1253
+ function createRule(fs) {
1254
+ return {
1255
+ meta: ruleMeta,
1256
+ create: function create(context) {
1257
+ return {
1258
+ CallExpression: function CallExpression(rawNode) {
1259
+ var node = rawNode;
1260
+
1261
+ // Step 1: Validate this is a jest.mock call
1262
+ if (!(0, _jestUtils.isJestMockCall)(node)) {
1263
+ return;
1264
+ }
1265
+
1266
+ // Step 2: Extract the import path
1267
+ var importPath = (0, _jestUtils.extractImportPath)(node);
1268
+ if (!importPath) {
1269
+ return;
1270
+ }
1271
+
1272
+ // Step 3: Validate and resolve barrel file
1273
+ var basedir = (0, _path.dirname)(context.filename);
1274
+ var workspaceRoot = (0, _fileSystem.findWorkspaceRoot)({
1275
+ startPath: basedir,
1276
+ fs: fs
1277
+ });
1278
+ var barrelInfo = validateAndResolveBarrelFile({
1279
+ importPath: importPath,
1280
+ basedir: basedir,
1281
+ workspaceRoot: workspaceRoot,
1282
+ fs: fs
1283
+ });
1284
+ if (!barrelInfo) {
1285
+ return;
1286
+ }
1287
+ var exportMap = barrelInfo.exportMap,
1288
+ barrelFilePath = barrelInfo.resolvedPath;
1289
+ var sourceCode = context.getSourceCode();
1290
+ var firstArg = node.arguments[0];
1291
+
1292
+ // Step 4: Handle auto-mock case (no mock implementation)
1293
+ var mockImpl = node.arguments[1];
1294
+ if (!mockImpl) {
1295
+ // Group exports by source file, filtering out type-only source files
1296
+ var sourceFilesWithNonTypeExports = new Set();
1297
+ var _iterator17 = _createForOfIteratorHelper(exportMap),
1298
+ _step17;
1299
+ try {
1300
+ for (_iterator17.s(); !(_step17 = _iterator17.n()).done;) {
1301
+ var _step17$value = (0, _slicedToArray2.default)(_step17.value, 2),
1302
+ info = _step17$value[1];
1303
+ if (!info.isTypeOnly) {
1304
+ sourceFilesWithNonTypeExports.add(info.path);
1305
+ }
1306
+ }
1307
+ } catch (err) {
1308
+ _iterator17.e(err);
1309
+ } finally {
1310
+ _iterator17.f();
1311
+ }
1312
+ if (sourceFilesWithNonTypeExports.size === 0) {
1313
+ return;
1314
+ }
1315
+ context.report({
1316
+ node: node,
1317
+ messageId: 'barrelMock',
1318
+ data: {
1319
+ path: importPath
1320
+ },
1321
+ fix: function fix(fixer) {
1322
+ var quote = sourceCode.getText(firstArg)[0];
1323
+ var replacement = generateAutoMockFix({
1324
+ exportMap: exportMap,
1325
+ basedir: basedir,
1326
+ importPath: importPath,
1327
+ quote: quote,
1328
+ workspaceRoot: workspaceRoot,
1329
+ fs: fs
1330
+ });
1331
+ return fixer.replaceText(node, replacement);
1332
+ }
1333
+ });
1334
+ return;
1335
+ }
1336
+
1337
+ // Step 5: Extract mock implementation and properties
1338
+ var mockObjectNode = extractMockImplementation(mockImpl);
1339
+ var _extractMockPropertie2 = extractMockProperties({
1340
+ sourceCode: sourceCode,
1341
+ mockObjectNode: mockObjectNode
1342
+ }),
1343
+ mockProperties = _extractMockPropertie2.properties,
1344
+ hasRequireActual = _extractMockPropertie2.hasRequireActual;
1345
+
1346
+ // Extract preamble (variable declarations, etc.) from the mock factory
1347
+ var preamble = extractMockFactoryPreamble({
1348
+ mockImpl: mockImpl,
1349
+ sourceCode: sourceCode
1350
+ });
1351
+ if (mockProperties.size === 0) {
1352
+ return;
1353
+ }
1354
+
1355
+ // Step 6: Group properties by their source files
1356
+ var propertiesBySource = groupPropertiesBySource({
1357
+ mockProperties: mockProperties,
1358
+ exportMap: exportMap
1359
+ });
1360
+
1361
+ // Step 7: Determine if we should report
1362
+ if (!shouldReportBarrelMock({
1363
+ propertiesBySource: propertiesBySource,
1364
+ barrelFilePath: barrelFilePath
1365
+ })) {
1366
+ return;
1367
+ }
1368
+
1369
+ // Step 8: Report with auto-fix
1370
+ context.report({
1371
+ node: node,
1372
+ messageId: 'barrelMock',
1373
+ data: {
1374
+ path: importPath
1375
+ },
1376
+ fix: function fix(_fixer) {
1377
+ var quote = sourceCode.getText(firstArg)[0];
1378
+ var fixes = generateMockImplementationFix({
1379
+ propertiesBySource: propertiesBySource,
1380
+ mockProperties: mockProperties,
1381
+ hasRequireActual: hasRequireActual,
1382
+ basedir: basedir,
1383
+ importPath: importPath,
1384
+ quote: quote,
1385
+ exportMap: exportMap,
1386
+ context: context,
1387
+ currentNode: node,
1388
+ preamble: preamble,
1389
+ workspaceRoot: workspaceRoot,
1390
+ fs: fs
1391
+ });
1392
+ return fixes;
1393
+ }
1394
+ });
1395
+ }
1396
+ };
1397
+ }
1398
+ };
1399
+ }
1400
+ var rule = createRule(_types.realFileSystem);
1401
+ var _default = exports.default = rule;