UNPKG

6.87 kBJavaScriptView Raw
1"use strict";
2
3
4module.exports = {
5 findFilesByExtension,
6 findFiles,
7 addPrefix,
8 mkdir,
9 rmdir,
10 file,
11 isDirectory,
12 isNewer,
13 touch,
14 size
15};
16
17const FS = require( "fs" ),
18 Path = require( "path" );
19
20const BYTES_TO_KB = 0.001;
21
22/**
23 * @param {string} root Root folder in which we will search.
24 * @param {rx|array} _filters If it is not an array, it is considered
25 * as an array with only one element. In the array, the last element
26 * is the regexp of a file to match, the other elements are regexp for
27 * containing folders.
28 * If filter is missing, return all files in `root`.
29 * @param {number} index Used internally for recursion purpose.
30 *
31 * @return {array} Array of full pathes of found files.
32 */
33function findFiles( root, _filters, index = 0 ) {
34 if ( !FS.existsSync( root ) ) return [];
35 if ( !isDirectory( root ) ) return [];
36
37 const filters = Array.isArray( _filters ) ? _filters : [_filters];
38 if ( index >= filters.length ) return [];
39
40 let files = [];
41 if ( filters.length > index + 1 ) {
42 // Looking for directories.
43 const filter = filters[ index ];
44 FS.readdirSync( root ).forEach(function ( filename ) {
45 if ( isDirectory( Path.join( root, filename ) ) ) {
46 if ( !filters || !filter || filter.test( filename ) ) {
47 files = files.concat(findFiles( Path.join( root, filename ), filters, index + 1 ));
48 }
49 }
50 });
51 } else {
52 // Looking for files.
53 const filter = filters[ index ];
54 FS.readdirSync( root ).forEach(function ( filename ) {
55 if ( isDirectory( Path.join( root, filename ) ) ) return;
56 if ( !filters || !filter || filter.test( filename ) ) {
57 files.push(Path.join( root, filename ));
58 }
59 });
60 }
61 return files;
62}
63
64function findFilesByExtension( root, ext ) {
65 const files = [],
66 fringe = [ root ];
67
68 while ( fringe.length > 0 ) {
69 const path = fringe.pop();
70 if ( FS.existsSync( path ) ) {
71 const subfiles = FS.readdirSync( path );
72 for( const filename of subfiles ) {
73 const f = Path.join( path, filename );
74 const stat = FS.statSync( f );
75 if ( !stat.isFile() ) {
76 fringe.push( f );
77 } else if ( filename.substr( -ext.length ) === ext ) {
78 files.push( f );
79 }
80 }
81 }
82 }
83 return files;
84}
85
86
87function addPrefix( path, prefix ) {
88 return Path.join(
89 Path.dirname( path ),
90 prefix + Path.basename( path )
91 ).split( Path.sep ).join( "/" );
92}
93
94function isDirectory( path ) {
95 if ( !FS.existsSync( path ) ) return false;
96 const stat = FS.statSync( path );
97 return stat.isDirectory();
98}
99
100function mkdir( ...pathes ) {
101 const path = Path.resolve( ...pathes );
102 let curPath = "";
103 const items = path.replace( /\\/gu, '/' ).split( "/" );
104 for ( let i = 0; i < items.length; i++ ) {
105 const item = items[ i ];
106 curPath += `${item}/`;
107 if ( FS.existsSync( curPath ) ) {
108 const stat = FS.statSync( curPath );
109 if ( !stat.isDirectory() ) {
110 break;
111 }
112 } else {
113 try {
114 if ( curPath !== '.' ) {
115 FS.mkdirSync( curPath );
116 }
117 } catch ( ex ) {
118 throw Error(`Unable to create directory "${curPath}"!\n${ex}`);
119 }
120 }
121 }
122 return path;
123}
124
125function rmdir( path ) {
126 if ( !FS.existsSync( path ) ) return false;
127 const stat = FS.statSync( path );
128 if ( stat.isDirectory() ) {
129 FS.readdirSync( path ).forEach(function ( filename ) {
130 const fullpath = Path.join( path, filename );
131 try {
132 rmdir( fullpath );
133 } catch ( ex ) {
134 console.error( `Unable to remove directory "${fullpath.redBG.white}"!` );
135 console.error( String(ex).red );
136 }
137 });
138 try {
139 FS.rmdirSync( path );
140 } catch ( err ) {
141 console.error( `Unable to remove directory '${path}'!` );
142 console.error( err );
143 }
144 } else {
145 try {
146 FS.unlinkSync( path );
147 } catch ( err ) {
148 console.error( `Unable to delete file '${path}'!` );
149 console.error( err );
150 }
151 }
152 return true;
153}
154
155/**
156 * Read or write the content of a file.
157 *
158 * If `content` is undefined, the content is read, otherwise it is
159 * written.
160 * If the file to be written is in a non-existent subfolder, the whole
161 * path will be created with the `mkdir`function.
162 *
163 * @param {string} path - Path of the file to read or write.
164 * @param {string} content - Optional. If omitted, we return the content of the file.
165 * Otherwise, we save this content to the file.
166 * @returns {string} The file content.
167 */
168function file( path, content ) {
169 try {
170 if ( typeof content === 'undefined' ) {
171 if ( !FS.existsSync( path ) ) return null;
172 return FS.readFileSync( path );
173 }
174 const dir = Path.dirname( path );
175 mkdir( dir );
176 FS.writeFileSync( path, content );
177 return content;
178 } catch ( ex ) {
179 console.warn( "content:", content );
180 throw new Error( `${ex}\n...in pathutils/file("${path}", ${typeof content})` );
181 }
182}
183
184/**
185 * @param {string} sourcePath - Full path.
186 * @param {string} referencePath - Full path.
187 * @return {boolean} `true` if `sourcePath` exists and is more recent than `referencePath`,
188 * `true` if `referencePath` does not exist,
189 * `false` otherwise.
190 */
191function isNewer( sourcePath, referencePath ) {
192 if ( !FS.existsSync( referencePath ) ) return true;
193 if ( !FS.existsSync( sourcePath ) ) return false;
194 const statSrc = FS.statSync( sourcePath );
195 const statRef = FS.statSync( referencePath );
196 const timeSrc = statSrc.mtime.getTime();
197 const timeRef = statRef.mtime.getTime();
198 return timeSrc > timeRef;
199}
200
201/**
202 * Set current date as modification time to a file.
203 *
204 * @param {string} path - Path of the file to touch.
205 * @returns {boolean} `true` is the file exists.
206 */
207function touch( path ) {
208 if ( FS.existsSync( path ) ) {
209 const content = FS.readFileSync( path );
210 FS.writeFileSync( path, content );
211 console.log( `File has been touched: ${path.yellow} (${(size(path) * BYTES_TO_KB).toFixed(1)} kb)` );
212 return true;
213 }
214 return false;
215}
216
217
218/**
219 * @param {string} path - Path of the file we want to know the size.
220 * @returns {int} Size in bytes.
221 */
222function size( path ) {
223 if( !FS.existsSync( path ) ) return 0;
224
225 const stat = FS.statSync( path );
226 return stat.size;
227}