121 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			121 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
'use strict';
 | 
						|
const {promisify} = require('util');
 | 
						|
const fs = require('fs');
 | 
						|
const path = require('path');
 | 
						|
const fastGlob = require('fast-glob');
 | 
						|
const gitIgnore = require('ignore');
 | 
						|
const slash = require('slash');
 | 
						|
 | 
						|
const DEFAULT_IGNORE = [
 | 
						|
	'**/node_modules/**',
 | 
						|
	'**/flow-typed/**',
 | 
						|
	'**/coverage/**',
 | 
						|
	'**/.git'
 | 
						|
];
 | 
						|
 | 
						|
const readFileP = promisify(fs.readFile);
 | 
						|
 | 
						|
const mapGitIgnorePatternTo = base => ignore => {
 | 
						|
	if (ignore.startsWith('!')) {
 | 
						|
		return '!' + path.posix.join(base, ignore.slice(1));
 | 
						|
	}
 | 
						|
 | 
						|
	return path.posix.join(base, ignore);
 | 
						|
};
 | 
						|
 | 
						|
const parseGitIgnore = (content, options) => {
 | 
						|
	const base = slash(path.relative(options.cwd, path.dirname(options.fileName)));
 | 
						|
 | 
						|
	return content
 | 
						|
		.split(/\r?\n/)
 | 
						|
		.filter(Boolean)
 | 
						|
		.filter(line => !line.startsWith('#'))
 | 
						|
		.map(mapGitIgnorePatternTo(base));
 | 
						|
};
 | 
						|
 | 
						|
const reduceIgnore = files => {
 | 
						|
	const ignores = gitIgnore();
 | 
						|
	for (const file of files) {
 | 
						|
		ignores.add(parseGitIgnore(file.content, {
 | 
						|
			cwd: file.cwd,
 | 
						|
			fileName: file.filePath
 | 
						|
		}));
 | 
						|
	}
 | 
						|
 | 
						|
	return ignores;
 | 
						|
};
 | 
						|
 | 
						|
const ensureAbsolutePathForCwd = (cwd, p) => {
 | 
						|
	cwd = slash(cwd);
 | 
						|
	if (path.isAbsolute(p)) {
 | 
						|
		if (slash(p).startsWith(cwd)) {
 | 
						|
			return p;
 | 
						|
		}
 | 
						|
 | 
						|
		throw new Error(`Path ${p} is not in cwd ${cwd}`);
 | 
						|
	}
 | 
						|
 | 
						|
	return path.join(cwd, p);
 | 
						|
};
 | 
						|
 | 
						|
const getIsIgnoredPredecate = (ignores, cwd) => {
 | 
						|
	return p => ignores.ignores(slash(path.relative(cwd, ensureAbsolutePathForCwd(cwd, p.path || p))));
 | 
						|
};
 | 
						|
 | 
						|
const getFile = async (file, cwd) => {
 | 
						|
	const filePath = path.join(cwd, file);
 | 
						|
	const content = await readFileP(filePath, 'utf8');
 | 
						|
 | 
						|
	return {
 | 
						|
		cwd,
 | 
						|
		filePath,
 | 
						|
		content
 | 
						|
	};
 | 
						|
};
 | 
						|
 | 
						|
const getFileSync = (file, cwd) => {
 | 
						|
	const filePath = path.join(cwd, file);
 | 
						|
	const content = fs.readFileSync(filePath, 'utf8');
 | 
						|
 | 
						|
	return {
 | 
						|
		cwd,
 | 
						|
		filePath,
 | 
						|
		content
 | 
						|
	};
 | 
						|
};
 | 
						|
 | 
						|
const normalizeOptions = ({
 | 
						|
	ignore = [],
 | 
						|
	cwd = slash(process.cwd())
 | 
						|
} = {}) => {
 | 
						|
	return {ignore, cwd};
 | 
						|
};
 | 
						|
 | 
						|
module.exports = async options => {
 | 
						|
	options = normalizeOptions(options);
 | 
						|
 | 
						|
	const paths = await fastGlob('**/.gitignore', {
 | 
						|
		ignore: DEFAULT_IGNORE.concat(options.ignore),
 | 
						|
		cwd: options.cwd
 | 
						|
	});
 | 
						|
 | 
						|
	const files = await Promise.all(paths.map(file => getFile(file, options.cwd)));
 | 
						|
	const ignores = reduceIgnore(files);
 | 
						|
 | 
						|
	return getIsIgnoredPredecate(ignores, options.cwd);
 | 
						|
};
 | 
						|
 | 
						|
module.exports.sync = options => {
 | 
						|
	options = normalizeOptions(options);
 | 
						|
 | 
						|
	const paths = fastGlob.sync('**/.gitignore', {
 | 
						|
		ignore: DEFAULT_IGNORE.concat(options.ignore),
 | 
						|
		cwd: options.cwd
 | 
						|
	});
 | 
						|
 | 
						|
	const files = paths.map(file => getFileSync(file, options.cwd));
 | 
						|
	const ignores = reduceIgnore(files);
 | 
						|
 | 
						|
	return getIsIgnoredPredecate(ignores, options.cwd);
 | 
						|
};
 |