readfiles.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. var fs = require('fs'),
  2. path = require('path');
  3. /**
  4. * merge two objects by extending target object with source object
  5. * @param target object to merge
  6. * @param source object to merge
  7. * @param {Boolean} [modify] whether to modify the target
  8. * @returns {Object} extended object
  9. */
  10. function extend(target, source, modify) {
  11. var result = target ? modify ? target : extend({}, target, true) : {};
  12. if (!source) return result;
  13. for (var key in source) {
  14. if (source.hasOwnProperty(key) && source[key] !== undefined) {
  15. result[key] = source[key];
  16. }
  17. }
  18. return result;
  19. }
  20. /**
  21. * determine if a string is contained within an array or matches a regular expression
  22. * @param {String} str string to match
  23. * @param {Array|Regex} match array or regular expression to match against
  24. * @returns {Boolean} whether there is a match
  25. */
  26. function matches(str, match) {
  27. if (Array.isArray(match)) return match.indexOf(str) > -1;
  28. return match.test(str);
  29. }
  30. /**
  31. * read files and call a function with the contents of each file
  32. * @param {String} dir path of dir containing the files to be read
  33. * @param {String} encoding file encoding (default is 'utf8')
  34. * @param {Object} options options hash for encoding, recursive, and match/exclude
  35. * @param {Function(error, string)} callback callback for each files content
  36. * @param {Function(error)} complete fn to call when finished
  37. */
  38. function readFiles(dir, options, callback, complete) {
  39. if (typeof options === 'function') {
  40. complete = callback;
  41. callback = options;
  42. options = {};
  43. }
  44. if (typeof options === 'string') options = {
  45. encoding: options
  46. };
  47. options = extend({
  48. recursive: true,
  49. encoding: 'utf8'
  50. }, options);
  51. var files = [];
  52. var done = function(err) {
  53. if (typeof complete === 'function') {
  54. if (err) return complete(err);
  55. complete(null, files);
  56. }
  57. };
  58. fs.readdir(dir, function(err, list) {
  59. if (err) return done(err);
  60. var i = 0;
  61. if (options.reverse === true ||
  62. (typeof options.sort == 'string' &&
  63. (/reverse|desc/i).test(options.sort))) {
  64. list = list.reverse();
  65. } else if (options.sort !== false) list = list.sort();
  66. (function next() {
  67. var filename = list[i++];
  68. if (!filename) return done(null, files);
  69. var file = path.join(dir, filename);
  70. fs.stat(file, function(err, stat) {
  71. if (err) return done(err);
  72. if (stat && stat.isDirectory()) {
  73. if (options.recursive) {
  74. if (options.matchDir && !matches(filename, options.matchDir)) return next();
  75. if (options.excludeDir && matches(filename, options.excludeDir)) return next();
  76. readFiles(file, options, callback, function(err, sfiles) {
  77. if (err) return done(err);
  78. files = files.concat(sfiles);
  79. next();
  80. });
  81. } else next();
  82. } else {
  83. if (options.match && !matches(filename, options.match)) return next();
  84. if (options.exclude && matches(filename, options.exclude)) return next();
  85. if (options.filter && !options.filter(filename)) return next();
  86. if (options.shortName) files.push(filename);
  87. else files.push(file);
  88. fs.readFile(file, options.encoding, function(err, data) {
  89. if (err) return done(err);
  90. if (callback.length > 3)
  91. if (options.shortName) callback(null, data, filename, next);
  92. else callback(null, data, file, next);
  93. else callback(null, data, next);
  94. });
  95. }
  96. });
  97. })();
  98. });
  99. }
  100. module.exports = readFiles;