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.

95 lines
2.2 KiB

4 years ago
  1. 'use strict';
  2. const fs = require('fs');
  3. const path = require('path');
  4. const fastGlob = require('fast-glob');
  5. const gitIgnore = require('ignore');
  6. const pify = require('pify');
  7. const slash = require('slash');
  8. const DEFAULT_IGNORE = [
  9. '**/node_modules/**',
  10. '**/bower_components/**',
  11. '**/flow-typed/**',
  12. '**/coverage/**',
  13. '**/.git'
  14. ];
  15. const readFileP = pify(fs.readFile);
  16. const mapGitIgnorePatternTo = base => ignore => {
  17. if (ignore.startsWith('!')) {
  18. return '!' + path.posix.join(base, ignore.substr(1));
  19. }
  20. return path.posix.join(base, ignore);
  21. };
  22. const parseGitIgnore = (content, opts) => {
  23. const base = slash(path.relative(opts.cwd, path.dirname(opts.fileName)));
  24. return content
  25. .split(/\r?\n/)
  26. .filter(Boolean)
  27. .filter(l => l.charAt(0) !== '#')
  28. .map(mapGitIgnorePatternTo(base));
  29. };
  30. const reduceIgnore = files => {
  31. return files.reduce((ignores, file) => {
  32. ignores.add(parseGitIgnore(file.content, {
  33. cwd: file.cwd,
  34. fileName: file.filePath
  35. }));
  36. return ignores;
  37. }, gitIgnore());
  38. };
  39. const getIsIgnoredPredecate = (ignores, cwd) => {
  40. return p => ignores.ignores(slash(path.relative(cwd, p)));
  41. };
  42. const getFile = (file, cwd) => {
  43. const filePath = path.join(cwd, file);
  44. return readFileP(filePath, 'utf8')
  45. .then(content => ({
  46. content,
  47. cwd,
  48. filePath
  49. }));
  50. };
  51. const getFileSync = (file, cwd) => {
  52. const filePath = path.join(cwd, file);
  53. const content = fs.readFileSync(filePath, 'utf8');
  54. return {
  55. content,
  56. cwd,
  57. filePath
  58. };
  59. };
  60. const normalizeOpts = opts => {
  61. opts = opts || {};
  62. const ignore = opts.ignore || [];
  63. const cwd = opts.cwd || process.cwd();
  64. return {ignore, cwd};
  65. };
  66. module.exports = o => {
  67. const opts = normalizeOpts(o);
  68. return fastGlob('**/.gitignore', {ignore: DEFAULT_IGNORE.concat(opts.ignore), cwd: opts.cwd})
  69. .then(paths => Promise.all(paths.map(file => getFile(file, opts.cwd))))
  70. .then(files => reduceIgnore(files))
  71. .then(ignores => getIsIgnoredPredecate(ignores, opts.cwd));
  72. };
  73. module.exports.sync = o => {
  74. const opts = normalizeOpts(o);
  75. const paths = fastGlob.sync('**/.gitignore', {ignore: DEFAULT_IGNORE.concat(opts.ignore), cwd: opts.cwd});
  76. const files = paths.map(file => getFileSync(file, opts.cwd));
  77. const ignores = reduceIgnore(files);
  78. return getIsIgnoredPredecate(ignores, opts.cwd);
  79. };