index.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. /*jslint node: true */
  2. 'use strict';
  3. var through2 = require('through2');
  4. var Combine = require('ordered-read-streams');
  5. var unique = require('unique-stream');
  6. var glob = require('glob');
  7. var minimatch = require('minimatch');
  8. var glob2base = require('glob2base');
  9. var path = require('path');
  10. var gs = {
  11. // creates a stream for a single glob or filter
  12. createStream: function(ourGlob, negatives, opt) {
  13. if (!negatives) negatives = [];
  14. if (!opt) opt = {};
  15. if (typeof opt.cwd !== 'string') opt.cwd = process.cwd();
  16. if (typeof opt.dot !== 'boolean') opt.dot = false;
  17. if (typeof opt.silent !== 'boolean') opt.silent = true;
  18. if (typeof opt.nonull !== 'boolean') opt.nonull = false;
  19. if (typeof opt.cwdbase !== 'boolean') opt.cwdbase = false;
  20. if (opt.cwdbase) opt.base = opt.cwd;
  21. // remove path relativity to make globs make sense
  22. ourGlob = unrelative(opt.cwd, ourGlob);
  23. negatives = negatives.map(unrelative.bind(null, opt.cwd));
  24. // create globbing stuff
  25. var globber = new glob.Glob(ourGlob, opt);
  26. // extract base path from glob
  27. var basePath = opt.base ? opt.base : glob2base(globber);
  28. // create stream and map events from globber to it
  29. var stream = through2.obj(negatives.length ? filterNegatives : undefined);
  30. globber.on('error', stream.emit.bind(stream, 'error'));
  31. globber.on('end', function(/* some args here so can't use bind directly */){
  32. stream.end();
  33. });
  34. globber.on('match', function(filename) {
  35. stream.write({
  36. cwd: opt.cwd,
  37. base: basePath,
  38. path: path.resolve(opt.cwd, filename)
  39. });
  40. });
  41. return stream;
  42. function filterNegatives(filename, enc, cb) {
  43. var matcha = isMatch.bind(null, filename, opt);
  44. if (negatives.every(matcha)) {
  45. cb(null, filename); // pass
  46. } else {
  47. cb(); // ignore
  48. }
  49. }
  50. },
  51. // creates a stream for multiple globs or filters
  52. create: function(globs, opt) {
  53. if (!opt) opt = {};
  54. // only one glob no need to aggregate
  55. if (!Array.isArray(globs)) return gs.createStream(globs, null, opt);
  56. var positives = globs.filter(isPositive);
  57. var negatives = globs.filter(isNegative);
  58. if (positives.length === 0) throw new Error("Missing positive glob");
  59. // only one positive glob no need to aggregate
  60. if (positives.length === 1) return gs.createStream(positives[0], negatives, opt);
  61. // create all individual streams
  62. var streams = positives.map(function(glob){
  63. return gs.createStream(glob, negatives, opt);
  64. });
  65. // then just pipe them to a single unique stream and return it
  66. var aggregate = new Combine(streams);
  67. var uniqueStream = unique('path');
  68. return aggregate.pipe(uniqueStream);
  69. }
  70. };
  71. function isMatch(file, opt, pattern) {
  72. if (typeof pattern === 'string') return minimatch(file.path, pattern, opt);
  73. if (pattern instanceof RegExp) return pattern.test(file.path);
  74. return true; // unknown glob type?
  75. }
  76. function isNegative(pattern) {
  77. if (typeof pattern !== 'string') return true;
  78. if (pattern[0] === '!') return true;
  79. return false;
  80. }
  81. function isPositive(pattern) {
  82. return !isNegative(pattern);
  83. }
  84. function unrelative(cwd, glob) {
  85. var mod = '';
  86. if (glob[0] === '!') {
  87. mod = glob[0];
  88. glob = glob.slice(1);
  89. }
  90. return mod+path.resolve(cwd, glob);
  91. }
  92. module.exports = gs;