UNPKG

2.51 kBJavaScriptView Raw
1import process from 'node:process';
2import fs from 'node:fs';
3import path from 'node:path';
4import fastGlob from 'fast-glob';
5import gitIgnore from 'ignore';
6import slash from 'slash';
7import toPath from './to-path.js';
8
9const DEFAULT_IGNORE = [
10 '**/node_modules/**',
11 '**/flow-typed/**',
12 '**/coverage/**',
13 '**/.git',
14];
15
16const mapGitIgnorePatternTo = base => ignore => {
17 if (ignore.startsWith('!')) {
18 return '!' + path.posix.join(base, ignore.slice(1));
19 }
20
21 return path.posix.join(base, ignore);
22};
23
24const parseGitIgnore = (content, options) => {
25 const base = slash(path.relative(options.cwd, path.dirname(options.fileName)));
26
27 return content
28 .split(/\r?\n/)
29 .filter(Boolean)
30 .filter(line => !line.startsWith('#'))
31 .map(mapGitIgnorePatternTo(base));
32};
33
34const reduceIgnore = files => {
35 const ignores = gitIgnore();
36 for (const file of files) {
37 ignores.add(parseGitIgnore(file.content, {
38 cwd: file.cwd,
39 fileName: file.filePath,
40 }));
41 }
42
43 return ignores;
44};
45
46const ensureAbsolutePathForCwd = (cwd, p) => {
47 cwd = slash(cwd);
48 if (path.isAbsolute(p)) {
49 if (slash(p).startsWith(cwd)) {
50 return p;
51 }
52
53 throw new Error(`Path ${p} is not in cwd ${cwd}`);
54 }
55
56 return path.join(cwd, p);
57};
58
59const getIsIgnoredPredicate = (ignores, cwd) => p => ignores.ignores(slash(path.relative(cwd, ensureAbsolutePathForCwd(cwd, toPath(p.path || p)))));
60
61const getFile = async (file, cwd) => {
62 const filePath = path.join(cwd, file);
63 const content = await fs.promises.readFile(filePath, 'utf8');
64
65 return {
66 cwd,
67 filePath,
68 content,
69 };
70};
71
72const getFileSync = (file, cwd) => {
73 const filePath = path.join(cwd, file);
74 const content = fs.readFileSync(filePath, 'utf8');
75
76 return {
77 cwd,
78 filePath,
79 content,
80 };
81};
82
83const normalizeOptions = ({
84 ignore = [],
85 cwd = slash(process.cwd()),
86} = {}) => ({ignore: [...DEFAULT_IGNORE, ...ignore], cwd: toPath(cwd)});
87
88export const isGitIgnored = async options => {
89 options = normalizeOptions(options);
90
91 const paths = await fastGlob('**/.gitignore', options);
92
93 const files = await Promise.all(paths.map(file => getFile(file, options.cwd)));
94 const ignores = reduceIgnore(files);
95
96 return getIsIgnoredPredicate(ignores, options.cwd);
97};
98
99export const isGitIgnoredSync = options => {
100 options = normalizeOptions(options);
101
102 const paths = fastGlob.sync('**/.gitignore', options);
103
104 const files = paths.map(file => getFileSync(file, options.cwd));
105 const ignores = reduceIgnore(files);
106
107 return getIsIgnoredPredicate(ignores, options.cwd);
108};