UNPKG

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