Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Style tweak #227

Merged
merged 2 commits into from Jan 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
88 changes: 37 additions & 51 deletions gitignore.js
Expand Up @@ -4,7 +4,7 @@ import path from 'node:path';
import fastGlob from 'fast-glob';
import gitIgnore from 'ignore';
import slash from 'slash';
import {toPath} from './utilities.js';
import {toPath, isNegativePattern} from './utilities.js';

const gitignoreGlobOptions = {
ignore: [
Expand All @@ -16,85 +16,71 @@ const gitignoreGlobOptions = {
absolute: true,
};

const mapGitIgnorePatternTo = base => ignore => {
if (ignore.startsWith('!')) {
return '!' + path.posix.join(base, ignore.slice(1));
}

return path.posix.join(base, ignore);
};
const applyBaseToPattern = (pattern, base) => isNegativePattern(pattern)
? '!' + path.posix.join(base, pattern.slice(1))
: path.posix.join(base, pattern);

const parseGitIgnore = (content, options) => {
const base = slash(path.relative(options.cwd, path.dirname(options.fileName)));
const parseGitIgnoreFile = (file, cwd) => {
const base = slash(path.relative(cwd, path.dirname(file.filePath)));

return content
return file.content
.split(/\r?\n/)
.filter(Boolean)
.filter(line => !line.startsWith('#'))
.map(mapGitIgnorePatternTo(base));
.filter(line => line && !line.startsWith('#'))
.map(pattern => applyBaseToPattern(pattern, 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) => {
const toRelativePath = (fileOrDirectory, cwd) => {
cwd = slash(cwd);
if (path.isAbsolute(p)) {
if (slash(p).startsWith(cwd)) {
return p;
if (path.isAbsolute(fileOrDirectory)) {
if (slash(fileOrDirectory).startsWith(cwd)) {
return path.relative(cwd, fileOrDirectory);
}

throw new Error(`Path ${p} is not in cwd ${cwd}`);
throw new Error(`Path ${fileOrDirectory} is not in cwd ${cwd}`);
}

return path.join(cwd, p);
return fileOrDirectory;
};

const getIsIgnoredPredicate = (ignores, cwd) => p => ignores.ignores(slash(path.relative(cwd, ensureAbsolutePathForCwd(cwd, toPath(p)))));

const getFile = async (filePath, cwd) => ({
cwd,
filePath,
content: await fs.promises.readFile(filePath, 'utf8'),
});
const getIsIgnoredPredicate = (files, cwd) => {
const patterns = files.flatMap(file => parseGitIgnoreFile(file, cwd));
const ignores = gitIgnore().add(patterns);

const getFileSync = (filePath, cwd) => ({
cwd,
filePath,
content: fs.readFileSync(filePath, 'utf8'),
});
return fileOrDirectory => {
fileOrDirectory = toPath(fileOrDirectory);
fileOrDirectory = toRelativePath(fileOrDirectory, cwd);
return ignores.ignores(slash(fileOrDirectory));
};
};

const normalizeOptions = (options = {}) => ({
cwd: toPath(options.cwd) || slash(process.cwd()),
cwd: toPath(options.cwd) || process.cwd(),
});

export const isGitIgnored = async options => {
const {cwd} = normalizeOptions(options);

const paths = await fastGlob('**/.gitignore', {cwd, ...gitignoreGlobOptions});

const files = await Promise.all(paths.map(file => getFile(file, cwd)));
const ignores = reduceIgnore(files);
const files = await Promise.all(
paths.map(async filePath => ({
filePath,
content: await fs.promises.readFile(filePath, 'utf8'),
})),
);

return getIsIgnoredPredicate(ignores, cwd);
return getIsIgnoredPredicate(files, cwd);
};

export const isGitIgnoredSync = options => {
const {cwd} = normalizeOptions(options);

const paths = fastGlob.sync('**/.gitignore', {cwd, ...gitignoreGlobOptions});

const files = paths.map(file => getFileSync(file, cwd));
const ignores = reduceIgnore(files);
const files = paths.map(filePath => ({
filePath,
content: fs.readFileSync(filePath, 'utf8'),
}));

return getIsIgnoredPredicate(ignores, cwd);
return getIsIgnoredPredicate(files, cwd);
};
6 changes: 2 additions & 4 deletions index.js
Expand Up @@ -3,9 +3,7 @@ import merge2 from 'merge2';
import fastGlob from 'fast-glob';
import dirGlob from 'dir-glob';
import {isGitIgnored, isGitIgnoredSync} from './gitignore.js';
import {FilterStream, toPath} from './utilities.js';

const isNegative = pattern => pattern[0] === '!';
import {FilterStream, toPath, isNegativePattern} from './utilities.js';

const assertPatternsInput = patterns => {
if (!patterns.every(pattern => typeof pattern === 'string')) {
Expand Down Expand Up @@ -78,7 +76,7 @@ const convertNegativePatterns = (patterns, options) => {
const tasks = [];

while (patterns.length > 0) {
const index = patterns.findIndex(pattern => isNegative(pattern));
const index = patterns.findIndex(pattern => isNegativePattern(pattern));

if (index === -1) {
tasks.push({patterns, options});
Expand Down
2 changes: 2 additions & 0 deletions utilities.js
Expand Up @@ -13,3 +13,5 @@ export class FilterStream extends Transform {
});
}
}

export const isNegativePattern = pattern => pattern[0] === '!';