| 67 | let activeCalls = 0; |
| 68 | |
| 69 | function search(directory: string): void { |
| 70 | activeCalls++; |
| 71 | fs.readdir(directory, {withFileTypes: true}, (err, entries) => { |
| 72 | activeCalls--; |
| 73 | if (err) { |
| 74 | if (activeCalls === 0) { |
| 75 | callback(result); |
| 76 | } |
| 77 | return; |
| 78 | } |
| 79 | for (const entry of entries) { |
| 80 | const file = path.join(directory, entry.name); |
| 81 | |
| 82 | if (ignore(file)) { |
| 83 | continue; |
| 84 | } |
| 85 | |
| 86 | if (entry.isSymbolicLink()) { |
| 87 | continue; |
| 88 | } |
| 89 | if (entry.isDirectory()) { |
| 90 | search(file); |
| 91 | continue; |
| 92 | } |
| 93 | |
| 94 | activeCalls++; |
| 95 | |
| 96 | const stat = enableSymlinks ? fs.stat : fs.lstat; |
| 97 | |
| 98 | stat(file, (err, stat) => { |
| 99 | activeCalls--; |
| 100 | |
| 101 | // This logic is unnecessary for node > v10.10, but leaving it in |
| 102 | // since we need it for backwards-compatibility still. |
| 103 | if (!err && stat && !stat.isSymbolicLink()) { |
| 104 | if (stat.isDirectory()) { |
| 105 | search(file); |
| 106 | } else { |
| 107 | const ext = path.extname(file).slice(1); |
| 108 | if (extensions.includes(ext)) { |
| 109 | result.push([file, stat.mtime.getTime(), stat.size]); |
| 110 | } |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | if (activeCalls === 0) { |
| 115 | callback(result); |
| 116 | } |
| 117 | }); |
| 118 | } |
| 119 | |
| 120 | if (activeCalls === 0) { |
| 121 | callback(result); |
| 122 | } |
| 123 | }); |
| 124 | } |
| 125 | |
| 126 | if (roots.length > 0) { |