UNPKG

4.35 kBJavaScriptView Raw
1/**
2 * @copyright Copyright (c) 2019 Maxim Khorin <maksimovichu@gmail.com>
3 */
4'use strict';
5
6module.exports = class FileHelper {
7
8 static getBasename (file) {
9 return path.basename(file, path.extname(file));
10 }
11
12 static getRelativePathByDirectory (name, file) {
13 const basePath = this.getClosestDirectory(name, file);
14 return basePath ? this.getRelativePath(basePath, file) : file;
15 }
16
17 static getRelativePath (basePath, file) {
18 return file.indexOf(basePath) === 0 ? file.substring(basePath.length + 1) : file;
19 }
20
21 static trimExtension (file) {
22 return file.substring(0, file.length - path.extname(file).length);
23 }
24
25 static getStat (file) {
26 return new Promise(resolve => fs.stat(file, (err, stat) => resolve(err ? null : stat)));
27 }
28
29 static async delete (file) {
30 const stat = await this.getStat(file);
31 if (!stat) {
32 return false; // skip non-existent
33 }
34 if (stat.isFile()) {
35 return fs.promises.unlink(file);
36 }
37 await PromiseHelper.setImmediate(); // flush calling stack
38 await this.handleChildren(file, child => this.delete(path.join(file, child)));
39 return fs.promises.rmdir(file);
40 }
41
42 static async copy (source, target, flags) {
43 const stat = await fs.promises.stat(source);
44 if (stat.isFile()) {
45 await this.createDirectory(path.dirname(target), {mode: stat.mode});
46 return fs.promises.copyFile(source, target, flags);
47 }
48 await this.createDirectory(target, {mode: stat.mode});
49 await PromiseHelper.setImmediate(); // flush calling stack
50 await this.handleChildren(source, file => {
51 return this.copy(path.join(source, file), path.join(target, file), flags);
52 });
53 }
54
55 static async copyChildren (source, target, flags) {
56 const stat = await fs.promises.stat(source);
57 if (stat.isDirectory()) {
58 await this.handleChildren(source, file => {
59 return this.copy(path.join(source, file), path.join(target, file), flags);
60 });
61 }
62 }
63
64 // DIRECTORY
65
66 static readDirectory (dir) {
67 return new Promise(resolve => fs.readdir(dir, (err, result) => resolve(err ? [] : result)));
68 }
69
70 static createDirectory (dir, options) {
71 return fs.promises.mkdir(dir, {
72 recursive: true,
73 ...options
74 });
75 }
76
77 static emptyDirectory (dir) {
78 return this.handleChildren(dir, file => this.delete(path.join(dir, file)));
79 }
80
81 static getClosestDirectory (name, dir) {
82 let base = path.basename(dir);
83 while (base) {
84 if (base === name) {
85 return dir;
86 }
87 base = path.dirname(dir);
88 if (base === dir) {
89 break; // break root repeating
90 }
91 dir = base;
92 base = path.basename(dir);
93 }
94 }
95
96 // JSON
97
98 static isJsonExtension (file) {
99 return path.extname(file).toLowerCase() === '.json';
100 }
101
102 static async readJsonFile (file) {
103 return JSON.parse(await fs.promises.readFile(file));
104 }
105
106 static filterJsonFiles (files) {
107 return files.filter(this.isJsonExtension, this);
108 }
109
110 // HANDLER
111
112 static handleChildDirectories (dir, handler) {
113 return this.handleChildren(dir, async file => {
114 const stat = await fs.promises.stat(path.join(dir, file));
115 if (stat.isDirectory()) {
116 await handler(file, dir, stat);
117 }
118 });
119 }
120
121 static handleChildFiles (dir, handler) {
122 return this.handleChildren(dir, async file => {
123 const stat = await fs.promises.stat(path.join(dir, file));
124 if (stat.isFile()) {
125 await handler(file, dir, stat);
126 }
127 });
128 }
129
130 static async handleChildren (dir, handler) {
131 const files = await fs.promises.readdir(dir);
132 for (const file of files) {
133 await handler(file, dir);
134 }
135 }
136};
137
138const fs = require('fs');
139const path = require('path');
140const PromiseHelper = require('./PromiseHelper');
\No newline at end of file