@atlaskit/eslint-plugin-platform 2.7.2 → 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.
- package/CHANGELOG.md +7 -0
- package/dist/cjs/index.js +14 -3
- package/dist/cjs/rules/feature-gating/valid-gate-name/index.js +60 -0
- package/dist/cjs/rules/import/no-barrel-entry-imports/index.js +871 -0
- package/dist/cjs/rules/import/no-barrel-entry-jest-mock/index.js +1384 -0
- package/dist/cjs/rules/import/no-conversation-assistant-barrel-imports/index.js +43 -0
- package/dist/cjs/rules/import/no-jest-mock-barrel-files/index.js +1401 -0
- package/dist/cjs/rules/import/no-relative-barrel-file-imports/index.js +777 -0
- package/dist/cjs/rules/import/shared/barrel-parsing.js +511 -0
- package/dist/cjs/rules/import/shared/file-system.js +186 -0
- package/dist/cjs/rules/import/shared/jest-utils.js +191 -0
- package/dist/cjs/rules/import/shared/package-registry.js +263 -0
- package/dist/cjs/rules/import/shared/package-resolution.js +185 -0
- package/dist/cjs/rules/import/shared/perf.js +89 -0
- package/dist/cjs/rules/import/shared/types.js +67 -0
- package/dist/es2019/index.js +14 -3
- package/dist/es2019/rules/feature-gating/valid-gate-name/index.js +52 -0
- package/dist/es2019/rules/import/no-barrel-entry-imports/index.js +801 -0
- package/dist/es2019/rules/import/no-barrel-entry-jest-mock/index.js +1113 -0
- package/dist/es2019/rules/import/no-conversation-assistant-barrel-imports/index.js +37 -0
- package/dist/es2019/rules/import/no-jest-mock-barrel-files/index.js +1179 -0
- package/dist/es2019/rules/import/no-relative-barrel-file-imports/index.js +738 -0
- package/dist/es2019/rules/import/shared/barrel-parsing.js +433 -0
- package/dist/es2019/rules/import/shared/file-system.js +174 -0
- package/dist/es2019/rules/import/shared/jest-utils.js +159 -0
- package/dist/es2019/rules/import/shared/package-registry.js +240 -0
- package/dist/es2019/rules/import/shared/package-resolution.js +161 -0
- package/dist/es2019/rules/import/shared/perf.js +83 -0
- package/dist/es2019/rules/import/shared/types.js +57 -0
- package/dist/esm/index.js +14 -3
- package/dist/esm/rules/feature-gating/valid-gate-name/index.js +53 -0
- package/dist/esm/rules/import/no-barrel-entry-imports/index.js +864 -0
- package/dist/esm/rules/import/no-barrel-entry-jest-mock/index.js +1375 -0
- package/dist/esm/rules/import/no-conversation-assistant-barrel-imports/index.js +37 -0
- package/dist/esm/rules/import/no-jest-mock-barrel-files/index.js +1391 -0
- package/dist/esm/rules/import/no-relative-barrel-file-imports/index.js +770 -0
- package/dist/esm/rules/import/shared/barrel-parsing.js +500 -0
- package/dist/esm/rules/import/shared/file-system.js +176 -0
- package/dist/esm/rules/import/shared/jest-utils.js +179 -0
- package/dist/esm/rules/import/shared/package-registry.js +256 -0
- package/dist/esm/rules/import/shared/package-resolution.js +175 -0
- package/dist/esm/rules/import/shared/perf.js +80 -0
- package/dist/esm/rules/import/shared/types.js +61 -0
- package/dist/types/index.d.ts +16 -2
- package/dist/types/rules/feature-gating/valid-gate-name/index.d.ts +3 -0
- package/dist/types/rules/import/no-barrel-entry-imports/index.d.ts +9 -0
- package/dist/types/rules/import/no-barrel-entry-jest-mock/index.d.ts +9 -0
- package/dist/types/rules/import/no-conversation-assistant-barrel-imports/index.d.ts +3 -0
- package/dist/types/rules/import/no-jest-mock-barrel-files/index.d.ts +22 -0
- package/dist/types/rules/import/no-relative-barrel-file-imports/index.d.ts +5 -0
- package/dist/types/rules/import/shared/barrel-parsing.d.ts +30 -0
- package/dist/types/rules/import/shared/file-system.d.ts +38 -0
- package/dist/types/rules/import/shared/jest-utils.d.ts +47 -0
- package/dist/types/rules/import/shared/package-registry.d.ts +26 -0
- package/dist/types/rules/import/shared/package-resolution.d.ts +38 -0
- package/dist/types/rules/import/shared/perf.d.ts +13 -0
- package/dist/types/rules/import/shared/types.d.ts +131 -0
- package/dist/types-ts4.5/index.d.ts +16 -2
- package/dist/types-ts4.5/rules/import/no-barrel-entry-imports/index.d.ts +9 -0
- package/dist/types-ts4.5/rules/import/no-barrel-entry-jest-mock/index.d.ts +9 -0
- package/dist/types-ts4.5/rules/import/no-jest-mock-barrel-files/index.d.ts +22 -0
- package/dist/types-ts4.5/rules/import/no-relative-barrel-file-imports/index.d.ts +5 -0
- package/dist/types-ts4.5/rules/import/shared/barrel-parsing.d.ts +30 -0
- package/dist/types-ts4.5/rules/import/shared/file-system.d.ts +38 -0
- package/dist/types-ts4.5/rules/import/shared/jest-utils.d.ts +47 -0
- package/dist/types-ts4.5/rules/import/shared/package-registry.d.ts +26 -0
- package/dist/types-ts4.5/rules/import/shared/package-resolution.d.ts +38 -0
- package/dist/types-ts4.5/rules/import/shared/perf.d.ts +13 -0
- package/dist/types-ts4.5/rules/import/shared/types.d.ts +131 -0
- package/package.json +4 -2
- package/dist/cjs/rules/ensure-native-and-af-exports-synced/index.js +0 -158
- package/dist/es2019/rules/ensure-native-and-af-exports-synced/index.js +0 -146
- package/dist/esm/rules/ensure-native-and-af-exports-synced/index.js +0 -151
- /package/dist/types-ts4.5/rules/{ensure-native-and-af-exports-synced → feature-gating/valid-gate-name}/index.d.ts +0 -0
- /package/dist/{types/rules/ensure-native-and-af-exports-synced → types-ts4.5/rules/import/no-conversation-assistant-barrel-imports}/index.d.ts +0 -0
|
@@ -0,0 +1,1384 @@
|
|
|
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
|
+
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
|
|
11
|
+
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
12
|
+
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
13
|
+
var _path = require("path");
|
|
14
|
+
var ts = _interopRequireWildcard(require("typescript"));
|
|
15
|
+
var _barrelParsing = require("../shared/barrel-parsing");
|
|
16
|
+
var _fileSystem = require("../shared/file-system");
|
|
17
|
+
var _jestUtils = require("../shared/jest-utils");
|
|
18
|
+
var _packageRegistry = require("../shared/package-registry");
|
|
19
|
+
var _packageResolution = require("../shared/package-resolution");
|
|
20
|
+
var _types = require("../shared/types");
|
|
21
|
+
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); }
|
|
22
|
+
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; } } }; }
|
|
23
|
+
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; } }
|
|
24
|
+
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; }
|
|
25
|
+
/**
|
|
26
|
+
* Options for the no-barrel-entry-jest-mock rule.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Result of tracing a symbol through barrel files to its source.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Grouped mock properties by their target export path.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Trace the re-export chain for a symbol from a barrel file.
|
|
39
|
+
* Returns an array of file paths representing the chain from the barrel to the source.
|
|
40
|
+
* For example: [barrel.ts, intermediate.ts, source.ts]
|
|
41
|
+
*/
|
|
42
|
+
function traceReExportChain(_ref) {
|
|
43
|
+
var barrelFilePath = _ref.barrelFilePath,
|
|
44
|
+
symbolName = _ref.symbolName,
|
|
45
|
+
fs = _ref.fs,
|
|
46
|
+
_ref$visited = _ref.visited,
|
|
47
|
+
visited = _ref$visited === void 0 ? new Set() : _ref$visited;
|
|
48
|
+
if (visited.has(barrelFilePath)) {
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
visited.add(barrelFilePath);
|
|
52
|
+
var content = (0, _fileSystem.readFileContent)({
|
|
53
|
+
filePath: barrelFilePath,
|
|
54
|
+
fs: fs
|
|
55
|
+
});
|
|
56
|
+
if (!content) {
|
|
57
|
+
return [barrelFilePath];
|
|
58
|
+
}
|
|
59
|
+
var sourceFile;
|
|
60
|
+
try {
|
|
61
|
+
sourceFile = ts.createSourceFile(barrelFilePath, content, ts.ScriptTarget.Latest, true);
|
|
62
|
+
} catch (_unused) {
|
|
63
|
+
return [barrelFilePath];
|
|
64
|
+
}
|
|
65
|
+
var barrelDir = (0, _path.dirname)(barrelFilePath);
|
|
66
|
+
var _iterator = _createForOfIteratorHelper(sourceFile.statements),
|
|
67
|
+
_step;
|
|
68
|
+
try {
|
|
69
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
70
|
+
var statement = _step.value;
|
|
71
|
+
if (!ts.isExportDeclaration(statement) || !statement.moduleSpecifier) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (!ts.isStringLiteral(statement.moduleSpecifier)) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
var modulePath = statement.moduleSpecifier.text;
|
|
78
|
+
if (!(0, _fileSystem.isRelativeImport)(modulePath)) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Check if this export statement includes our symbol
|
|
83
|
+
var includesSymbol = false;
|
|
84
|
+
if (statement.exportClause) {
|
|
85
|
+
if (ts.isNamedExports(statement.exportClause)) {
|
|
86
|
+
var _iterator2 = _createForOfIteratorHelper(statement.exportClause.elements),
|
|
87
|
+
_step2;
|
|
88
|
+
try {
|
|
89
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
90
|
+
var element = _step2.value;
|
|
91
|
+
var exportedName = element.name.text;
|
|
92
|
+
if (exportedName === symbolName) {
|
|
93
|
+
includesSymbol = true;
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
} catch (err) {
|
|
98
|
+
_iterator2.e(err);
|
|
99
|
+
} finally {
|
|
100
|
+
_iterator2.f();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
// Star export - might include the symbol
|
|
105
|
+
includesSymbol = true;
|
|
106
|
+
}
|
|
107
|
+
if (includesSymbol) {
|
|
108
|
+
var resolvedSource = (0, _fileSystem.resolveImportPath)({
|
|
109
|
+
basedir: barrelDir,
|
|
110
|
+
importPath: modulePath,
|
|
111
|
+
fs: fs
|
|
112
|
+
});
|
|
113
|
+
if (resolvedSource) {
|
|
114
|
+
// Recursively trace from the resolved source
|
|
115
|
+
var restOfChain = traceReExportChain({
|
|
116
|
+
barrelFilePath: resolvedSource,
|
|
117
|
+
symbolName: symbolName,
|
|
118
|
+
fs: fs,
|
|
119
|
+
visited: visited
|
|
120
|
+
});
|
|
121
|
+
return [barrelFilePath].concat((0, _toConsumableArray2.default)(restOfChain));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Symbol is defined in this file (not re-exported)
|
|
127
|
+
} catch (err) {
|
|
128
|
+
_iterator.e(err);
|
|
129
|
+
} finally {
|
|
130
|
+
_iterator.f();
|
|
131
|
+
}
|
|
132
|
+
return [barrelFilePath];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Find a package.json export that can provide a given symbol.
|
|
137
|
+
*
|
|
138
|
+
* This function traces the re-export chain from the current barrel to the symbol's source,
|
|
139
|
+
* and returns an export if its entry file is on that chain (i.e., it's an intermediate barrel
|
|
140
|
+
* that the main barrel imports from for this symbol).
|
|
141
|
+
*
|
|
142
|
+
* This prevents suggesting unrelated barrel files that happen to re-export the same symbol
|
|
143
|
+
* through a different path.
|
|
144
|
+
*/
|
|
145
|
+
function findExportForSymbol(_ref2) {
|
|
146
|
+
var symbolName = _ref2.symbolName,
|
|
147
|
+
symbolSourcePath = _ref2.symbolSourcePath,
|
|
148
|
+
exportsMap = _ref2.exportsMap,
|
|
149
|
+
currentExportPath = _ref2.currentExportPath,
|
|
150
|
+
fs = _ref2.fs;
|
|
151
|
+
var currentEntryFilePath = exportsMap.get(currentExportPath);
|
|
152
|
+
if (!currentEntryFilePath) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Trace the re-export chain from the current barrel to the source
|
|
157
|
+
var reExportChain = traceReExportChain({
|
|
158
|
+
barrelFilePath: currentEntryFilePath,
|
|
159
|
+
symbolName: symbolName,
|
|
160
|
+
fs: fs
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Convert chain to a Set for O(1) lookup
|
|
164
|
+
var chainSet = new Set(reExportChain);
|
|
165
|
+
|
|
166
|
+
// Check each package.json export entry (except the current one)
|
|
167
|
+
var _iterator3 = _createForOfIteratorHelper(exportsMap),
|
|
168
|
+
_step3;
|
|
169
|
+
try {
|
|
170
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
171
|
+
var _step3$value = (0, _slicedToArray2.default)(_step3.value, 2),
|
|
172
|
+
exportPath = _step3$value[0],
|
|
173
|
+
entryFilePath = _step3$value[1];
|
|
174
|
+
if (exportPath === currentExportPath) {
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Skip exports that resolve to the same file as the current export path
|
|
179
|
+
if (entryFilePath === currentEntryFilePath) {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Only return this export if its entry file is on the re-export chain
|
|
184
|
+
// (meaning it's an intermediate barrel the main barrel imports from for this symbol)
|
|
185
|
+
// or if it directly points to the source file
|
|
186
|
+
if (chainSet.has(entryFilePath) || entryFilePath === symbolSourcePath) {
|
|
187
|
+
// Verify the symbol is actually exported from this entry file
|
|
188
|
+
var entryExports = (0, _barrelParsing.parseBarrelExports)({
|
|
189
|
+
barrelFilePath: entryFilePath,
|
|
190
|
+
depth: 0,
|
|
191
|
+
fs: fs
|
|
192
|
+
});
|
|
193
|
+
if (entryExports.has(symbolName)) {
|
|
194
|
+
return exportPath;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
} catch (err) {
|
|
199
|
+
_iterator3.e(err);
|
|
200
|
+
} finally {
|
|
201
|
+
_iterator3.f();
|
|
202
|
+
}
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Preamble statement extracted from a mock factory function.
|
|
208
|
+
*/
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Collect all identifier names used in a node (recursively).
|
|
212
|
+
* Avoids circular references by skipping parent-related properties.
|
|
213
|
+
*/
|
|
214
|
+
function collectUsedIdentifiers(_ref3) {
|
|
215
|
+
var node = _ref3.node;
|
|
216
|
+
var identifiers = new Set();
|
|
217
|
+
var visited = new WeakSet();
|
|
218
|
+
|
|
219
|
+
// Properties to skip to avoid circular references
|
|
220
|
+
var skipProperties = new Set(['parent', 'tokens', 'comments', 'loc', 'range']);
|
|
221
|
+
function traverse(n) {
|
|
222
|
+
if (visited.has(n)) {
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
visited.add(n);
|
|
226
|
+
if (n.type === 'Identifier') {
|
|
227
|
+
identifiers.add(n.name);
|
|
228
|
+
}
|
|
229
|
+
for (var _i = 0, _Object$keys = Object.keys(n); _i < _Object$keys.length; _i++) {
|
|
230
|
+
var key = _Object$keys[_i];
|
|
231
|
+
if (skipProperties.has(key)) {
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
var child = n[key];
|
|
235
|
+
if (child && (0, _typeof2.default)(child) === 'object') {
|
|
236
|
+
if (Array.isArray(child)) {
|
|
237
|
+
var _iterator4 = _createForOfIteratorHelper(child),
|
|
238
|
+
_step4;
|
|
239
|
+
try {
|
|
240
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
241
|
+
var item = _step4.value;
|
|
242
|
+
if (item && (0, _typeof2.default)(item) === 'object' && 'type' in item) {
|
|
243
|
+
traverse(item);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
} catch (err) {
|
|
247
|
+
_iterator4.e(err);
|
|
248
|
+
} finally {
|
|
249
|
+
_iterator4.f();
|
|
250
|
+
}
|
|
251
|
+
} else if ('type' in child) {
|
|
252
|
+
traverse(child);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
traverse(node);
|
|
258
|
+
return identifiers;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Extract preamble statements (variable declarations) from a block body.
|
|
263
|
+
*/
|
|
264
|
+
function extractPreambleStatements(_ref4) {
|
|
265
|
+
var mockImpl = _ref4.mockImpl,
|
|
266
|
+
sourceCode = _ref4.sourceCode;
|
|
267
|
+
var preamble = [];
|
|
268
|
+
var body = null;
|
|
269
|
+
if (mockImpl.type === 'ArrowFunctionExpression' && mockImpl.body.type === 'BlockStatement') {
|
|
270
|
+
body = mockImpl.body.body;
|
|
271
|
+
} else if (mockImpl.type === 'FunctionExpression' && mockImpl.body.type === 'BlockStatement') {
|
|
272
|
+
body = mockImpl.body.body;
|
|
273
|
+
}
|
|
274
|
+
if (!body) {
|
|
275
|
+
return preamble;
|
|
276
|
+
}
|
|
277
|
+
var _iterator5 = _createForOfIteratorHelper(body),
|
|
278
|
+
_step5;
|
|
279
|
+
try {
|
|
280
|
+
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
|
|
281
|
+
var stmt = _step5.value;
|
|
282
|
+
if (stmt.type === 'ReturnStatement') {
|
|
283
|
+
break; // Stop at return
|
|
284
|
+
}
|
|
285
|
+
if (stmt.type === 'VariableDeclaration') {
|
|
286
|
+
var declaredNames = [];
|
|
287
|
+
var usedIdentifiers = new Set();
|
|
288
|
+
var _iterator6 = _createForOfIteratorHelper(stmt.declarations),
|
|
289
|
+
_step6;
|
|
290
|
+
try {
|
|
291
|
+
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
|
|
292
|
+
var decl = _step6.value;
|
|
293
|
+
if (decl.id.type === 'Identifier') {
|
|
294
|
+
declaredNames.push(decl.id.name);
|
|
295
|
+
}
|
|
296
|
+
if (decl.init) {
|
|
297
|
+
var used = collectUsedIdentifiers({
|
|
298
|
+
node: decl.init
|
|
299
|
+
});
|
|
300
|
+
var _iterator7 = _createForOfIteratorHelper(used),
|
|
301
|
+
_step7;
|
|
302
|
+
try {
|
|
303
|
+
for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
|
|
304
|
+
var id = _step7.value;
|
|
305
|
+
usedIdentifiers.add(id);
|
|
306
|
+
}
|
|
307
|
+
} catch (err) {
|
|
308
|
+
_iterator7.e(err);
|
|
309
|
+
} finally {
|
|
310
|
+
_iterator7.f();
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Remove declared names from used identifiers
|
|
316
|
+
} catch (err) {
|
|
317
|
+
_iterator6.e(err);
|
|
318
|
+
} finally {
|
|
319
|
+
_iterator6.f();
|
|
320
|
+
}
|
|
321
|
+
for (var _i2 = 0, _declaredNames = declaredNames; _i2 < _declaredNames.length; _i2++) {
|
|
322
|
+
var name = _declaredNames[_i2];
|
|
323
|
+
usedIdentifiers.delete(name);
|
|
324
|
+
}
|
|
325
|
+
preamble.push({
|
|
326
|
+
declaredNames: declaredNames,
|
|
327
|
+
text: sourceCode.getText(stmt),
|
|
328
|
+
usedIdentifiers: usedIdentifiers
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
} catch (err) {
|
|
333
|
+
_iterator5.e(err);
|
|
334
|
+
} finally {
|
|
335
|
+
_iterator5.f();
|
|
336
|
+
}
|
|
337
|
+
return preamble;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Determine which preamble statements are needed for a set of property texts.
|
|
342
|
+
* Returns the preamble statements in order, including any transitively needed ones.
|
|
343
|
+
*/
|
|
344
|
+
function getNeededPreamble(_ref5) {
|
|
345
|
+
var propertyTexts = _ref5.propertyTexts,
|
|
346
|
+
allPreamble = _ref5.allPreamble;
|
|
347
|
+
// Collect all identifiers used in the property texts
|
|
348
|
+
var neededIdentifiers = new Set();
|
|
349
|
+
var _iterator8 = _createForOfIteratorHelper(propertyTexts),
|
|
350
|
+
_step8;
|
|
351
|
+
try {
|
|
352
|
+
for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
|
|
353
|
+
var text = _step8.value;
|
|
354
|
+
// Simple regex to find identifiers in the text
|
|
355
|
+
// This is a basic approach; handles most common cases
|
|
356
|
+
var identifierPattern = /\b([a-zA-Z_$][a-zA-Z0-9_$]*)\b/g;
|
|
357
|
+
var match = void 0;
|
|
358
|
+
while ((match = identifierPattern.exec(text)) !== null) {
|
|
359
|
+
neededIdentifiers.add(match[1]);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Build dependency graph and find needed preamble
|
|
364
|
+
} catch (err) {
|
|
365
|
+
_iterator8.e(err);
|
|
366
|
+
} finally {
|
|
367
|
+
_iterator8.f();
|
|
368
|
+
}
|
|
369
|
+
var neededPreamble = [];
|
|
370
|
+
var includedNames = new Set();
|
|
371
|
+
var changed = true;
|
|
372
|
+
while (changed) {
|
|
373
|
+
changed = false;
|
|
374
|
+
var _iterator9 = _createForOfIteratorHelper(allPreamble),
|
|
375
|
+
_step9;
|
|
376
|
+
try {
|
|
377
|
+
for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) {
|
|
378
|
+
var stmt = _step9.value;
|
|
379
|
+
// Check if any declared name is needed
|
|
380
|
+
var isNeeded = stmt.declaredNames.some(function (name) {
|
|
381
|
+
return neededIdentifiers.has(name);
|
|
382
|
+
});
|
|
383
|
+
var alreadyIncluded = stmt.declaredNames.some(function (name) {
|
|
384
|
+
return includedNames.has(name);
|
|
385
|
+
});
|
|
386
|
+
if (isNeeded && !alreadyIncluded) {
|
|
387
|
+
neededPreamble.push(stmt);
|
|
388
|
+
var _iterator0 = _createForOfIteratorHelper(stmt.declaredNames),
|
|
389
|
+
_step0;
|
|
390
|
+
try {
|
|
391
|
+
for (_iterator0.s(); !(_step0 = _iterator0.n()).done;) {
|
|
392
|
+
var name = _step0.value;
|
|
393
|
+
includedNames.add(name);
|
|
394
|
+
}
|
|
395
|
+
// Add any identifiers this statement uses to needed set
|
|
396
|
+
} catch (err) {
|
|
397
|
+
_iterator0.e(err);
|
|
398
|
+
} finally {
|
|
399
|
+
_iterator0.f();
|
|
400
|
+
}
|
|
401
|
+
var _iterator1 = _createForOfIteratorHelper(stmt.usedIdentifiers),
|
|
402
|
+
_step1;
|
|
403
|
+
try {
|
|
404
|
+
for (_iterator1.s(); !(_step1 = _iterator1.n()).done;) {
|
|
405
|
+
var id = _step1.value;
|
|
406
|
+
if (!neededIdentifiers.has(id)) {
|
|
407
|
+
neededIdentifiers.add(id);
|
|
408
|
+
changed = true;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
} catch (err) {
|
|
412
|
+
_iterator1.e(err);
|
|
413
|
+
} finally {
|
|
414
|
+
_iterator1.f();
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
} catch (err) {
|
|
419
|
+
_iterator9.e(err);
|
|
420
|
+
} finally {
|
|
421
|
+
_iterator9.f();
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// Return in original order
|
|
426
|
+
return allPreamble.filter(function (stmt) {
|
|
427
|
+
return neededPreamble.includes(stmt);
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Extract mock object properties from jest.mock call
|
|
433
|
+
* Returns a map of property name -> { node, text } and whether there's a jest.requireActual spread
|
|
434
|
+
*/
|
|
435
|
+
function extractMockProperties(_ref6) {
|
|
436
|
+
var sourceCode = _ref6.sourceCode,
|
|
437
|
+
mockObjectNode = _ref6.mockObjectNode;
|
|
438
|
+
var properties = new Map();
|
|
439
|
+
var hasRequireActual = false;
|
|
440
|
+
if (mockObjectNode.type === 'ObjectExpression') {
|
|
441
|
+
var _iterator10 = _createForOfIteratorHelper(mockObjectNode.properties),
|
|
442
|
+
_step10;
|
|
443
|
+
try {
|
|
444
|
+
for (_iterator10.s(); !(_step10 = _iterator10.n()).done;) {
|
|
445
|
+
var prop = _step10.value;
|
|
446
|
+
if (prop.type === 'SpreadElement') {
|
|
447
|
+
if ((0, _jestUtils.isJestRequireActual)(prop.argument)) {
|
|
448
|
+
hasRequireActual = true;
|
|
449
|
+
}
|
|
450
|
+
} else if (prop.type === 'Property') {
|
|
451
|
+
var keyName = void 0;
|
|
452
|
+
if (prop.key.type === 'Identifier') {
|
|
453
|
+
keyName = prop.key.name;
|
|
454
|
+
} else if (prop.key.type === 'Literal') {
|
|
455
|
+
keyName = String(prop.key.value);
|
|
456
|
+
} else {
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
var propText = sourceCode.getText(prop);
|
|
460
|
+
properties.set(keyName, {
|
|
461
|
+
node: prop,
|
|
462
|
+
text: propText
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
} catch (err) {
|
|
467
|
+
_iterator10.e(err);
|
|
468
|
+
} finally {
|
|
469
|
+
_iterator10.f();
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
return {
|
|
473
|
+
properties: properties,
|
|
474
|
+
hasRequireActual: hasRequireActual
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Information about an existing jest.mock call in the file
|
|
480
|
+
*/
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Find all jest.mock calls in the current file
|
|
484
|
+
*/
|
|
485
|
+
function findAllJestMocksInFile(_ref7) {
|
|
486
|
+
var context = _ref7.context;
|
|
487
|
+
var allMocks = new Map();
|
|
488
|
+
var sourceCode = context.getSourceCode();
|
|
489
|
+
var ast = sourceCode.ast;
|
|
490
|
+
|
|
491
|
+
// Use a visited set to prevent infinite recursion
|
|
492
|
+
var visited = new WeakSet();
|
|
493
|
+
|
|
494
|
+
// Properties to skip to avoid circular references
|
|
495
|
+
var skipKeys = new Set(['parent', 'loc', 'range', 'tokens', 'comments']);
|
|
496
|
+
function visitNode(node) {
|
|
497
|
+
// Prevent revisiting nodes
|
|
498
|
+
if (visited.has(node)) {
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
visited.add(node);
|
|
502
|
+
if (node.type === 'CallExpression' && (0, _jestUtils.isJestMockCall)(node)) {
|
|
503
|
+
var importPath = (0, _jestUtils.extractImportPath)(node);
|
|
504
|
+
if (importPath) {
|
|
505
|
+
var mockImpl = node.arguments[1];
|
|
506
|
+
if (mockImpl) {
|
|
507
|
+
var mockObjectNode = extractMockImplementation({
|
|
508
|
+
mockImpl: mockImpl
|
|
509
|
+
});
|
|
510
|
+
var _extractMockPropertie = extractMockProperties({
|
|
511
|
+
sourceCode: sourceCode,
|
|
512
|
+
mockObjectNode: mockObjectNode
|
|
513
|
+
}),
|
|
514
|
+
properties = _extractMockPropertie.properties,
|
|
515
|
+
hasRequireActual = _extractMockPropertie.hasRequireActual;
|
|
516
|
+
allMocks.set(importPath, {
|
|
517
|
+
node: node,
|
|
518
|
+
importPath: importPath,
|
|
519
|
+
properties: properties,
|
|
520
|
+
hasRequireActual: hasRequireActual
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
// Recursively visit child nodes
|
|
527
|
+
for (var key in node) {
|
|
528
|
+
if (skipKeys.has(key)) {
|
|
529
|
+
continue;
|
|
530
|
+
}
|
|
531
|
+
var value = node[key];
|
|
532
|
+
if (value && (0, _typeof2.default)(value) === 'object') {
|
|
533
|
+
if (Array.isArray(value)) {
|
|
534
|
+
var _iterator11 = _createForOfIteratorHelper(value),
|
|
535
|
+
_step11;
|
|
536
|
+
try {
|
|
537
|
+
for (_iterator11.s(); !(_step11 = _iterator11.n()).done;) {
|
|
538
|
+
var child = _step11.value;
|
|
539
|
+
if (child && (0, _typeof2.default)(child) === 'object' && 'type' in child) {
|
|
540
|
+
visitNode(child);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
} catch (err) {
|
|
544
|
+
_iterator11.e(err);
|
|
545
|
+
} finally {
|
|
546
|
+
_iterator11.f();
|
|
547
|
+
}
|
|
548
|
+
} else if ('type' in value) {
|
|
549
|
+
visitNode(value);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
visitNode(ast);
|
|
555
|
+
return allMocks;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Merge mock properties from multiple sources for the same file
|
|
560
|
+
*/
|
|
561
|
+
function mergeMockProperties(_ref8) {
|
|
562
|
+
var existingProperties = _ref8.existingProperties,
|
|
563
|
+
newProperties = _ref8.newProperties;
|
|
564
|
+
var merged = new Map(existingProperties);
|
|
565
|
+
var _iterator12 = _createForOfIteratorHelper(newProperties),
|
|
566
|
+
_step12;
|
|
567
|
+
try {
|
|
568
|
+
for (_iterator12.s(); !(_step12 = _iterator12.n()).done;) {
|
|
569
|
+
var _step12$value = (0, _slicedToArray2.default)(_step12.value, 2),
|
|
570
|
+
key = _step12$value[0],
|
|
571
|
+
value = _step12$value[1];
|
|
572
|
+
merged.set(key, value);
|
|
573
|
+
}
|
|
574
|
+
} catch (err) {
|
|
575
|
+
_iterator12.e(err);
|
|
576
|
+
} finally {
|
|
577
|
+
_iterator12.f();
|
|
578
|
+
}
|
|
579
|
+
return merged;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Check if a node is an Object.assign call
|
|
584
|
+
*/
|
|
585
|
+
function isObjectAssignCall(_ref9) {
|
|
586
|
+
var node = _ref9.node;
|
|
587
|
+
if (node.type !== 'CallExpression') {
|
|
588
|
+
return false;
|
|
589
|
+
}
|
|
590
|
+
var callee = node.callee;
|
|
591
|
+
if (callee.type === 'MemberExpression') {
|
|
592
|
+
return callee.object.type === 'Identifier' && callee.object.name === 'Object' && callee.property.type === 'Identifier' && callee.property.name === 'assign';
|
|
593
|
+
}
|
|
594
|
+
return false;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* Extract the object expression containing mock properties from an Object.assign call.
|
|
599
|
+
* Pattern: Object.assign({}, jest.requireActual(...), { props... })
|
|
600
|
+
* Returns the last ObjectExpression argument, or null if not found.
|
|
601
|
+
*/
|
|
602
|
+
function extractObjectFromAssign(_ref0) {
|
|
603
|
+
var callExpr = _ref0.callExpr;
|
|
604
|
+
// Look for ObjectExpression arguments that are not the target (first arg)
|
|
605
|
+
// The pattern is typically: Object.assign({}, jest.requireActual(...), { actual props })
|
|
606
|
+
// We want the last ObjectExpression that contains the actual mock properties
|
|
607
|
+
for (var i = callExpr.arguments.length - 1; i >= 0; i--) {
|
|
608
|
+
var arg = callExpr.arguments[i];
|
|
609
|
+
if (arg.type === 'ObjectExpression' && arg.properties.length > 0) {
|
|
610
|
+
return arg;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
return null;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/**
|
|
617
|
+
* Extract the mock implementation object from the jest.mock call.
|
|
618
|
+
* Handles arrow functions, function expressions, and Object.assign patterns.
|
|
619
|
+
*/
|
|
620
|
+
function extractMockImplementation(_ref1) {
|
|
621
|
+
var mockImpl = _ref1.mockImpl;
|
|
622
|
+
// Helper to unwrap Object.assign if present
|
|
623
|
+
var unwrapObjectAssign = function unwrapObjectAssign(node) {
|
|
624
|
+
if (node.type === 'CallExpression' && isObjectAssignCall({
|
|
625
|
+
node: node
|
|
626
|
+
})) {
|
|
627
|
+
var extracted = extractObjectFromAssign({
|
|
628
|
+
callExpr: node
|
|
629
|
+
});
|
|
630
|
+
if (extracted) {
|
|
631
|
+
return extracted;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
return node;
|
|
635
|
+
};
|
|
636
|
+
if (mockImpl.type === 'ArrowFunctionExpression') {
|
|
637
|
+
if (mockImpl.body.type === 'ObjectExpression') {
|
|
638
|
+
return mockImpl.body;
|
|
639
|
+
}
|
|
640
|
+
// Handle arrow function returning Object.assign
|
|
641
|
+
if (mockImpl.body.type === 'CallExpression' && isObjectAssignCall({
|
|
642
|
+
node: mockImpl.body
|
|
643
|
+
})) {
|
|
644
|
+
return unwrapObjectAssign(mockImpl.body);
|
|
645
|
+
}
|
|
646
|
+
if (mockImpl.body.type === 'BlockStatement') {
|
|
647
|
+
var returnStmt = mockImpl.body.body.find(function (s) {
|
|
648
|
+
return s.type === 'ReturnStatement';
|
|
649
|
+
});
|
|
650
|
+
if (returnStmt !== null && returnStmt !== void 0 && returnStmt.argument) {
|
|
651
|
+
return unwrapObjectAssign(returnStmt.argument);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
if (mockImpl.type === 'FunctionExpression' && mockImpl.body.type === 'BlockStatement') {
|
|
656
|
+
var _returnStmt = mockImpl.body.body.find(function (s) {
|
|
657
|
+
return s.type === 'ReturnStatement';
|
|
658
|
+
});
|
|
659
|
+
if (_returnStmt !== null && _returnStmt !== void 0 && _returnStmt.argument) {
|
|
660
|
+
return unwrapObjectAssign(_returnStmt.argument);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
return mockImpl;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
/**
|
|
667
|
+
* Trace mocked symbols to their source files and group by package.json exports.
|
|
668
|
+
*/
|
|
669
|
+
function traceSymbolsToExports(_ref10) {
|
|
670
|
+
var symbolNames = _ref10.symbolNames,
|
|
671
|
+
exportMap = _ref10.exportMap,
|
|
672
|
+
exportsMap = _ref10.exportsMap,
|
|
673
|
+
currentExportPath = _ref10.currentExportPath,
|
|
674
|
+
fs = _ref10.fs;
|
|
675
|
+
var groupedByExport = new Map();
|
|
676
|
+
var crossPackageGroups = new Map();
|
|
677
|
+
var unmappedSymbols = [];
|
|
678
|
+
var _iterator13 = _createForOfIteratorHelper(symbolNames),
|
|
679
|
+
_step13;
|
|
680
|
+
try {
|
|
681
|
+
for (_iterator13.s(); !(_step13 = _iterator13.n()).done;) {
|
|
682
|
+
var symbolName = _step13.value;
|
|
683
|
+
var exportInfo = exportMap.get(symbolName);
|
|
684
|
+
if (!exportInfo) {
|
|
685
|
+
unmappedSymbols.push(symbolName);
|
|
686
|
+
continue;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
// Check for cross-package source first
|
|
690
|
+
if (exportInfo.crossPackageSource) {
|
|
691
|
+
var key = "".concat(exportInfo.crossPackageSource.packageName).concat(exportInfo.crossPackageSource.exportPath === '.' ? '' : exportInfo.crossPackageSource.exportPath.slice(1));
|
|
692
|
+
if (!crossPackageGroups.has(key)) {
|
|
693
|
+
crossPackageGroups.set(key, []);
|
|
694
|
+
}
|
|
695
|
+
crossPackageGroups.get(key).push({
|
|
696
|
+
symbolName: symbolName,
|
|
697
|
+
originalName: exportInfo.originalName,
|
|
698
|
+
sourceFilePath: exportInfo.path,
|
|
699
|
+
isTypeOnly: exportInfo.isTypeOnly,
|
|
700
|
+
crossPackageSource: exportInfo.crossPackageSource
|
|
701
|
+
});
|
|
702
|
+
continue;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
// First try to find an export that directly exposes the source file
|
|
706
|
+
var targetExportPath = (0, _packageResolution.findExportForSourceFile)({
|
|
707
|
+
sourceFilePath: exportInfo.path,
|
|
708
|
+
exportsMap: exportsMap
|
|
709
|
+
});
|
|
710
|
+
|
|
711
|
+
// If no direct match, check which export can provide this symbol
|
|
712
|
+
// (handles nested barrels where the symbol is re-exported through intermediate files)
|
|
713
|
+
if (!targetExportPath) {
|
|
714
|
+
targetExportPath = findExportForSymbol({
|
|
715
|
+
symbolName: symbolName,
|
|
716
|
+
symbolSourcePath: exportInfo.path,
|
|
717
|
+
exportsMap: exportsMap,
|
|
718
|
+
currentExportPath: currentExportPath,
|
|
719
|
+
fs: fs
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
if (targetExportPath && targetExportPath !== currentExportPath) {
|
|
723
|
+
if (!groupedByExport.has(targetExportPath)) {
|
|
724
|
+
groupedByExport.set(targetExportPath, []);
|
|
725
|
+
}
|
|
726
|
+
groupedByExport.get(targetExportPath).push({
|
|
727
|
+
symbolName: symbolName,
|
|
728
|
+
originalName: exportInfo.originalName,
|
|
729
|
+
sourceFilePath: exportInfo.path,
|
|
730
|
+
isTypeOnly: exportInfo.isTypeOnly
|
|
731
|
+
});
|
|
732
|
+
} else {
|
|
733
|
+
unmappedSymbols.push(symbolName);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
} catch (err) {
|
|
737
|
+
_iterator13.e(err);
|
|
738
|
+
} finally {
|
|
739
|
+
_iterator13.f();
|
|
740
|
+
}
|
|
741
|
+
return {
|
|
742
|
+
groupedByExport: groupedByExport,
|
|
743
|
+
crossPackageGroups: crossPackageGroups,
|
|
744
|
+
unmappedSymbols: unmappedSymbols
|
|
745
|
+
};
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* Replace the property key in property text when the export is aliased.
|
|
750
|
+
* For example, if the original text is "renamedFunction: jest.fn()" and
|
|
751
|
+
* the original name is "originalFunction", returns "originalFunction: jest.fn()".
|
|
752
|
+
*/
|
|
753
|
+
function replacePropertyKey(_ref11) {
|
|
754
|
+
var propText = _ref11.propText,
|
|
755
|
+
mockName = _ref11.mockName,
|
|
756
|
+
originalName = _ref11.originalName;
|
|
757
|
+
// Match the property key at the start (handles both quoted and unquoted keys)
|
|
758
|
+
var keyPattern = new RegExp("^(['\"]?)".concat(escapeRegExp(mockName), "\\1\\s*:"));
|
|
759
|
+
return propText.replace(keyPattern, "".concat(originalName, ":"));
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
/**
|
|
763
|
+
* Escape special regex characters in a string.
|
|
764
|
+
*/
|
|
765
|
+
function escapeRegExp(str) {
|
|
766
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
/**
|
|
770
|
+
* Generate fix text for multiple jest.mock calls
|
|
771
|
+
*/
|
|
772
|
+
function generateMockFixes(_ref12) {
|
|
773
|
+
var groups = _ref12.groups,
|
|
774
|
+
crossPackageGroups = _ref12.crossPackageGroups,
|
|
775
|
+
packageName = _ref12.packageName,
|
|
776
|
+
mockProperties = _ref12.mockProperties,
|
|
777
|
+
quote = _ref12.quote,
|
|
778
|
+
preambleStatements = _ref12.preambleStatements;
|
|
779
|
+
var mockCalls = [];
|
|
780
|
+
|
|
781
|
+
// Helper to generate a single mock call
|
|
782
|
+
var generateMockCall = function generateMockCall(group, fullImportPath) {
|
|
783
|
+
var propTexts = [];
|
|
784
|
+
propTexts.push("...jest.requireActual(".concat(quote).concat(fullImportPath).concat(quote, ")"));
|
|
785
|
+
|
|
786
|
+
// Add __esModule: true when mocking default exports
|
|
787
|
+
if (group.hasDefaultExport) {
|
|
788
|
+
propTexts.push('__esModule: true');
|
|
789
|
+
}
|
|
790
|
+
var _iterator14 = _createForOfIteratorHelper(group.propertyNames),
|
|
791
|
+
_step14;
|
|
792
|
+
try {
|
|
793
|
+
for (_iterator14.s(); !(_step14 = _iterator14.n()).done;) {
|
|
794
|
+
var propName = _step14.value;
|
|
795
|
+
// First try to get from group's propertyTexts (used for merged mocks)
|
|
796
|
+
var groupPropText = group.propertyTexts.get(propName);
|
|
797
|
+
if (groupPropText) {
|
|
798
|
+
// Check if this property needs to be renamed (aliased export)
|
|
799
|
+
var originalName = group.nameMapping.get(propName);
|
|
800
|
+
if (originalName && originalName !== propName) {
|
|
801
|
+
var renamedText = replacePropertyKey({
|
|
802
|
+
propText: groupPropText,
|
|
803
|
+
mockName: propName,
|
|
804
|
+
originalName: originalName
|
|
805
|
+
});
|
|
806
|
+
propTexts.push(renamedText);
|
|
807
|
+
} else {
|
|
808
|
+
propTexts.push(groupPropText);
|
|
809
|
+
}
|
|
810
|
+
} else {
|
|
811
|
+
// Fallback to mockProperties (shouldn't happen with properly constructed groups)
|
|
812
|
+
var propInfo = mockProperties.get(propName);
|
|
813
|
+
if (propInfo) {
|
|
814
|
+
var _originalName = group.nameMapping.get(propName);
|
|
815
|
+
if (_originalName && _originalName !== propName) {
|
|
816
|
+
var _renamedText = replacePropertyKey({
|
|
817
|
+
propText: propInfo.text,
|
|
818
|
+
mockName: propName,
|
|
819
|
+
originalName: _originalName
|
|
820
|
+
});
|
|
821
|
+
propTexts.push(_renamedText);
|
|
822
|
+
} else {
|
|
823
|
+
propTexts.push(propInfo.text);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
// Determine if we need preamble for this group
|
|
830
|
+
} catch (err) {
|
|
831
|
+
_iterator14.e(err);
|
|
832
|
+
} finally {
|
|
833
|
+
_iterator14.f();
|
|
834
|
+
}
|
|
835
|
+
var neededPreamble = getNeededPreamble({
|
|
836
|
+
propertyTexts: propTexts,
|
|
837
|
+
allPreamble: preambleStatements
|
|
838
|
+
});
|
|
839
|
+
if (neededPreamble.length > 0) {
|
|
840
|
+
// Generate block body arrow function with preamble
|
|
841
|
+
var preambleLines = neededPreamble.map(function (p) {
|
|
842
|
+
return "\t".concat(p.text);
|
|
843
|
+
}).join('\n');
|
|
844
|
+
var formattedProps = propTexts.map(function (p) {
|
|
845
|
+
return "\t\t".concat(p, ",");
|
|
846
|
+
}).join('\n');
|
|
847
|
+
return "jest.mock(".concat(quote).concat(fullImportPath).concat(quote, ", () => {\n").concat(preambleLines, "\n\treturn {\n").concat(formattedProps, "\n\t};\n})");
|
|
848
|
+
} else {
|
|
849
|
+
// Always use multi-line format for consistency
|
|
850
|
+
var _formattedProps = propTexts.map(function (p) {
|
|
851
|
+
return "\t".concat(p, ",");
|
|
852
|
+
}).join('\n');
|
|
853
|
+
return "jest.mock(".concat(quote).concat(fullImportPath).concat(quote, ", () => ({\n").concat(_formattedProps, "\n}))");
|
|
854
|
+
}
|
|
855
|
+
};
|
|
856
|
+
|
|
857
|
+
// Generate mocks for cross-package groups first
|
|
858
|
+
var _iterator15 = _createForOfIteratorHelper(crossPackageGroups),
|
|
859
|
+
_step15;
|
|
860
|
+
try {
|
|
861
|
+
for (_iterator15.s(); !(_step15 = _iterator15.n()).done;) {
|
|
862
|
+
var group = _step15.value;
|
|
863
|
+
mockCalls.push(generateMockCall(group, group.importPath));
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// Generate mocks for same-package groups
|
|
867
|
+
} catch (err) {
|
|
868
|
+
_iterator15.e(err);
|
|
869
|
+
} finally {
|
|
870
|
+
_iterator15.f();
|
|
871
|
+
}
|
|
872
|
+
var _iterator16 = _createForOfIteratorHelper(groups),
|
|
873
|
+
_step16;
|
|
874
|
+
try {
|
|
875
|
+
for (_iterator16.s(); !(_step16 = _iterator16.n()).done;) {
|
|
876
|
+
var _group = _step16.value;
|
|
877
|
+
var fullImportPath = "".concat(packageName).concat(_group.exportPath.slice(1));
|
|
878
|
+
mockCalls.push(generateMockCall(_group, fullImportPath));
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
// Join with semicolons but don't add trailing semicolon
|
|
882
|
+
} catch (err) {
|
|
883
|
+
_iterator16.e(err);
|
|
884
|
+
} finally {
|
|
885
|
+
_iterator16.f();
|
|
886
|
+
}
|
|
887
|
+
return mockCalls.join(';\n');
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
/**
|
|
891
|
+
* Context resolved for a jest.mock that may be mocking a barrel file.
|
|
892
|
+
*/
|
|
893
|
+
|
|
894
|
+
/**
|
|
895
|
+
* Resolves jest.mock context for barrel file analysis.
|
|
896
|
+
* Returns null if the mock should not be processed.
|
|
897
|
+
*/
|
|
898
|
+
function resolveJestMockContext(_ref13) {
|
|
899
|
+
var importPath = _ref13.importPath,
|
|
900
|
+
workspaceRoot = _ref13.workspaceRoot,
|
|
901
|
+
fs = _ref13.fs,
|
|
902
|
+
applyToImportsFrom = _ref13.applyToImportsFrom;
|
|
903
|
+
if ((0, _fileSystem.isRelativeImport)(importPath)) {
|
|
904
|
+
return null;
|
|
905
|
+
}
|
|
906
|
+
var packageNameMatch = importPath.match(/^(@[^/]+\/[^/]+)/);
|
|
907
|
+
if (!packageNameMatch) {
|
|
908
|
+
return null;
|
|
909
|
+
}
|
|
910
|
+
var packageName = packageNameMatch[1];
|
|
911
|
+
var subPath = importPath.slice(packageName.length);
|
|
912
|
+
|
|
913
|
+
// Find the package (resolution is not constrained by applyToImportsFrom)
|
|
914
|
+
var packageDir = (0, _packageRegistry.findPackageInRegistry)({
|
|
915
|
+
packageName: packageName,
|
|
916
|
+
workspaceRoot: workspaceRoot,
|
|
917
|
+
fs: fs
|
|
918
|
+
});
|
|
919
|
+
if (!packageDir) {
|
|
920
|
+
return null;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
// Only check mocks from packages in our applyToImportsFrom folders
|
|
924
|
+
if (!(0, _packageRegistry.isPackageInApplyToImportsFrom)({
|
|
925
|
+
packageDir: packageDir,
|
|
926
|
+
workspaceRoot: workspaceRoot,
|
|
927
|
+
applyToImportsFrom: applyToImportsFrom
|
|
928
|
+
})) {
|
|
929
|
+
return null;
|
|
930
|
+
}
|
|
931
|
+
var exportsMap = (0, _packageResolution.parsePackageExports)({
|
|
932
|
+
packageDir: packageDir,
|
|
933
|
+
fs: fs
|
|
934
|
+
});
|
|
935
|
+
if (exportsMap.size === 0) {
|
|
936
|
+
return null;
|
|
937
|
+
}
|
|
938
|
+
var currentExportPath = subPath ? '.' + subPath : '.';
|
|
939
|
+
var entryFilePath = exportsMap.get(currentExportPath);
|
|
940
|
+
if (!entryFilePath) {
|
|
941
|
+
return null;
|
|
942
|
+
}
|
|
943
|
+
var exportMap = (0, _barrelParsing.parseBarrelExports)({
|
|
944
|
+
barrelFilePath: entryFilePath,
|
|
945
|
+
fs: fs,
|
|
946
|
+
workspaceRoot: workspaceRoot
|
|
947
|
+
});
|
|
948
|
+
if (exportMap.size === 0) {
|
|
949
|
+
return null;
|
|
950
|
+
}
|
|
951
|
+
return {
|
|
952
|
+
importPath: importPath,
|
|
953
|
+
packageName: packageName,
|
|
954
|
+
packageDir: packageDir,
|
|
955
|
+
currentExportPath: currentExportPath,
|
|
956
|
+
exportsMap: exportsMap,
|
|
957
|
+
exportMap: exportMap,
|
|
958
|
+
entryFilePath: entryFilePath
|
|
959
|
+
};
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
/**
|
|
963
|
+
* Check if the entry file is a barrel file (re-exports from other files)
|
|
964
|
+
*/
|
|
965
|
+
function isBarrelFile(_ref14) {
|
|
966
|
+
var exportMap = _ref14.exportMap,
|
|
967
|
+
entryFilePath = _ref14.entryFilePath;
|
|
968
|
+
return (0, _barrelParsing.hasReExportsFromOtherFiles)({
|
|
969
|
+
exportMap: exportMap,
|
|
970
|
+
sourceFilePath: entryFilePath
|
|
971
|
+
});
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
/**
|
|
975
|
+
* Metadata for the ESLint rule
|
|
976
|
+
*/
|
|
977
|
+
var ruleMeta = {
|
|
978
|
+
type: 'problem',
|
|
979
|
+
docs: {
|
|
980
|
+
description: 'Disallow jest.mock calls on barrel file entry points. Mock source files directly using package.json exports.',
|
|
981
|
+
category: 'Best Practices',
|
|
982
|
+
recommended: false
|
|
983
|
+
},
|
|
984
|
+
fixable: 'code',
|
|
985
|
+
schema: [{
|
|
986
|
+
type: 'object',
|
|
987
|
+
properties: {
|
|
988
|
+
applyToImportsFrom: {
|
|
989
|
+
type: 'array',
|
|
990
|
+
items: {
|
|
991
|
+
type: 'string'
|
|
992
|
+
},
|
|
993
|
+
description: 'The folder paths (relative to workspace root) containing packages whose imports will be checked and autofixed.'
|
|
994
|
+
}
|
|
995
|
+
},
|
|
996
|
+
additionalProperties: false
|
|
997
|
+
}],
|
|
998
|
+
messages: {
|
|
999
|
+
barrelEntryMock: "jest.mock('{{path}}') is mocking a barrel file entry point. Split into separate mocks for each source file using package.json exports."
|
|
1000
|
+
}
|
|
1001
|
+
};
|
|
1002
|
+
|
|
1003
|
+
/**
|
|
1004
|
+
* Factory function to create the ESLint rule with a given file system.
|
|
1005
|
+
* This enables testing with mock file systems.
|
|
1006
|
+
*/
|
|
1007
|
+
function createRule(fs) {
|
|
1008
|
+
return {
|
|
1009
|
+
meta: ruleMeta,
|
|
1010
|
+
create: function create(context) {
|
|
1011
|
+
var _options$applyToImpor;
|
|
1012
|
+
var options = context.options[0] || {};
|
|
1013
|
+
var applyToImportsFrom = (_options$applyToImpor = options.applyToImportsFrom) !== null && _options$applyToImpor !== void 0 ? _options$applyToImpor : _fileSystem.DEFAULT_TARGET_FOLDERS;
|
|
1014
|
+
var workspaceRoot = (0, _fileSystem.findWorkspaceRoot)({
|
|
1015
|
+
startPath: (0, _path.dirname)(context.filename),
|
|
1016
|
+
fs: fs,
|
|
1017
|
+
applyToImportsFrom: applyToImportsFrom
|
|
1018
|
+
});
|
|
1019
|
+
return {
|
|
1020
|
+
CallExpression: function CallExpression(rawNode) {
|
|
1021
|
+
var node = rawNode;
|
|
1022
|
+
if (!(0, _jestUtils.isJestMockCall)(node)) {
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
var importPath = (0, _jestUtils.extractImportPath)(node);
|
|
1026
|
+
if (!importPath) {
|
|
1027
|
+
return;
|
|
1028
|
+
}
|
|
1029
|
+
var mockContext = resolveJestMockContext({
|
|
1030
|
+
importPath: importPath,
|
|
1031
|
+
workspaceRoot: workspaceRoot,
|
|
1032
|
+
fs: fs,
|
|
1033
|
+
applyToImportsFrom: applyToImportsFrom
|
|
1034
|
+
});
|
|
1035
|
+
if (!mockContext) {
|
|
1036
|
+
return;
|
|
1037
|
+
}
|
|
1038
|
+
if (!isBarrelFile({
|
|
1039
|
+
exportMap: mockContext.exportMap,
|
|
1040
|
+
entryFilePath: mockContext.entryFilePath
|
|
1041
|
+
})) {
|
|
1042
|
+
return;
|
|
1043
|
+
}
|
|
1044
|
+
var mockImpl = node.arguments[1];
|
|
1045
|
+
// Ignore auto-mocks (jest.mock with only the import string and no second argument)
|
|
1046
|
+
// These are intentionally excluded from barrel file checks as they auto-mock all exports
|
|
1047
|
+
if (!mockImpl) {
|
|
1048
|
+
return;
|
|
1049
|
+
}
|
|
1050
|
+
var mockObjectNode = extractMockImplementation({
|
|
1051
|
+
mockImpl: mockImpl
|
|
1052
|
+
});
|
|
1053
|
+
var sourceCode = context.getSourceCode();
|
|
1054
|
+
var _extractMockPropertie2 = extractMockProperties({
|
|
1055
|
+
sourceCode: sourceCode,
|
|
1056
|
+
mockObjectNode: mockObjectNode
|
|
1057
|
+
}),
|
|
1058
|
+
mockProperties = _extractMockPropertie2.properties;
|
|
1059
|
+
|
|
1060
|
+
// Extract preamble statements (variable declarations before return)
|
|
1061
|
+
var preambleStatements = extractPreambleStatements({
|
|
1062
|
+
mockImpl: mockImpl,
|
|
1063
|
+
sourceCode: sourceCode
|
|
1064
|
+
});
|
|
1065
|
+
if (mockProperties.size === 0) {
|
|
1066
|
+
return;
|
|
1067
|
+
}
|
|
1068
|
+
var symbolNames = Array.from(mockProperties.keys());
|
|
1069
|
+
var _traceSymbolsToExport = traceSymbolsToExports({
|
|
1070
|
+
symbolNames: symbolNames,
|
|
1071
|
+
exportMap: mockContext.exportMap,
|
|
1072
|
+
exportsMap: mockContext.exportsMap,
|
|
1073
|
+
currentExportPath: mockContext.currentExportPath,
|
|
1074
|
+
fs: fs
|
|
1075
|
+
}),
|
|
1076
|
+
groupedByExport = _traceSymbolsToExport.groupedByExport,
|
|
1077
|
+
crossPackageGroups = _traceSymbolsToExport.crossPackageGroups,
|
|
1078
|
+
unmappedSymbols = _traceSymbolsToExport.unmappedSymbols;
|
|
1079
|
+
|
|
1080
|
+
// If no symbols can be mapped to specific exports or cross-package sources,
|
|
1081
|
+
// there's nothing to fix so don't report an error
|
|
1082
|
+
if (groupedByExport.size === 0 && crossPackageGroups.size === 0) {
|
|
1083
|
+
return;
|
|
1084
|
+
}
|
|
1085
|
+
var groups = [];
|
|
1086
|
+
var _iterator17 = _createForOfIteratorHelper(groupedByExport),
|
|
1087
|
+
_step17;
|
|
1088
|
+
try {
|
|
1089
|
+
for (_iterator17.s(); !(_step17 = _iterator17.n()).done;) {
|
|
1090
|
+
var _step17$value = (0, _slicedToArray2.default)(_step17.value, 2),
|
|
1091
|
+
exportPath = _step17$value[0],
|
|
1092
|
+
symbols = _step17$value[1];
|
|
1093
|
+
// Build name mapping for aliased exports
|
|
1094
|
+
var nameMapping = new Map();
|
|
1095
|
+
var _iterator22 = _createForOfIteratorHelper(symbols),
|
|
1096
|
+
_step22;
|
|
1097
|
+
try {
|
|
1098
|
+
for (_iterator22.s(); !(_step22 = _iterator22.n()).done;) {
|
|
1099
|
+
var s = _step22.value;
|
|
1100
|
+
if (s.originalName) {
|
|
1101
|
+
nameMapping.set(s.symbolName, s.originalName);
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
// Check if any symbol in this group is a default export
|
|
1106
|
+
} catch (err) {
|
|
1107
|
+
_iterator22.e(err);
|
|
1108
|
+
} finally {
|
|
1109
|
+
_iterator22.f();
|
|
1110
|
+
}
|
|
1111
|
+
var hasDefaultExport = symbols.some(function (s) {
|
|
1112
|
+
return s.originalName === 'default';
|
|
1113
|
+
});
|
|
1114
|
+
groups.push({
|
|
1115
|
+
exportPath: exportPath,
|
|
1116
|
+
importPath: "".concat(mockContext.packageName).concat(exportPath.slice(1)),
|
|
1117
|
+
propertyNames: symbols.map(function (s) {
|
|
1118
|
+
return s.symbolName;
|
|
1119
|
+
}),
|
|
1120
|
+
propertyTexts: new Map(symbols.map(function (s) {
|
|
1121
|
+
return [s.symbolName, mockProperties.get(s.symbolName).text];
|
|
1122
|
+
})),
|
|
1123
|
+
nameMapping: nameMapping,
|
|
1124
|
+
hasDefaultExport: hasDefaultExport
|
|
1125
|
+
});
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
// Build cross-package groups
|
|
1129
|
+
} catch (err) {
|
|
1130
|
+
_iterator17.e(err);
|
|
1131
|
+
} finally {
|
|
1132
|
+
_iterator17.f();
|
|
1133
|
+
}
|
|
1134
|
+
var crossPackageMockGroups = [];
|
|
1135
|
+
var _iterator18 = _createForOfIteratorHelper(crossPackageGroups),
|
|
1136
|
+
_step18;
|
|
1137
|
+
try {
|
|
1138
|
+
for (_iterator18.s(); !(_step18 = _iterator18.n()).done;) {
|
|
1139
|
+
var _step18$value = (0, _slicedToArray2.default)(_step18.value, 2),
|
|
1140
|
+
_importPath = _step18$value[0],
|
|
1141
|
+
_symbols = _step18$value[1];
|
|
1142
|
+
// Build name mapping for aliased exports
|
|
1143
|
+
var _nameMapping = new Map();
|
|
1144
|
+
var _iterator23 = _createForOfIteratorHelper(_symbols),
|
|
1145
|
+
_step23;
|
|
1146
|
+
try {
|
|
1147
|
+
for (_iterator23.s(); !(_step23 = _iterator23.n()).done;) {
|
|
1148
|
+
var _s = _step23.value;
|
|
1149
|
+
if (_s.originalName) {
|
|
1150
|
+
_nameMapping.set(_s.symbolName, _s.originalName);
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
// Check if any symbol in this group is a default export
|
|
1155
|
+
} catch (err) {
|
|
1156
|
+
_iterator23.e(err);
|
|
1157
|
+
} finally {
|
|
1158
|
+
_iterator23.f();
|
|
1159
|
+
}
|
|
1160
|
+
var _hasDefaultExport = _symbols.some(function (s) {
|
|
1161
|
+
return s.originalName === 'default';
|
|
1162
|
+
});
|
|
1163
|
+
|
|
1164
|
+
// Get cross-package source info from the first symbol (all symbols in same group have same source)
|
|
1165
|
+
var crossPackageSource = _symbols[0].crossPackageSource;
|
|
1166
|
+
crossPackageMockGroups.push({
|
|
1167
|
+
exportPath: crossPackageSource.exportPath,
|
|
1168
|
+
importPath: _importPath,
|
|
1169
|
+
propertyNames: _symbols.map(function (s) {
|
|
1170
|
+
return s.symbolName;
|
|
1171
|
+
}),
|
|
1172
|
+
propertyTexts: new Map(_symbols.map(function (s) {
|
|
1173
|
+
return [s.symbolName, mockProperties.get(s.symbolName).text];
|
|
1174
|
+
})),
|
|
1175
|
+
nameMapping: _nameMapping,
|
|
1176
|
+
hasDefaultExport: _hasDefaultExport
|
|
1177
|
+
});
|
|
1178
|
+
}
|
|
1179
|
+
} catch (err) {
|
|
1180
|
+
_iterator18.e(err);
|
|
1181
|
+
} finally {
|
|
1182
|
+
_iterator18.f();
|
|
1183
|
+
}
|
|
1184
|
+
if (unmappedSymbols.length > 0) {
|
|
1185
|
+
groups.push({
|
|
1186
|
+
exportPath: mockContext.currentExportPath,
|
|
1187
|
+
importPath: mockContext.importPath,
|
|
1188
|
+
propertyNames: unmappedSymbols,
|
|
1189
|
+
propertyTexts: new Map(unmappedSymbols.map(function (s) {
|
|
1190
|
+
return [s, mockProperties.get(s).text];
|
|
1191
|
+
})),
|
|
1192
|
+
nameMapping: new Map(),
|
|
1193
|
+
hasDefaultExport: false
|
|
1194
|
+
});
|
|
1195
|
+
}
|
|
1196
|
+
context.report({
|
|
1197
|
+
node: node,
|
|
1198
|
+
messageId: 'barrelEntryMock',
|
|
1199
|
+
data: {
|
|
1200
|
+
path: importPath
|
|
1201
|
+
},
|
|
1202
|
+
fix: function fix(fixer) {
|
|
1203
|
+
var firstArg = node.arguments[0];
|
|
1204
|
+
var quote = sourceCode.getText(firstArg)[0];
|
|
1205
|
+
|
|
1206
|
+
// Build a mapping from old import path to new import paths (with their symbols)
|
|
1207
|
+
// so we can update jest.requireMock() calls later
|
|
1208
|
+
var oldImportPath = importPath;
|
|
1209
|
+
|
|
1210
|
+
// Find all existing jest.mock calls in the file
|
|
1211
|
+
var allExistingMocks = findAllJestMocksInFile({
|
|
1212
|
+
context: context
|
|
1213
|
+
});
|
|
1214
|
+
|
|
1215
|
+
// Track nodes to remove and merged mock info
|
|
1216
|
+
var nodesToRemove = [node];
|
|
1217
|
+
var mergedGroups = [];
|
|
1218
|
+
for (var _i3 = 0, _groups = groups; _i3 < _groups.length; _i3++) {
|
|
1219
|
+
var group = _groups[_i3];
|
|
1220
|
+
var existingMock = allExistingMocks.get(group.importPath);
|
|
1221
|
+
if (existingMock && existingMock.node !== node) {
|
|
1222
|
+
// Merge properties from existing mock with new properties
|
|
1223
|
+
var newPropertiesMap = new Map();
|
|
1224
|
+
var _iterator19 = _createForOfIteratorHelper(group.propertyNames),
|
|
1225
|
+
_step19;
|
|
1226
|
+
try {
|
|
1227
|
+
for (_iterator19.s(); !(_step19 = _iterator19.n()).done;) {
|
|
1228
|
+
var propName = _step19.value;
|
|
1229
|
+
var propInfo = mockProperties.get(propName);
|
|
1230
|
+
if (propInfo) {
|
|
1231
|
+
// Check if this property needs to be renamed (aliased export)
|
|
1232
|
+
var originalName = group.nameMapping.get(propName);
|
|
1233
|
+
if (originalName && originalName !== propName) {
|
|
1234
|
+
var renamedText = replacePropertyKey({
|
|
1235
|
+
propText: propInfo.text,
|
|
1236
|
+
mockName: propName,
|
|
1237
|
+
originalName: originalName
|
|
1238
|
+
});
|
|
1239
|
+
newPropertiesMap.set(originalName, {
|
|
1240
|
+
node: propInfo.node,
|
|
1241
|
+
text: renamedText
|
|
1242
|
+
});
|
|
1243
|
+
} else {
|
|
1244
|
+
newPropertiesMap.set(propName, propInfo);
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
} catch (err) {
|
|
1249
|
+
_iterator19.e(err);
|
|
1250
|
+
} finally {
|
|
1251
|
+
_iterator19.f();
|
|
1252
|
+
}
|
|
1253
|
+
var mergedProperties = mergeMockProperties({
|
|
1254
|
+
existingProperties: existingMock.properties,
|
|
1255
|
+
newProperties: newPropertiesMap
|
|
1256
|
+
});
|
|
1257
|
+
|
|
1258
|
+
// Create merged group with all properties
|
|
1259
|
+
mergedGroups.push({
|
|
1260
|
+
exportPath: group.exportPath,
|
|
1261
|
+
importPath: group.importPath,
|
|
1262
|
+
propertyNames: Array.from(mergedProperties.keys()),
|
|
1263
|
+
propertyTexts: new Map(Array.from(mergedProperties.entries()).map(function (_ref15) {
|
|
1264
|
+
var _ref16 = (0, _slicedToArray2.default)(_ref15, 2),
|
|
1265
|
+
k = _ref16[0],
|
|
1266
|
+
v = _ref16[1];
|
|
1267
|
+
return [k, v.text];
|
|
1268
|
+
})),
|
|
1269
|
+
nameMapping: new Map(),
|
|
1270
|
+
// Already applied above
|
|
1271
|
+
hasDefaultExport: group.hasDefaultExport
|
|
1272
|
+
});
|
|
1273
|
+
|
|
1274
|
+
// Mark existing mock for removal
|
|
1275
|
+
nodesToRemove.push(existingMock.node);
|
|
1276
|
+
} else {
|
|
1277
|
+
// No existing mock, use the group as-is
|
|
1278
|
+
mergedGroups.push(group);
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
var fixText = generateMockFixes({
|
|
1282
|
+
groups: mergedGroups,
|
|
1283
|
+
crossPackageGroups: crossPackageMockGroups,
|
|
1284
|
+
packageName: mockContext.packageName,
|
|
1285
|
+
mockProperties: mockProperties,
|
|
1286
|
+
quote: quote,
|
|
1287
|
+
preambleStatements: preambleStatements
|
|
1288
|
+
});
|
|
1289
|
+
|
|
1290
|
+
// Build a map of symbol name -> new import path for jest.requireMock() rewriting
|
|
1291
|
+
var symbolToNewImportPath = new Map();
|
|
1292
|
+
for (var _i4 = 0, _arr = [].concat(mergedGroups, crossPackageMockGroups); _i4 < _arr.length; _i4++) {
|
|
1293
|
+
var _group2 = _arr[_i4];
|
|
1294
|
+
var _iterator20 = _createForOfIteratorHelper(_group2.propertyNames),
|
|
1295
|
+
_step20;
|
|
1296
|
+
try {
|
|
1297
|
+
for (_iterator20.s(); !(_step20 = _iterator20.n()).done;) {
|
|
1298
|
+
var _propName = _step20.value;
|
|
1299
|
+
symbolToNewImportPath.set(_propName, _group2.importPath);
|
|
1300
|
+
}
|
|
1301
|
+
} catch (err) {
|
|
1302
|
+
_iterator20.e(err);
|
|
1303
|
+
} finally {
|
|
1304
|
+
_iterator20.f();
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
// Sort nodes by position
|
|
1309
|
+
var sortedNodesToRemove = nodesToRemove.sort(function (a, b) {
|
|
1310
|
+
var _a$range$, _a$range, _b$range$, _b$range;
|
|
1311
|
+
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);
|
|
1312
|
+
});
|
|
1313
|
+
var fixes = [];
|
|
1314
|
+
if (sortedNodesToRemove.length === 1) {
|
|
1315
|
+
// Simple case: just replace the current node
|
|
1316
|
+
fixes.push(fixer.replaceText(node, fixText));
|
|
1317
|
+
} else {
|
|
1318
|
+
// Complex case: replace first node, remove others
|
|
1319
|
+
// Replace the first node with the merged mocks
|
|
1320
|
+
fixes.push(fixer.replaceText(sortedNodesToRemove[0], fixText));
|
|
1321
|
+
|
|
1322
|
+
// Remove remaining nodes
|
|
1323
|
+
for (var i = 1; i < sortedNodesToRemove.length; i++) {
|
|
1324
|
+
var nodeToRemove = sortedNodesToRemove[i];
|
|
1325
|
+
var tokenAfter = sourceCode.getTokenAfter(nodeToRemove);
|
|
1326
|
+
var startPos = nodeToRemove.range[0];
|
|
1327
|
+
var endPos = nodeToRemove.range[1];
|
|
1328
|
+
|
|
1329
|
+
// Include trailing semicolon if present
|
|
1330
|
+
if (tokenAfter && tokenAfter.type === 'Punctuator' && tokenAfter.value === ';') {
|
|
1331
|
+
endPos = tokenAfter.range[1];
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
// Include trailing whitespace and newlines
|
|
1335
|
+
var text = sourceCode.getText();
|
|
1336
|
+
while (endPos < text.length && /[\s\n]/.test(text[endPos])) {
|
|
1337
|
+
endPos++;
|
|
1338
|
+
}
|
|
1339
|
+
fixes.push(fixer.removeRange([startPos, endPos]));
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
// Fix jest.requireMock() calls that reference the old barrel path.
|
|
1344
|
+
// When we split a jest.mock('pkg/barrel') into jest.mock('pkg/subpath'),
|
|
1345
|
+
// any jest.requireMock('pkg/barrel') calls also need to be updated.
|
|
1346
|
+
var ast = sourceCode.ast;
|
|
1347
|
+
var requireMockCalls = (0, _jestUtils.findJestRequireMockCalls)({
|
|
1348
|
+
ast: ast,
|
|
1349
|
+
matchPath: function matchPath(candidatePath) {
|
|
1350
|
+
return candidatePath === oldImportPath;
|
|
1351
|
+
}
|
|
1352
|
+
});
|
|
1353
|
+
var _iterator21 = _createForOfIteratorHelper(requireMockCalls),
|
|
1354
|
+
_step21;
|
|
1355
|
+
try {
|
|
1356
|
+
for (_iterator21.s(); !(_step21 = _iterator21.n()).done;) {
|
|
1357
|
+
var requireMockNode = _step21.value;
|
|
1358
|
+
var requireMockArg = requireMockNode.arguments[0];
|
|
1359
|
+
if (!requireMockArg) {
|
|
1360
|
+
continue;
|
|
1361
|
+
}
|
|
1362
|
+
var newPath = (0, _jestUtils.resolveNewPathForRequireMock)({
|
|
1363
|
+
requireMockNode: requireMockNode,
|
|
1364
|
+
symbolToNewPath: symbolToNewImportPath
|
|
1365
|
+
});
|
|
1366
|
+
if (newPath) {
|
|
1367
|
+
fixes.push(fixer.replaceText(requireMockArg, "".concat(quote).concat(newPath).concat(quote)));
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
} catch (err) {
|
|
1371
|
+
_iterator21.e(err);
|
|
1372
|
+
} finally {
|
|
1373
|
+
_iterator21.f();
|
|
1374
|
+
}
|
|
1375
|
+
return fixes;
|
|
1376
|
+
}
|
|
1377
|
+
});
|
|
1378
|
+
}
|
|
1379
|
+
};
|
|
1380
|
+
}
|
|
1381
|
+
};
|
|
1382
|
+
}
|
|
1383
|
+
var rule = createRule(_types.realFileSystem);
|
|
1384
|
+
var _default = exports.default = rule;
|