UNPKG

4.34 kBJavaScriptView Raw
1const FileSystem = require('fs');
2const Path = require('path');
3const Util = require('util');
4
5/**
6 * Returns a function that will wrap the given `nodeFunction`. Instead of taking a callback, the returned function will return a promise whose fate is decided by the callback behavior of the given node function. The node function should conform to node.js convention of accepting a callback as last argument and calling that callback with error as the first argument and success value on the second argument.
7 *
8 * @param {Function} nodeFunction
9 * @returns {Function}
10 */
11
12function promisify(nodeFunction) {
13 return function(...args) {
14 return new Promise((resolve, reject) => {
15 nodeFunction(...args, function(err, data) {
16 if(err) {
17 reject(err);
18 } else {
19 resolve(data);
20 }
21 })
22 });
23 };
24}
25
26const readDirAsync = promisify(FileSystem.readdir);
27const readDir = path => readDirAsync(path).then(entries => entries.map(e => Path.join(path, e)));
28const fileStat = promisify(FileSystem.stat);
29const fileAccess = promisify(FileSystem.access);
30const fileExists = file => fileAccess(file, FileSystem.F_OK);
31const readFile = promisify(FileSystem.readFile);
32const readText = file => readFile(file, {encoding: 'utf8'});
33
34async function filterAsync(array, callback) {
35 let results = await Promise.all(array.map(callback));
36 return array.filter((_,i) => results[i]);
37}
38
39function getFiles(dir) {
40 return readDir(dir).then(entries => filterAsync(entries, e => fileStat(e).then(s => s.isFile())));
41}
42
43
44function readDirR(dir) {
45 return FileSystem.statSync(dir).isDirectory()
46 ? Array.prototype.concat(...FileSystem.readdirSync(dir).map(f => readDirR(Path.join(dir, f))))
47 : dir;
48}
49
50
51function copyFile(source, target) {
52 return new Promise((resolve,reject) => {
53 const rd = FileSystem.createReadStream(source);
54 rd.on('error', err => reject(err));
55 const wr = FileSystem.createWriteStream(target);
56 wr.on('error', err => reject(err));
57 wr.on('close', () => resolve());
58 rd.pipe(wr);
59 });
60}
61
62
63function format(...args) {
64 if(args.length === 1 && Object.prototype.toString.call(args[0]) === '[object String]') {
65 return args[0];
66 }
67 return args.map(o => Util.inspect(o, {colors: true, depth: 3, showHidden: false})).join(' ');
68}
69
70function log(...args) {
71 return console.log(format(...args));
72}
73
74function splice(str, index, count, add) {
75 // We cannot pass negative indexes dirrectly to the 2nd slicing operation.
76 if (index < 0) {
77 index = str.length + index;
78 if (index < 0) {
79 index = 0;
80 }
81 }
82
83 return str.slice(0, index) + (add || "") + str.slice(index + count);
84}
85
86function mapToObject(array, callback) {
87 let result = Object.create(null);
88 for(let i = 0; i<array.length; ++i) {
89 let pair = callback(array[i], i);
90 result[pair[0]] = pair[1];
91 }
92 return result;
93}
94
95function isObject(obj) {
96 return obj !== null && typeof obj === 'object';
97}
98
99
100function isPlainObject(obj) {
101 return isObject(obj) && (
102 obj.constructor === Object // obj = {}
103 || obj.constructor === undefined // obj = Object.create(null)
104 );
105}
106
107function mergeDeep(target, ...sources) {
108 if (!sources.length) return target;
109 const source = sources.shift();
110
111 if(Array.isArray(target)) {
112 if(Array.isArray(source)) {
113 target.push(...source);
114 } else {
115 target.push(source);
116 }
117 } else if(isPlainObject(target)) {
118 if(isPlainObject(source)) {
119 for(let key of Object.keys(source)) {
120 if(!target[key]) {
121 target[key] = source[key];
122 } else {
123 mergeDeep(target[key], source[key]);
124 }
125 }
126 } else {
127 throw new Error(`Cannot merge object with non-object`);
128 }
129 } else {
130 target = source;
131 }
132
133 return mergeDeep(target, ...sources);
134}
135
136function forAll(array, callback) {
137 return Promise.all(array.map(callback));
138}
139
140Object.assign(exports, {readDir, fileStat, fileAccess, fileExists, promisify, mergeDeep, mapToObject, splice, log, copyFile, getFiles, readDirR, readText, forAll});
\No newline at end of file