@atlaskit/eslint-plugin-platform 2.7.2 → 2.9.0

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