Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: sindresorhus/globby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 6e099869e77240f705a951b6a80c09d3bab55423
Choose a base ref
...
head repository: sindresorhus/globby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: fc653c7277b5cc4e035531aef20e3d873fe55658
Choose a head ref
  • 9 commits
  • 10 files changed
  • 3 contributors

Commits on Dec 6, 2021

  1. Upgrade dev dependencies

    Closes #198
    sindresorhus committed Dec 6, 2021
    Copy the full SHA
    79765fb View commit details

Commits on Jan 12, 2022

  1. Copy the full SHA
    60b7116 View commit details
  2. DRY a little bit (#203)

    fisker authored Jan 12, 2022
    Copy the full SHA
    de4082b View commit details

Commits on Jan 15, 2022

  1. Support URL as cwd (#201)

    fisker authored Jan 15, 2022
    Copy the full SHA
    73c0aca View commit details
  2. 12.1.0

    sindresorhus committed Jan 15, 2022
    Copy the full SHA
    1be9d02 View commit details

Commits on Jan 17, 2022

  1. Accept URL in function returned by isGitIgnored (#207)

    Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
    fisker and sindresorhus authored Jan 17, 2022
    Copy the full SHA
    a9fc794 View commit details
  2. Copy the full SHA
    1224230 View commit details
  3. Fix readme

    sindresorhus committed Jan 17, 2022
    Copy the full SHA
    2e57ffa View commit details
  4. 12.2.0

    sindresorhus committed Jan 17, 2022
    Copy the full SHA
    fc653c7 View commit details
Showing with 263 additions and 153 deletions.
  1. +3 −2 bench.js
  2. +7 −14 gitignore.js
  3. +98 −61 gitignore.test.js
  4. +21 −4 index.d.ts
  5. +14 −5 index.js
  6. +4 −0 index.test-d.ts
  7. +10 −10 package.json
  8. +4 −3 readme.md
  9. +87 −54 test.js
  10. +15 −0 to-path.js
5 changes: 3 additions & 2 deletions bench.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* global after, before, bench, suite */
import process from 'node:process';
import fs from 'node:fs';
import path from 'node:path';
import {fileURLToPath} from 'node:url';
@@ -56,7 +57,7 @@ const runners = [
run: patterns => {
fastGlob.sync(patterns);
},
}
},
];

const benchs = [
@@ -80,7 +81,7 @@ const benchs = [
'a/*',
'b/*',
],
}
},
];

before(() => {
21 changes: 7 additions & 14 deletions gitignore.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import {promisify} from 'node:util';
import process from 'node:process';
import fs from 'node:fs';
import path from 'node:path';
import fastGlob from 'fast-glob';
import gitIgnore from 'ignore';
import slash from 'slash';
import toPath from './to-path.js';

const DEFAULT_IGNORE = [
'**/node_modules/**',
@@ -12,8 +13,6 @@ const DEFAULT_IGNORE = [
'**/.git',
];

const readFileP = promisify(fs.readFile);

const mapGitIgnorePatternTo = base => ignore => {
if (ignore.startsWith('!')) {
return '!' + path.posix.join(base, ignore.slice(1));
@@ -57,11 +56,11 @@ const ensureAbsolutePathForCwd = (cwd, p) => {
return path.join(cwd, p);
};

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

const getFile = async (file, cwd) => {
const filePath = path.join(cwd, file);
const content = await readFileP(filePath, 'utf8');
const content = await fs.promises.readFile(filePath, 'utf8');

return {
cwd,
@@ -84,15 +83,12 @@ const getFileSync = (file, cwd) => {
const normalizeOptions = ({
ignore = [],
cwd = slash(process.cwd()),
} = {}) => ({ignore, cwd});
} = {}) => ({ignore: [...DEFAULT_IGNORE, ...ignore], cwd: toPath(cwd)});

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

const paths = await fastGlob('**/.gitignore', {
ignore: DEFAULT_IGNORE.concat(options.ignore),
cwd: options.cwd,
});
const paths = await fastGlob('**/.gitignore', options);

const files = await Promise.all(paths.map(file => getFile(file, options.cwd)));
const ignores = reduceIgnore(files);
@@ -103,10 +99,7 @@ export const isGitIgnored = async options => {
export const isGitIgnoredSync = options => {
options = normalizeOptions(options);

const paths = fastGlob.sync('**/.gitignore', {
ignore: DEFAULT_IGNORE.concat(options.ignore),
cwd: options.cwd,
});
const paths = fastGlob.sync('**/.gitignore', options);

const files = paths.map(file => getFileSync(file, options.cwd));
const ignores = reduceIgnore(files);
159 changes: 98 additions & 61 deletions gitignore.test.js
Original file line number Diff line number Diff line change
@@ -1,101 +1,138 @@
import path from 'node:path';
import {fileURLToPath} from 'node:url';
import {fileURLToPath, pathToFileURL} from 'node:url';
import test from 'ava';
import slash from 'slash';
import {isGitIgnored, isGitIgnoredSync} from './gitignore.js';

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const getPathValues = cwd => [cwd, pathToFileURL(cwd), pathToFileURL(cwd).href];

test('gitignore', async t => {
const cwd = path.join(__dirname, 'fixtures/gitignore');
const isIgnored = await isGitIgnored({cwd});
const actual = ['foo.js', 'bar.js'].filter(file => !isIgnored(file));
const expected = ['bar.js'];
t.deepEqual(actual, expected);
for (const cwd of getPathValues(path.join(__dirname, 'fixtures/gitignore'))) {
// eslint-disable-next-line no-await-in-loop
const isIgnored = await isGitIgnored({cwd});
const actual = ['foo.js', 'bar.js'].filter(file => !isIgnored(file));
const expected = ['bar.js'];
t.deepEqual(actual, expected);
}
});

test('gitignore - mixed path styles', async t => {
const cwd = path.join(__dirname, 'fixtures/gitignore');
const isIgnored = await isGitIgnored({cwd});
t.true(isIgnored(slash(path.resolve(cwd, 'foo.js'))));
const directory = path.join(__dirname, 'fixtures/gitignore');
for (const cwd of getPathValues(directory)) {
// eslint-disable-next-line no-await-in-loop
const isIgnored = await isGitIgnored({cwd});
t.true(isIgnored(slash(path.resolve(directory, 'foo.js'))));
}
});

test('gitignore - os paths', async t => {
const cwd = path.join(__dirname, 'fixtures/gitignore');
const isIgnored = await isGitIgnored({cwd});
t.true(isIgnored(path.resolve(cwd, 'foo.js')));
const directory = path.join(__dirname, 'fixtures/gitignore');
for (const cwd of getPathValues(directory)) {
// eslint-disable-next-line no-await-in-loop
const isIgnored = await isGitIgnored({cwd});
t.true(isIgnored(path.resolve(directory, 'foo.js')));
}
});

test('gitignore - sync', t => {
const cwd = path.join(__dirname, 'fixtures/gitignore');
const isIgnored = isGitIgnoredSync({cwd});
const actual = ['foo.js', 'bar.js'].filter(file => !isIgnored(file));
const expected = ['bar.js'];
t.deepEqual(actual, expected);
for (const cwd of getPathValues(path.join(__dirname, 'fixtures/gitignore'))) {
const isIgnored = isGitIgnoredSync({cwd});
const actual = ['foo.js', 'bar.js'].filter(file => !isIgnored(file));
const expected = ['bar.js'];
t.deepEqual(actual, expected);
}
});

test('ignore ignored .gitignore', async t => {
const cwd = path.join(__dirname, 'fixtures/gitignore');
const ignore = ['**/.gitignore'];

const isIgnored = await isGitIgnored({cwd, ignore});
const actual = ['foo.js', 'bar.js'].filter(file => !isIgnored(file));
const expected = ['foo.js', 'bar.js'];
t.deepEqual(actual, expected);
for (const cwd of getPathValues(path.join(__dirname, 'fixtures/gitignore'))) {
// eslint-disable-next-line no-await-in-loop
const isIgnored = await isGitIgnored({cwd, ignore});
const actual = ['foo.js', 'bar.js'].filter(file => !isIgnored(file));
const expected = ['foo.js', 'bar.js'];
t.deepEqual(actual, expected);
}
});

test('ignore ignored .gitignore - sync', t => {
const cwd = path.join(__dirname, 'fixtures/gitignore');
const ignore = ['**/.gitignore'];

const isIgnored = isGitIgnoredSync({cwd, ignore});
const actual = ['foo.js', 'bar.js'].filter(file => !isIgnored(file));
const expected = ['foo.js', 'bar.js'];
t.deepEqual(actual, expected);
for (const cwd of getPathValues(path.join(__dirname, 'fixtures/gitignore'))) {
const isIgnored = isGitIgnoredSync({cwd, ignore});
const actual = ['foo.js', 'bar.js'].filter(file => !isIgnored(file));
const expected = ['foo.js', 'bar.js'];
t.deepEqual(actual, expected);
}
});

test('negative gitignore', async t => {
const cwd = path.join(__dirname, 'fixtures/negative');
const isIgnored = await isGitIgnored({cwd});
const actual = ['foo.js', 'bar.js'].filter(file => !isIgnored(file));
const expected = ['foo.js'];
t.deepEqual(actual, expected);
for (const cwd of getPathValues(path.join(__dirname, 'fixtures/negative'))) {
// eslint-disable-next-line no-await-in-loop
const isIgnored = await isGitIgnored({cwd});
const actual = ['foo.js', 'bar.js'].filter(file => !isIgnored(file));
const expected = ['foo.js'];
t.deepEqual(actual, expected);
}
});

test('negative gitignore - sync', t => {
const cwd = path.join(__dirname, 'fixtures/negative');
const isIgnored = isGitIgnoredSync({cwd});
const actual = ['foo.js', 'bar.js'].filter(file => !isIgnored(file));
const expected = ['foo.js'];
t.deepEqual(actual, expected);
for (const cwd of getPathValues(path.join(__dirname, 'fixtures/negative'))) {
const isIgnored = isGitIgnoredSync({cwd});
const actual = ['foo.js', 'bar.js'].filter(file => !isIgnored(file));
const expected = ['foo.js'];
t.deepEqual(actual, expected);
}
});

test('multiple negation', async t => {
const cwd = path.join(__dirname, 'fixtures/multiple-negation');
const isIgnored = await isGitIgnored({cwd});

const actual = [
'!!!unicorn.js',
'!!unicorn.js',
'!unicorn.js',
'unicorn.js',
].filter(file => !isIgnored(file));

const expected = ['!!unicorn.js', '!unicorn.js'];
t.deepEqual(actual, expected);
for (const cwd of getPathValues(path.join(__dirname, 'fixtures/multiple-negation'))) {
// eslint-disable-next-line no-await-in-loop
const isIgnored = await isGitIgnored({cwd});

const actual = [
'!!!unicorn.js',
'!!unicorn.js',
'!unicorn.js',
'unicorn.js',
].filter(file => !isIgnored(file));

const expected = ['!!unicorn.js', '!unicorn.js'];
t.deepEqual(actual, expected);
}
});

test('multiple negation - sync', t => {
const cwd = path.join(__dirname, 'fixtures/multiple-negation');
const isIgnored = isGitIgnoredSync({cwd});

const actual = [
'!!!unicorn.js',
'!!unicorn.js',
'!unicorn.js',
'unicorn.js',
].filter(file => !isIgnored(file));

const expected = ['!!unicorn.js', '!unicorn.js'];
t.deepEqual(actual, expected);
for (const cwd of getPathValues(path.join(__dirname, 'fixtures/multiple-negation'))) {
const isIgnored = isGitIgnoredSync({cwd});

const actual = [
'!!!unicorn.js',
'!!unicorn.js',
'!unicorn.js',
'unicorn.js',
].filter(file => !isIgnored(file));

const expected = ['!!unicorn.js', '!unicorn.js'];
t.deepEqual(actual, expected);
}
});

test('check file', async t => {
const directory = path.join(__dirname, 'fixtures/gitignore');
const ignoredFile = path.join(directory, 'foo.js');
const isIgnored = await isGitIgnored({cwd: directory});
const isIgnoredSync = isGitIgnoredSync({cwd: directory});

for (const file of getPathValues(ignoredFile)) {
t.true(isIgnored(file));
t.true(isIgnored({path: file}));
t.true(isIgnoredSync(file));
t.true(isIgnoredSync({path: file}));
}

for (const file of getPathValues(path.join(directory, 'bar.js'))) {
t.false(isIgnored(file));
}
});
25 changes: 21 additions & 4 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {URL} from 'node:url'; // TODO: Remove this when https://github.com/DefinitelyTyped/DefinitelyTyped/issues/34960 is fixed.
import {Options as FastGlobOptions, Entry} from 'fast-glob';

export type GlobEntry = Entry;
@@ -12,7 +13,9 @@ export type ExpandDirectoriesOption =
| readonly string[]
| {files?: readonly string[]; extensions?: readonly string[]};

export interface Options extends FastGlobOptions {
type FastGlobOptionsWithoutCwd = Omit<FastGlobOptions, 'cwd'>;

export interface Options extends FastGlobOptionsWithoutCwd {
/**
If set to `true`, `globby` will automatically glob directories for you. If you define an `Array` it will only glob files that matches the patterns inside the `Array`. You can also define an `Object` with `files` and `extensions` like in the example below.
@@ -43,14 +46,21 @@ export interface Options extends FastGlobOptions {
@default false
*/
readonly gitignore?: boolean;

/**
The current working directory in which to search.
@default process.cwd()
*/
readonly cwd?: URL | string;
}

export interface GitignoreOptions {
readonly cwd?: string;
readonly cwd?: URL | string;
readonly ignore?: readonly string[];
}

export type GlobbyFilterFunction = (path: string) => boolean;
export type GlobbyFilterFunction = (path: URL | string) => boolean;

/**
Find files and directories using glob patterns.
@@ -144,7 +154,14 @@ This function is backed by [`fast-glob`](https://github.com/mrmlnc/fast-glob#isd
*/
export function isDynamicPattern(
patterns: string | readonly string[],
options?: FastGlobOptions
options?: FastGlobOptionsWithoutCwd & {
/**
The current working directory in which to search.
@default process.cwd()
*/
readonly cwd?: URL | string;
}
): boolean;

/**
Loading