1 | 'use strict';
|
2 |
|
3 | function _child_process() {
|
4 | const data = require('child_process');
|
5 |
|
6 | _child_process = function () {
|
7 | return data;
|
8 | };
|
9 |
|
10 | return data;
|
11 | }
|
12 |
|
13 | function path() {
|
14 | const data = _interopRequireWildcard(require('path'));
|
15 |
|
16 | path = function () {
|
17 | return data;
|
18 | };
|
19 |
|
20 | return data;
|
21 | }
|
22 |
|
23 | function fs() {
|
24 | const data = _interopRequireWildcard(require('graceful-fs'));
|
25 |
|
26 | fs = function () {
|
27 | return data;
|
28 | };
|
29 |
|
30 | return data;
|
31 | }
|
32 |
|
33 | var _constants = _interopRequireDefault(require('../constants'));
|
34 |
|
35 | var fastPath = _interopRequireWildcard(require('../lib/fast_path'));
|
36 |
|
37 | function _interopRequireDefault(obj) {
|
38 | return obj && obj.__esModule ? obj : {default: obj};
|
39 | }
|
40 |
|
41 | function _getRequireWildcardCache(nodeInterop) {
|
42 | if (typeof WeakMap !== 'function') return null;
|
43 | var cacheBabelInterop = new WeakMap();
|
44 | var cacheNodeInterop = new WeakMap();
|
45 | return (_getRequireWildcardCache = function (nodeInterop) {
|
46 | return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
47 | })(nodeInterop);
|
48 | }
|
49 |
|
50 | function _interopRequireWildcard(obj, nodeInterop) {
|
51 | if (!nodeInterop && obj && obj.__esModule) {
|
52 | return obj;
|
53 | }
|
54 | if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
|
55 | return {default: obj};
|
56 | }
|
57 | var cache = _getRequireWildcardCache(nodeInterop);
|
58 | if (cache && cache.has(obj)) {
|
59 | return cache.get(obj);
|
60 | }
|
61 | var newObj = {};
|
62 | var hasPropertyDescriptor =
|
63 | Object.defineProperty && Object.getOwnPropertyDescriptor;
|
64 | for (var key in obj) {
|
65 | if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {
|
66 | var desc = hasPropertyDescriptor
|
67 | ? Object.getOwnPropertyDescriptor(obj, key)
|
68 | : null;
|
69 | if (desc && (desc.get || desc.set)) {
|
70 | Object.defineProperty(newObj, key, desc);
|
71 | } else {
|
72 | newObj[key] = obj[key];
|
73 | }
|
74 | }
|
75 | }
|
76 | newObj.default = obj;
|
77 | if (cache) {
|
78 | cache.set(obj, newObj);
|
79 | }
|
80 | return newObj;
|
81 | }
|
82 |
|
83 |
|
84 |
|
85 |
|
86 |
|
87 |
|
88 |
|
89 | async function hasNativeFindSupport(forceNodeFilesystemAPI) {
|
90 | if (forceNodeFilesystemAPI) {
|
91 | return false;
|
92 | }
|
93 |
|
94 | try {
|
95 | return await new Promise(resolve => {
|
96 |
|
97 | const args = [
|
98 | '.',
|
99 | '-type',
|
100 | 'f',
|
101 | '(',
|
102 | '-iname',
|
103 | '*.ts',
|
104 | '-o',
|
105 | '-iname',
|
106 | '*.js',
|
107 | ')'
|
108 | ];
|
109 | const child = (0, _child_process().spawn)('find', args, {
|
110 | cwd: __dirname
|
111 | });
|
112 | child.on('error', () => {
|
113 | resolve(false);
|
114 | });
|
115 | child.on('exit', code => {
|
116 | resolve(code === 0);
|
117 | });
|
118 | });
|
119 | } catch {
|
120 | return false;
|
121 | }
|
122 | }
|
123 |
|
124 | function find(roots, extensions, ignore, enableSymlinks, callback) {
|
125 | const result = [];
|
126 | let activeCalls = 0;
|
127 |
|
128 | function search(directory) {
|
129 | activeCalls++;
|
130 | fs().readdir(
|
131 | directory,
|
132 | {
|
133 | withFileTypes: true
|
134 | },
|
135 | (err, entries) => {
|
136 | activeCalls--;
|
137 |
|
138 | if (err) {
|
139 | callback(result);
|
140 | return;
|
141 | }
|
142 |
|
143 |
|
144 | entries.forEach(entry => {
|
145 | const file = path().join(
|
146 | directory,
|
147 | typeof entry === 'string' ? entry : entry.name
|
148 | );
|
149 |
|
150 | if (ignore(file)) {
|
151 | return;
|
152 | }
|
153 |
|
154 | if (typeof entry !== 'string') {
|
155 | if (entry.isSymbolicLink()) {
|
156 | return;
|
157 | }
|
158 |
|
159 | if (entry.isDirectory()) {
|
160 | search(file);
|
161 | return;
|
162 | }
|
163 | }
|
164 |
|
165 | activeCalls++;
|
166 | const stat = enableSymlinks ? fs().stat : fs().lstat;
|
167 | stat(file, (err, stat) => {
|
168 | activeCalls--;
|
169 |
|
170 |
|
171 | if (!err && stat && !stat.isSymbolicLink()) {
|
172 | if (stat.isDirectory()) {
|
173 | search(file);
|
174 | } else {
|
175 | const ext = path().extname(file).substr(1);
|
176 |
|
177 | if (extensions.indexOf(ext) !== -1) {
|
178 | result.push([file, stat.mtime.getTime(), stat.size]);
|
179 | }
|
180 | }
|
181 | }
|
182 |
|
183 | if (activeCalls === 0) {
|
184 | callback(result);
|
185 | }
|
186 | });
|
187 | });
|
188 |
|
189 | if (activeCalls === 0) {
|
190 | callback(result);
|
191 | }
|
192 | }
|
193 | );
|
194 | }
|
195 |
|
196 | if (roots.length > 0) {
|
197 | roots.forEach(search);
|
198 | } else {
|
199 | callback(result);
|
200 | }
|
201 | }
|
202 |
|
203 | function findNative(roots, extensions, ignore, enableSymlinks, callback) {
|
204 | const args = Array.from(roots);
|
205 |
|
206 | if (enableSymlinks) {
|
207 | args.push('(', '-type', 'f', '-o', '-type', 'l', ')');
|
208 | } else {
|
209 | args.push('-type', 'f');
|
210 | }
|
211 |
|
212 | if (extensions.length) {
|
213 | args.push('(');
|
214 | }
|
215 |
|
216 | extensions.forEach((ext, index) => {
|
217 | if (index) {
|
218 | args.push('-o');
|
219 | }
|
220 |
|
221 | args.push('-iname');
|
222 | args.push('*.' + ext);
|
223 | });
|
224 |
|
225 | if (extensions.length) {
|
226 | args.push(')');
|
227 | }
|
228 |
|
229 | const child = (0, _child_process().spawn)('find', args);
|
230 | let stdout = '';
|
231 |
|
232 | if (child.stdout === null) {
|
233 | throw new Error(
|
234 | 'stdout is null - this should never happen. Please open up an issue at https://github.com/facebook/jest'
|
235 | );
|
236 | }
|
237 |
|
238 | child.stdout.setEncoding('utf-8');
|
239 | child.stdout.on('data', data => (stdout += data));
|
240 | child.stdout.on('close', () => {
|
241 | const lines = stdout
|
242 | .trim()
|
243 | .split('\n')
|
244 | .filter(x => !ignore(x));
|
245 | const result = [];
|
246 | let count = lines.length;
|
247 |
|
248 | if (!count) {
|
249 | callback([]);
|
250 | } else {
|
251 | lines.forEach(path => {
|
252 | fs().stat(path, (err, stat) => {
|
253 |
|
254 | if (!err && stat && !stat.isDirectory()) {
|
255 | result.push([path, stat.mtime.getTime(), stat.size]);
|
256 | }
|
257 |
|
258 | if (--count === 0) {
|
259 | callback(result);
|
260 | }
|
261 | });
|
262 | });
|
263 | }
|
264 | });
|
265 | }
|
266 |
|
267 | module.exports = async function nodeCrawl(options) {
|
268 | const {
|
269 | data,
|
270 | extensions,
|
271 | forceNodeFilesystemAPI,
|
272 | ignore,
|
273 | rootDir,
|
274 | enableSymlinks,
|
275 | roots
|
276 | } = options;
|
277 | const useNativeFind = await hasNativeFindSupport(forceNodeFilesystemAPI);
|
278 | return new Promise(resolve => {
|
279 | const callback = list => {
|
280 | const files = new Map();
|
281 | const removedFiles = new Map(data.files);
|
282 | list.forEach(fileData => {
|
283 | const [filePath, mtime, size] = fileData;
|
284 | const relativeFilePath = fastPath.relative(rootDir, filePath);
|
285 | const existingFile = data.files.get(relativeFilePath);
|
286 |
|
287 | if (existingFile && existingFile[_constants.default.MTIME] === mtime) {
|
288 | files.set(relativeFilePath, existingFile);
|
289 | } else {
|
290 |
|
291 | files.set(relativeFilePath, ['', mtime, size, 0, '', null]);
|
292 | }
|
293 |
|
294 | removedFiles.delete(relativeFilePath);
|
295 | });
|
296 | data.files = files;
|
297 | resolve({
|
298 | hasteMap: data,
|
299 | removedFiles
|
300 | });
|
301 | };
|
302 |
|
303 | if (useNativeFind) {
|
304 | findNative(roots, extensions, ignore, enableSymlinks, callback);
|
305 | } else {
|
306 | find(roots, extensions, ignore, enableSymlinks, callback);
|
307 | }
|
308 | });
|
309 | };
|