UNPKG

bal-util

Version:

Common utility functions for Node.js used and maintained by Benjamin Lupton

482 lines (467 loc) 14.1 kB
// Generated by CoffeeScript 2.3.1 // Import var TaskGroup, balUtilFlow, balUtilPaths, eachr, extendr, extractOpts, ignorefs, pathUtil, safefs, scandir, typeChecker; pathUtil = require('path'); eachr = require('eachr'); typeChecker = require('typechecker'); extendr = require('extendr'); safefs = require('safefs'); extractOpts = require('extract-opts'); ({TaskGroup} = require('taskgroup')); balUtilFlow = require('./flow'); ignorefs = require('ignorefs'); scandir = require('scandirectory'); // Define balUtilPaths = { // ===================================== // Our Extensions // Resolve a Case Sensitive Path // next(err, result) resolveCaseSensitivePath: function(path, next) { var parentPath; // Resolve the parent path parentPath = safefs.getParentPathSync(path) || '/'; if (parentPath === '/') { return next(null, parentPath); } safefs.resolveCaseSensitivePath(parentPath, function(err, parentPath) { return safefs.readdir(parentPath, function(err, files) { var file, i, len, relativePathLowerCase; if (err) { return next(err); } relativePathLowerCase = relativePath.toLowerCase(); for (i = 0, len = files.length; i < len; i++) { file = files[i]; if (file.toLowerCase() === relativePathLowerCase) { return next(null, pathUtil.join(parentPath, relativePath)); } } err = new Error(`Could not find the path ${relativePath} inside ${parentPath}`); return next(err); }); }); // Chain return safefs; }, // Copy a file // Or rather overwrite a file, regardless of whether or not it was existing before // next(err) cp: function(src, dst, next) { // Copy safefs.readFile(src, 'binary', function(err, data) { if (err) { // Error return next(err); } // Success return safefs.writeFile(dst, data, 'binary', function(err) { // Forward return next(err); }); }); return this; }, // Prefix path prefixPathSync: function(path, parentPath) { path = path.replace(/[\/\\]$/, ''); if (/^([a-zA-Z]\:|\/)/.test(path) === false) { path = pathUtil.join(parentPath, path); } return path; }, // Is it a directory? // path can also be a stat object // next(err,isDirectory,fileStat) isDirectory: function(path, next) { // Check if path is a stat object if ((path != null ? path.isDirectory : void 0) != null) { return next(null, path.isDirectory(), path); } else { // Otherwise fetch the stat and do the check safefs.stat(path, function(err, stat) { if (err) { // Error return next(err); } // Success return next(null, stat.isDirectory(), stat); }); } return this; }, // Generate a slug for a file generateSlugSync: function(path) { var result; // Slugify result = path.replace(/[^a-zA-Z0-9]/g, '-').replace(/^-/, '').replace(/-+/, '-'); // Return return result; }, // Scan a directory into a list // next(err,list) scanlist: function(path, next) { // Handle scandir({ path: path, readFiles: true, ignoreHiddenFiles: true, next: function(err, list) { return next(err, list); } }); return this; }, // Scan a directory into a tree // next(err,tree) scantree: function(path, next) { // Handle scandir({ path: path, readFiles: true, ignoreHiddenFiles: true, next: function(err, list, tree) { return next(err, tree); } }); return this; }, // Copy a directory // If the same file already exists, we will keep the source one // Usage: // cpdir({srcPath,outPath,next}) // cpdir(srcPath,outPath,next) // Callbacks: // next(err) cpdir: function(...args) { var err, i, len, next, opt, opts, outPath, ref, scandirOpts, srcPath; // Prepare opts = {}; if (args.length === 1) { opts = args[0]; } else if (args.length >= 3) { [srcPath, outPath, next] = args; opts = {srcPath, outPath, next}; } else { err = new Error('balUtilPaths.cpdir: unknown arguments'); if (next) { return next(err); } else { throw err; } } // Create opts scandirOpts = { path: opts.srcPath, fileAction: function(fileSrcPath, fileRelativePath, next) { var fileOutPath; // Prepare fileOutPath = pathUtil.join(opts.outPath, fileRelativePath); // Ensure the directory that the file is going to exists return safefs.ensurePath(pathUtil.dirname(fileOutPath), function(err) { // Error if (err) { return next(err); } // The directory now does exist // So let's now place the file inside it return balUtilPaths.cp(fileSrcPath, fileOutPath, function(err) { // Forward return next(err); }); }); }, next: opts.next }; ref = ['ignorePaths', 'ignoreHiddenFiles', 'ignoreCommonPatterns', 'ignoreCustomPatterns']; // Passed Scandir Opts for (i = 0, len = ref.length; i < len; i++) { opt = ref[i]; scandirOpts[opt] = opts[opt]; } // Scan all the files in the diretory and copy them over asynchronously scandir(scandirOpts); return this; }, // Replace a directory // If the same file already exists, we will keep the newest one // Usage: // rpdir({srcPath,outPath,next}) // rpdir(srcPath,outPath,next) // Callbacks: // next(err) rpdir: function(...args) { var err, i, len, next, opt, opts, outPath, ref, scandirOpts, srcPath; // Prepare opts = {}; if (args.length === 1) { opts = args[0]; } else if (args.length >= 3) { [srcPath, outPath, next] = args; opts = {srcPath, outPath, next}; } else { err = new Error('balUtilPaths.cpdir: unknown arguments'); if (next) { return next(err); } else { throw err; } } // Create opts scandirOpts = { path: opts.srcPath, fileAction: function(fileSrcPath, fileRelativePath, next) { var fileOutPath; // Prepare fileOutPath = pathUtil.join(opts.outPath, fileRelativePath); // Ensure the directory that the file is going to exists return safefs.ensurePath(pathUtil.dirname(fileOutPath), function(err) { if (err) { // Error return next(err); } // Check if it is worthwhile copying that file return balUtilPaths.isPathOlderThan(fileOutPath, fileSrcPath, function(err, older) { // The src path has been modified since the out path was generated if (older === true || older === null) { // The directory now does exist // So let's now place the file inside it return balUtilPaths.cp(fileSrcPath, fileOutPath, function(err) { // Forward return next(err); }); } else { // The out path is new enough return next(); } }); }); }, next: opts.next }; ref = ['ignorePaths', 'ignoreHiddenFiles', 'ignoreCommonPatterns', 'ignoreCustomPatterns']; // Passed Scandir Opts for (i = 0, len = ref.length; i < len; i++) { opt = ref[i]; scandirOpts[opt] = opts[opt]; } // Scan all the files in the diretory and copy them over asynchronously scandir(scandirOpts); return this; }, // Write tree // next(err) writetree: function(dstPath, tree, next) { // Ensure Destination safefs.ensurePath(dstPath, function(err) { var tasks; if (err) { // Checks return next(err); } // Group tasks = new TaskGroup({ concurrency: 0 }).done(next); // Cycle eachr(tree, function(value, fileRelativePath) { return tasks.addTask(function(complete) { var fileFullPath; fileFullPath = pathUtil.join(dstPath, fileRelativePath.replace(/^\/+/, '')); if (typeChecker.isObject(value)) { return balUtilPaths.writetree(fileFullPath, value, complete); } else { return safefs.writeFile(fileFullPath, value, complete); } }); }); // Run the tasks return tasks.run(); }); return this; }, // Read path // Reads a path be it local or remote // next(err,data) readPath: function(filePath, opts, next) { var base, base1, err, http, ref, req, requestOpts, zlib; [opts, next] = extractOpts(opts, next); // Request if (/^http/.test(filePath)) { // Zlib zlib = null; try { zlib = require('zlib'); } catch (error) { err = error; } // do nothing // Options requestOpts = require('url').parse(filePath); if (requestOpts.path == null) { requestOpts.path = requestOpts.pathname; } if (requestOpts.method == null) { requestOpts.method = 'GET'; } if (requestOpts.headers == null) { requestOpts.headers = {}; } if (zlib) { if ((base = requestOpts.headers)['accept-encoding'] == null) { base['accept-encoding'] = 'gzip,deflate'; } } if ((base1 = requestOpts.headers)['user-agent'] == null) { base1['user-agent'] = 'Wget/1.14 (linux-gnu)'; } // Prepare request http = requestOpts.protocol === 'https:' ? require('https') : require('http'); req = http.request(requestOpts); if (req.setTimeout == null) { req.setTimeout = function(delay) { var onTimeout; onTimeout = function() { return req.emit('error', new Error('request timed out')); }; return setTimeout(onTimeout, delay); // alias for node <=0.9 }; } req.setTimeout((ref = opts.timeout) != null ? ref : 10 * 1000); // 10 second timeout req.once('error', next); req.once('timeout', function() { return req.abort(); // must abort manually, will trigger error event }); req.once('response', function(res) { var chunks, locationHeader, ref1; locationHeader = ((ref1 = res.headers) != null ? ref1.location : void 0) || null; if (locationHeader && locationHeader !== requestOpts.href) { req.removeAllListeners(); balUtilPaths.readPath(locationHeader, opts, next); return; } chunks = []; res.on('data', function(chunk) { return chunks.push(chunk); }); return res.once('end', function() { var data; data = new Buffer.concat(chunks); switch (res.headers['content-encoding']) { case 'gzip': zlib.unzip(data, next); break; case 'deflate': zlib.inflate(data, next); break; default: return next(null, data); } }); }); // End request, start response req.end(); } else { // Local safefs.readFile(filePath, function(err, data) { if (err) { return next(err); } return next(null, data); }); } return this; }, // Empty // Check if the file does not exist, or is empty // next(err,empty) empty: function(filePath, next) { // Check if we exist safefs.exists(filePath, function(exists) { if (!exists) { // Return empty if we don't exist return next(null, true); } // We do exist, so check if we have content return safefs.stat(filePath, function(err, stat) { if (err) { // Check return next(err); } // Return whether or not we are actually empty return next(null, stat.size === 0); }); }); return this; }, // Is Path Older Than // Checks if a path is older than a particular amount of millesconds // next(err,older) // older will be null if the path does not exist isPathOlderThan: function(aPath, bInput, next) { var bMtime, bPath, mode; // Handle mtime bMtime = null; if (typeChecker.isNumber(bInput)) { mode = 'time'; bMtime = new Date(new Date() - bInput); } else { mode = 'path'; bPath = bInput; } // Check if the path exists balUtilPaths.empty(aPath, function(err, empty) { if (empty || err) { // If it doesn't then we should return right away return next(err, null); } // We do exist, so let's check how old we are return safefs.stat(aPath, function(err, aStat) { var compare; if (err) { // Check return next(err); } // Prepare compare = function() { var older; // Time comparison if (aStat.mtime < bMtime) { older = true; } else { older = false; } // Return result return next(null, older); }; // Perform the comparison if (mode === 'path') { // Check if the bPath exists return balUtilPaths.empty(bPath, function(err, empty) { if (empty || err) { // Return result if we are empty return next(err, null); } // It does exist so lets get the stat return safefs.stat(bPath, function(err, bStat) { if (err) { // Check return next(err); } // Assign the outer bMtime variable bMtime = bStat.mtime; // Perform the comparison return compare(); }); }); } else { // We already have the bMtime return compare(); } }); }); return this; } }; // Export module.exports = balUtilPaths;