UNPKG

3.19 kBPlain TextView Raw
1import path from 'path';
2import fs from 'fs';
3import { promisify } from 'util';
4
5import rimraf from 'rimraf';
6import { isErrnoException } from '@stryker-mutator/util';
7
8export const fileUtils = {
9 deleteDir: promisify(rimraf),
10
11 async cleanFolder(folderName: string): Promise<string | undefined> {
12 try {
13 await fs.promises.lstat(folderName);
14 await this.deleteDir(folderName);
15 return fs.promises.mkdir(folderName, { recursive: true });
16 } catch (e) {
17 return fs.promises.mkdir(folderName, { recursive: true });
18 }
19 },
20
21 async exists(fileName: string): Promise<boolean> {
22 try {
23 await fs.promises.stat(fileName);
24 return true;
25 } catch (err) {
26 if (isErrnoException(err) && err.code === 'ENOENT') {
27 return false;
28 } else {
29 // Oops, didn't mean to catch this one ⚾
30 throw err;
31 }
32 }
33 },
34
35 /**
36 * Wrapper around the 'import' expression (for testability)
37 */
38 importModule(moduleName: string): Promise<unknown> {
39 return import(moduleName);
40 },
41
42 /**
43 * Recursively walks the from directory and copy the content to the target directory synchronously
44 * @param from The source directory to move from
45 * @param to The target directory to move to
46 */
47 moveDirectoryRecursiveSync(from: string, to: string): void {
48 if (!fs.existsSync(from)) {
49 return;
50 }
51 if (!fs.existsSync(to)) {
52 fs.mkdirSync(to);
53 }
54 const files = fs.readdirSync(from);
55 for (const file of files) {
56 const fromFileName = path.join(from, file);
57 const toFileName = path.join(to, file);
58 const stats = fs.lstatSync(fromFileName);
59 if (stats.isFile()) {
60 fs.renameSync(fromFileName, toFileName);
61 } else {
62 this.moveDirectoryRecursiveSync(fromFileName, toFileName);
63 }
64 }
65 fs.rmdirSync(from);
66 },
67
68 /**
69 * Creates a symlink at `from` that points to `to`
70 * @param to The thing you want to point to
71 * @param from The thing you want to point from
72 */
73 async symlinkJunction(to: string, from: string): Promise<void> {
74 await fs.promises.mkdir(path.dirname(from), { recursive: true });
75 return fs.promises.symlink(to, from, 'junction');
76 },
77
78 /**
79 * Looks for the node_modules folder from basePath up to root.
80 * returns the first occurrence of the node_modules, or null of none could be found.
81 * @param basePath starting point
82 */
83 async findNodeModulesList(basePath: string, tempDirName?: string): Promise<string[]> {
84 const nodeModulesList: string[] = [];
85 const dirBfsQueue: string[] = ['.'] ?? [];
86
87 let dir: string | undefined;
88 while ((dir = dirBfsQueue.pop())) {
89 if (path.basename(dir) === tempDirName) {
90 continue;
91 }
92
93 if (path.basename(dir) === 'node_modules') {
94 nodeModulesList.push(dir);
95 continue;
96 }
97
98 const parentDir = dir;
99 const filesWithType = await fs.promises.readdir(path.join(basePath, dir), { withFileTypes: true });
100 const dirs = filesWithType.filter((file) => file.isDirectory()).map((childDir) => path.join(parentDir, childDir.name));
101 dirBfsQueue.push(...dirs);
102 }
103
104 return nodeModulesList;
105 },
106};