index.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. 'use strict';
  2. const arrayUnion = require('array-union');
  3. const glob = require('glob');
  4. const pify = require('pify');
  5. const dirGlob = require('dir-glob');
  6. const gitignore = require('./gitignore');
  7. const globP = pify(glob);
  8. const DEFAULT_FILTER = () => false;
  9. const isNegative = pattern => pattern[0] === '!';
  10. const assertPatternsInput = patterns => {
  11. if (!patterns.every(x => typeof x === 'string')) {
  12. throw new TypeError('Patterns must be a string or an array of strings');
  13. }
  14. };
  15. const generateGlobTasks = (patterns, taskOpts) => {
  16. patterns = [].concat(patterns);
  17. assertPatternsInput(patterns);
  18. const globTasks = [];
  19. taskOpts = Object.assign({
  20. cache: Object.create(null),
  21. statCache: Object.create(null),
  22. realpathCache: Object.create(null),
  23. symlinks: Object.create(null),
  24. ignore: [],
  25. expandDirectories: true,
  26. nodir: true
  27. }, taskOpts);
  28. patterns.forEach((pattern, i) => {
  29. if (isNegative(pattern)) {
  30. return;
  31. }
  32. const ignore = patterns
  33. .slice(i)
  34. .filter(isNegative)
  35. .map(pattern => pattern.slice(1));
  36. const opts = Object.assign({}, taskOpts, {
  37. ignore: taskOpts.ignore.concat(ignore)
  38. });
  39. globTasks.push({pattern, opts});
  40. });
  41. return globTasks;
  42. };
  43. const globDirs = (task, fn) => {
  44. if (Array.isArray(task.opts.expandDirectories)) {
  45. return fn(task.pattern, {files: task.opts.expandDirectories});
  46. }
  47. if (typeof task.opts.expandDirectories === 'object') {
  48. return fn(task.pattern, task.opts.expandDirectories);
  49. }
  50. return fn(task.pattern);
  51. };
  52. const getPattern = (task, fn) => task.opts.expandDirectories ? globDirs(task, fn) : [task.pattern];
  53. module.exports = (patterns, opts) => {
  54. let globTasks;
  55. try {
  56. globTasks = generateGlobTasks(patterns, opts);
  57. } catch (err) {
  58. return Promise.reject(err);
  59. }
  60. const getTasks = Promise.all(globTasks.map(task => Promise.resolve(getPattern(task, dirGlob))
  61. .then(globs => Promise.all(globs.map(glob => ({
  62. pattern: glob,
  63. opts: task.opts
  64. }))))
  65. ))
  66. .then(tasks => arrayUnion.apply(null, tasks));
  67. const getFilter = () => {
  68. return Promise.resolve(
  69. opts && opts.gitignore ?
  70. gitignore({cwd: opts.cwd, ignore: opts.ignore}) :
  71. DEFAULT_FILTER
  72. );
  73. };
  74. return getFilter()
  75. .then(filter => {
  76. return getTasks
  77. .then(tasks => Promise.all(tasks.map(task => globP(task.pattern, task.opts))))
  78. .then(paths => arrayUnion.apply(null, paths))
  79. .then(paths => paths.filter(p => !filter(p)));
  80. });
  81. };
  82. module.exports.sync = (patterns, opts) => {
  83. const globTasks = generateGlobTasks(patterns, opts);
  84. const getFilter = () => {
  85. return opts && opts.gitignore ?
  86. gitignore.sync({cwd: opts.cwd, ignore: opts.ignore}) :
  87. DEFAULT_FILTER;
  88. };
  89. const tasks = globTasks.reduce((tasks, task) => {
  90. const newTask = getPattern(task, dirGlob.sync).map(glob => ({
  91. pattern: glob,
  92. opts: task.opts
  93. }));
  94. return tasks.concat(newTask);
  95. }, []);
  96. const filter = getFilter();
  97. return tasks.reduce(
  98. (matches, task) => arrayUnion(matches, glob.sync(task.pattern, task.opts)),
  99. []
  100. ).filter(p => !filter(p));
  101. };
  102. module.exports.generateGlobTasks = generateGlobTasks;
  103. module.exports.hasMagic = (patterns, opts) => []
  104. .concat(patterns)
  105. .some(pattern => glob.hasMagic(pattern, opts));
  106. module.exports.gitignore = gitignore;