index.js (5813B)
1 #!/usr/bin/env node 2 3 // External modules 4 var node_path = require('path'); 5 var node_fs = require('fs'); 6 var _ = require('lodash'); 7 var iconv = require('iconv-lite'); 8 var rimraf = require('rimraf'); 9 10 11 var sync = module.exports = {}; 12 13 // explode built-in fs methods to `fs-more` 14 // sync.__proto__ = node_fs; 15 16 17 // Process specified wildcard glob patterns or filenames against a 18 // callback, excluding and uniquing files in the result set. 19 function processPatterns(patterns, fn) { 20 21 // Filepaths to return. 22 var result = []; 23 // Iterate over flattened patterns array. 24 _.flattenDeep(patterns).forEach(function(pattern) { 25 // If the first character is ! it should be omitted 26 var exclusion = pattern.indexOf('!') === 0; 27 // If the pattern is an exclusion, remove the ! 28 if (exclusion) { 29 pattern = pattern.slice(1); 30 } 31 // Find all matching files for this pattern. 32 var matches = fn(pattern); 33 34 if (exclusion) { 35 // If an exclusion, remove matching files. 36 result = _.difference(result, matches); 37 } else { 38 // Otherwise add matching files. 39 result = _.union(result, matches); 40 } 41 }); 42 43 return result; 44 }; 45 46 // Are descendant path(s) contained within ancestor path? Note: does not test 47 // if paths actually exist. 48 sync.doesPathContain = function(ancestor) { 49 ancestor = node_path.resolve(ancestor); 50 51 var relative; 52 var i = 1; 53 54 for (; i < arguments.length; i++) { 55 relative = node_path.relative(node_path.resolve(arguments[i]), ancestor); 56 if (relative === '' || /\w+/.test(relative)) { 57 return false; 58 } 59 } 60 61 return true; 62 }; 63 64 // @param {Object} options { 65 // force: {boolean} force to overridding 66 // } 67 sync.copy = function(file, dest, options) { 68 if (!options) { 69 options = {}; 70 } 71 72 // Just set encoding as `null` to force the file to R/W as a `Buffer` 73 options.encoding = null; 74 75 // 'abc/' -> '/xxxx/xxx/abc' 76 // 'abc.js' -> '/xxx/xxx/abc.js' 77 file = node_path.resolve(file); 78 79 if (sync.isFile(file)) { 80 var content = sync.read(file, options); 81 82 if (options.force || !sync.exists(dest)) { 83 return sync.write(dest, content, options); 84 } 85 86 return false; 87 88 } else if (sync.isDir(file)) { 89 90 var dir = file; 91 dest = node_path.resolve(dest); 92 93 sync.expand('**', { 94 95 // to get relative paths to dir 96 cwd: dir 97 98 }).forEach(function(path) { 99 var full_path = node_path.join(dir, path); 100 101 if (sync.isFile(full_path)) { 102 sync.copy(full_path, node_path.join(dest, path), options); 103 } 104 }); 105 } 106 }; 107 108 var glob = require('glob'); 109 110 // Return an array of all file paths that match the given wildcard patterns. 111 sync.expand = function(patterns, options) { 112 113 // Use the first argument if it's an Array, otherwise convert the arguments 114 // object to an array and use that. 115 patterns = Array.isArray(patterns) ? patterns : [patterns]; 116 117 return patterns.length === 0 ? [] : 118 119 processPatterns(patterns, function(pattern) { 120 121 // Find all matching files for this pattern. 122 return glob.sync(pattern, options); 123 }); 124 }; 125 126 var exists = node_fs.existsSync ? 127 function(file) { 128 return node_fs.existsSync(file); 129 } : 130 131 // if node -v <= 0.6, there's no fs.existsSync method. 132 function(file) { 133 try { 134 node_fs.statSync(file); 135 return true; 136 } catch (e) { 137 return false; 138 } 139 }; 140 141 142 // @returns {boolean} true if the file path exists. 143 sync.exists = function() { 144 var filepath = node_path.join.apply(node_path, arguments); 145 return exists(filepath); 146 }; 147 148 149 //@returns true if the file is a symbolic link. 150 sync.isLink = function() { 151 var filepath = node_path.join.apply(node_path, arguments); 152 return exists(filepath) && node_fs.lstatSync(filepath).isSymbolicLink(); 153 }; 154 155 // @returns {boolean} true if the path is a directory. 156 sync.isDir = function() { 157 var filepath = node_path.join.apply(node_path, arguments); 158 return exists(filepath) && node_fs.statSync(filepath).isDirectory(); 159 }; 160 161 // @returns {boolean} true if the path is a file. 162 sync.isFile = function() { 163 var filepath = node_path.join.apply(node_path, arguments); 164 return exists(filepath) && node_fs.statSync(filepath).isFile(); 165 }; 166 167 sync.isPathAbsolute = function() { 168 var filepath = node_path.join.apply(node_path, arguments); 169 return node_path.resolve(filepath) === filepath.replace(/[\/\\]+$/, ''); 170 }; 171 172 var mkdirp = require('mkdirp'); 173 174 sync.mkdir = mkdirp.sync; 175 176 sync.defaultEncoding = 'utf-8'; 177 178 sync.read = function(filepath, options) { 179 if (!options) { 180 options = {}; 181 } 182 183 var contents; 184 185 contents = node_fs.readFileSync(filepath, options); 186 // If encoding is not explicitly null, convert from encoded buffer to a 187 // string. If no encoding was specified, use the default. 188 if (options.encoding !== null) { 189 contents = iconv.decode(contents, options.encoding || sync.defaultEncoding); 190 // Strip any BOM that might exist. 191 if (contents.charCodeAt(0) === 0xFEFF) { 192 contents = contents.substring(1); 193 } 194 } 195 196 return contents; 197 }; 198 199 200 sync.readJSON = function(filepath, options) { 201 var src = sync.read(filepath, options); 202 return JSON.parse(src); 203 }; 204 205 // Delete folders and files recursively 206 sync.remove = function(filepath) { 207 filepath = String(filepath); 208 209 if (!sync.exists(filepath)) { 210 return false; 211 } 212 213 rimraf.sync(filepath); 214 215 return true; 216 }; 217 218 // Write a file. 219 sync.write = function(filepath, contents, options) { 220 if (!options) { 221 options = {}; 222 } 223 224 // Create path, if necessary. 225 sync.mkdir(node_path.dirname(filepath)); 226 227 // If contents is already a Buffer, don't try to encode it. If no encoding 228 // was specified, use the default. 229 if (!Buffer.isBuffer(contents)) { 230 contents = iconv.encode(contents, options.encoding || sync.defaultEncoding); 231 } 232 233 node_fs.writeFileSync(filepath, contents, options); 234 235 return true; 236 ```