You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

128 lines
3.1 KiB

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