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