| /** | 
|  * archiver-utils | 
|  * | 
|  * Copyright (c) 2012-2014 Chris Talkington, contributors. | 
|  * Licensed under the MIT license. | 
|  * https://github.com/archiverjs/node-archiver/blob/master/LICENSE-MIT | 
|  */ | 
| var fs = require('graceful-fs'); | 
| var path = require('path'); | 
|   | 
| var flatten = require('lodash.flatten'); | 
| var difference = require('lodash.difference'); | 
| var union = require('lodash.union'); | 
| var isPlainObject = require('lodash.isplainobject'); | 
|   | 
| var glob = require('glob'); | 
|   | 
| var file = module.exports = {}; | 
|   | 
| var pathSeparatorRe = /[\/\\]/g; | 
|   | 
| // Process specified wildcard glob patterns or filenames against a | 
| // callback, excluding and uniquing files in the result set. | 
| var processPatterns = function(patterns, fn) { | 
|   // Filepaths to return. | 
|   var result = []; | 
|   // Iterate over flattened patterns array. | 
|   flatten(patterns).forEach(function(pattern) { | 
|     // If the first character is ! it should be omitted | 
|     var exclusion = pattern.indexOf('!') === 0; | 
|     // If the pattern is an exclusion, remove the ! | 
|     if (exclusion) { pattern = pattern.slice(1); } | 
|     // Find all matching files for this pattern. | 
|     var matches = fn(pattern); | 
|     if (exclusion) { | 
|       // If an exclusion, remove matching files. | 
|       result = difference(result, matches); | 
|     } else { | 
|       // Otherwise add matching files. | 
|       result = union(result, matches); | 
|     } | 
|   }); | 
|   return result; | 
| }; | 
|   | 
| // True if the file path exists. | 
| file.exists = function() { | 
|   var filepath = path.join.apply(path, arguments); | 
|   return fs.existsSync(filepath); | 
| }; | 
|   | 
| // Return an array of all file paths that match the given wildcard patterns. | 
| file.expand = function(...args) { | 
|   // If the first argument is an options object, save those options to pass | 
|   // into the File.prototype.glob.sync method. | 
|   var options = isPlainObject(args[0]) ? args.shift() : {}; | 
|   // Use the first argument if it's an Array, otherwise convert the arguments | 
|   // object to an array and use that. | 
|   var patterns = Array.isArray(args[0]) ? args[0] : args; | 
|   // Return empty set if there are no patterns or filepaths. | 
|   if (patterns.length === 0) { return []; } | 
|   // Return all matching filepaths. | 
|   var matches = processPatterns(patterns, function(pattern) { | 
|     // Find all matching files for this pattern. | 
|     return glob.sync(pattern, options); | 
|   }); | 
|   // Filter result set? | 
|   if (options.filter) { | 
|     matches = matches.filter(function(filepath) { | 
|       filepath = path.join(options.cwd || '', filepath); | 
|       try { | 
|         if (typeof options.filter === 'function') { | 
|           return options.filter(filepath); | 
|         } else { | 
|           // If the file is of the right type and exists, this should work. | 
|           return fs.statSync(filepath)[options.filter](); | 
|         } | 
|       } catch(e) { | 
|         // Otherwise, it's probably not the right type. | 
|         return false; | 
|       } | 
|     }); | 
|   } | 
|   return matches; | 
| }; | 
|   | 
| // Build a multi task "files" object dynamically. | 
| file.expandMapping = function(patterns, destBase, options) { | 
|   options = Object.assign({ | 
|     rename: function(destBase, destPath) { | 
|       return path.join(destBase || '', destPath); | 
|     } | 
|   }, options); | 
|   var files = []; | 
|   var fileByDest = {}; | 
|   // Find all files matching pattern, using passed-in options. | 
|   file.expand(options, patterns).forEach(function(src) { | 
|     var destPath = src; | 
|     // Flatten? | 
|     if (options.flatten) { | 
|       destPath = path.basename(destPath); | 
|     } | 
|     // Change the extension? | 
|     if (options.ext) { | 
|       destPath = destPath.replace(/(\.[^\/]*)?$/, options.ext); | 
|     } | 
|     // Generate destination filename. | 
|     var dest = options.rename(destBase, destPath, options); | 
|     // Prepend cwd to src path if necessary. | 
|     if (options.cwd) { src = path.join(options.cwd, src); } | 
|     // Normalize filepaths to be unix-style. | 
|     dest = dest.replace(pathSeparatorRe, '/'); | 
|     src = src.replace(pathSeparatorRe, '/'); | 
|     // Map correct src path to dest path. | 
|     if (fileByDest[dest]) { | 
|       // If dest already exists, push this src onto that dest's src array. | 
|       fileByDest[dest].src.push(src); | 
|     } else { | 
|       // Otherwise create a new src-dest file mapping object. | 
|       files.push({ | 
|         src: [src], | 
|         dest: dest, | 
|       }); | 
|       // And store a reference for later use. | 
|       fileByDest[dest] = files[files.length - 1]; | 
|     } | 
|   }); | 
|   return files; | 
| }; | 
|   | 
| // reusing bits of grunt's multi-task source normalization | 
| file.normalizeFilesArray = function(data) { | 
|   var files = []; | 
|   | 
|   data.forEach(function(obj) { | 
|     var prop; | 
|     if ('src' in obj || 'dest' in obj) { | 
|       files.push(obj); | 
|     } | 
|   }); | 
|   | 
|   if (files.length === 0) { | 
|     return []; | 
|   } | 
|   | 
|   files = _(files).chain().forEach(function(obj) { | 
|     if (!('src' in obj) || !obj.src) { return; } | 
|     // Normalize .src properties to flattened array. | 
|     if (Array.isArray(obj.src)) { | 
|       obj.src = flatten(obj.src); | 
|     } else { | 
|       obj.src = [obj.src]; | 
|     } | 
|   }).map(function(obj) { | 
|     // Build options object, removing unwanted properties. | 
|     var expandOptions = Object.assign({}, obj); | 
|     delete expandOptions.src; | 
|     delete expandOptions.dest; | 
|   | 
|     // Expand file mappings. | 
|     if (obj.expand) { | 
|       return file.expandMapping(obj.src, obj.dest, expandOptions).map(function(mapObj) { | 
|         // Copy obj properties to result. | 
|         var result = Object.assign({}, obj); | 
|         // Make a clone of the orig obj available. | 
|         result.orig = Object.assign({}, obj); | 
|         // Set .src and .dest, processing both as templates. | 
|         result.src = mapObj.src; | 
|         result.dest = mapObj.dest; | 
|         // Remove unwanted properties. | 
|         ['expand', 'cwd', 'flatten', 'rename', 'ext'].forEach(function(prop) { | 
|           delete result[prop]; | 
|         }); | 
|         return result; | 
|       }); | 
|     } | 
|   | 
|     // Copy obj properties to result, adding an .orig property. | 
|     var result = Object.assign({}, obj); | 
|     // Make a clone of the orig obj available. | 
|     result.orig = Object.assign({}, obj); | 
|   | 
|     if ('src' in result) { | 
|       // Expose an expand-on-demand getter method as .src. | 
|       Object.defineProperty(result, 'src', { | 
|         enumerable: true, | 
|         get: function fn() { | 
|           var src; | 
|           if (!('result' in fn)) { | 
|             src = obj.src; | 
|             // If src is an array, flatten it. Otherwise, make it into an array. | 
|             src = Array.isArray(src) ? flatten(src) : [src]; | 
|             // Expand src files, memoizing result. | 
|             fn.result = file.expand(expandOptions, src); | 
|           } | 
|           return fn.result; | 
|         } | 
|       }); | 
|     } | 
|   | 
|     if ('dest' in result) { | 
|       result.dest = obj.dest; | 
|     } | 
|   | 
|     return result; | 
|   }).flatten().value(); | 
|   | 
|   return files; | 
| }; |