diff --git a/.gitignore b/.gitignore index b8a3a9f..983f70d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ -bench node_modules yarn.lock +bench *.tmp tmp diff --git a/.travis.yml b/.travis.yml index 2084bfa..29ef4bf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,4 +7,3 @@ node_js: - '12' - '10' - '8' - - '6' diff --git a/bench.js b/bench.js index 7a32367..fe9d681 100644 --- a/bench.js +++ b/bench.js @@ -11,13 +11,15 @@ const BENCH_DIR = 'bench'; const runners = [{ name: 'globby async (working directory)', - run: (patterns, cb) => { - globby(patterns).then(cb.bind(null, null), cb); + run: async (patterns, callback) => { + await globby(patterns); + callback(); } }, { name: 'globby async (upstream/master)', - run: (patterns, cb) => { - globbyMaster(patterns).then(cb.bind(null, null), cb); + run: async (patterns, callback) => { + await globbyMaster(patterns); + callback(); } }, { name: 'globby sync (working directory)', @@ -36,8 +38,9 @@ const runners = [{ } }, { name: 'fast-glob async', - run: (patterns, cb) => { - fastGlob(patterns).then(cb.bind(null, null), cb); + run: async (patterns, callback) => { + await fastGlob(patterns); + callback(); } }, { name: 'fast-glob sync', @@ -47,13 +50,22 @@ const runners = [{ }]; const benchs = [{ name: 'negative globs (some files inside dir)', - patterns: ['a/*', '!a/c*'] + patterns: [ + 'a/*', + '!a/c*' + ] }, { name: 'negative globs (whole dir)', - patterns: ['a/*', '!a/**'] + patterns: [ + 'a/*', + '!a/**' + ] }, { name: 'multiple positive globs', - patterns: ['a/*', 'b/*'] + patterns: [ + 'a/*', + 'b/*' + ] }]; before(() => { @@ -62,11 +74,11 @@ before(() => { fs.mkdirSync(BENCH_DIR); process.chdir(BENCH_DIR); ['a', 'b'] - .map(dir => `${dir}/`) - .forEach(dir => { - fs.mkdirSync(dir); + .map(directory => `${directory}/`) + .forEach(directory => { + fs.mkdirSync(directory); for (let i = 0; i < 500; i++) { - fs.writeFileSync(dir + (i < 100 ? 'c' : 'd') + i, ''); + fs.writeFileSync(directory + (i < 100 ? 'c' : 'd') + i, ''); } }); }); diff --git a/gitignore.js b/gitignore.js index 9ecbc05..524bca0 100644 --- a/gitignore.js +++ b/gitignore.js @@ -1,9 +1,9 @@ 'use strict'; +const {promisify} = require('util'); const fs = require('fs'); const path = require('path'); const fastGlob = require('fast-glob'); const gitIgnore = require('ignore'); -const pify = require('pify'); const slash = require('slash'); const DEFAULT_IGNORE = [ @@ -14,7 +14,7 @@ const DEFAULT_IGNORE = [ '**/.git' ]; -const readFileP = pify(fs.readFile); +const readFileP = promisify(fs.readFile); const mapGitIgnorePatternTo = base => ignore => { if (ignore.startsWith('!')) { @@ -30,7 +30,7 @@ const parseGitIgnore = (content, options) => { return content .split(/\r?\n/) .filter(Boolean) - .filter(line => line.charAt(0) !== '#') + .filter(line => !line.startsWith('#')) .map(mapGitIgnorePatternTo(base)); }; @@ -60,14 +60,15 @@ const getIsIgnoredPredecate = (ignores, cwd) => { return p => ignores.ignores(slash(path.relative(cwd, ensureAbsolutePathForCwd(cwd, p)))); }; -const getFile = (file, cwd) => { +const getFile = async (file, cwd) => { const filePath = path.join(cwd, file); - return readFileP(filePath, 'utf8') - .then(content => ({ - content, - cwd, - filePath - })); + const content = await readFileP(filePath, 'utf8'); + + return { + cwd, + filePath, + content + }; }; const getFileSync = (file, cwd) => { @@ -75,28 +76,31 @@ const getFileSync = (file, cwd) => { const content = fs.readFileSync(filePath, 'utf8'); return { - content, cwd, - filePath + filePath, + content }; }; -const normalizeOptions = (options = {}) => { - const ignore = options.ignore || []; - const cwd = options.cwd || process.cwd(); +const normalizeOptions = ({ + ignore = [], + cwd = process.cwd() +} = {}) => { return {ignore, cwd}; }; -module.exports = options => { +module.exports = async options => { options = normalizeOptions(options); - return fastGlob('**/.gitignore', { + const paths = await fastGlob('**/.gitignore', { ignore: DEFAULT_IGNORE.concat(options.ignore), cwd: options.cwd - }) - .then(paths => Promise.all(paths.map(file => getFile(file, options.cwd)))) - .then(files => reduceIgnore(files)) - .then(ignores => getIsIgnoredPredecate(ignores, 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 => { @@ -106,6 +110,7 @@ module.exports.sync = options => { ignore: DEFAULT_IGNORE.concat(options.ignore), cwd: options.cwd }); + const files = paths.map(file => getFileSync(file, options.cwd)); const ignores = reduceIgnore(files); diff --git a/index.d.ts b/index.d.ts index eb3bfdd..b124362 100644 --- a/index.d.ts +++ b/index.d.ts @@ -138,9 +138,6 @@ declare const globby: { ): boolean; readonly gitignore: Gitignore; - - // TODO: Remove this for the next major release - default: typeof globby; }; export = globby; diff --git a/index.js b/index.js index 4043b28..f8f3a57 100644 --- a/index.js +++ b/index.js @@ -11,7 +11,7 @@ const DEFAULT_FILTER = () => false; const isNegative = pattern => pattern[0] === '!'; const assertPatternsInput = patterns => { - if (!patterns.every(x => typeof x === 'string')) { + if (!patterns.every(pattern => typeof pattern === 'string')) { throw new TypeError('Patterns must be a string or an array of strings'); } }; @@ -31,27 +31,29 @@ const generateGlobTasks = (patterns, taskOptions) => { const globTasks = []; - taskOptions = Object.assign({ + taskOptions = { ignore: [], - expandDirectories: true - }, taskOptions); + expandDirectories: true, + ...taskOptions + }; - patterns.forEach((pattern, i) => { + for (const [index, pattern] of patterns.entries()) { if (isNegative(pattern)) { - return; + continue; } const ignore = patterns - .slice(i) + .slice(index) .filter(isNegative) .map(pattern => pattern.slice(1)); - const options = Object.assign({}, taskOptions, { + const options = { + ...taskOptions, ignore: taskOptions.ignore.concat(ignore) - }); + }; globTasks.push({pattern, options}); - }); + } return globTasks; }; @@ -63,9 +65,15 @@ const globDirs = (task, fn) => { } if (Array.isArray(task.options.expandDirectories)) { - options = Object.assign(options, {files: task.options.expandDirectories}); + options = { + ...options, + files: task.options.expandDirectories + }; } else if (typeof task.options.expandDirectories === 'object') { - options = Object.assign(options, task.options.expandDirectories); + options = { + ...options, + ...task.options.expandDirectories + }; } return fn(task.pattern, options); @@ -85,40 +93,29 @@ const globToTask = task => glob => { }; }; -const globby = (patterns, options) => { - let globTasks; +module.exports = async (patterns, options) => { + const globTasks = generateGlobTasks(patterns, options); - try { - globTasks = generateGlobTasks(patterns, options); - } catch (error) { - return Promise.reject(error); - } + const getFilter = async () => { + return options && options.gitignore ? + gitignore({cwd: options.cwd, ignore: options.ignore}) : + DEFAULT_FILTER; + }; - const getTasks = Promise.all(globTasks.map(task => Promise.resolve(getPattern(task, dirGlob)) - .then(globs => Promise.all(globs.map(globToTask(task)))) - )) - .then(tasks => arrayUnion(...tasks)); + const getTasks = async () => { + const tasks = await Promise.all(globTasks.map(async task => { + const globs = await getPattern(task, dirGlob); + return Promise.all(globs.map(globToTask(task))); + })); - const getFilter = () => { - return Promise.resolve( - options && options.gitignore ? - gitignore({cwd: options.cwd, ignore: options.ignore}) : - DEFAULT_FILTER - ); + return arrayUnion(...tasks); }; - return getFilter() - .then(filter => { - return getTasks - .then(tasks => Promise.all(tasks.map(task => fastGlob(task.pattern, task.options)))) - .then(paths => arrayUnion(...paths)) - .then(paths => paths.filter(p => !filter(getPathString(p)))); - }); -}; + const [filter, tasks] = await Promise.all([getFilter(), getTasks()]); + const paths = await Promise.all(tasks.map(task => fastGlob(task.pattern, task.options))); -module.exports = globby; -// TODO: Remove this for the next major release -module.exports.default = globby; + return arrayUnion(...paths).filter(path_ => !filter(getPathString(path_))); +}; module.exports.sync = (patterns, options) => { const globTasks = generateGlobTasks(patterns, options); @@ -138,7 +135,7 @@ module.exports.sync = (patterns, options) => { return tasks.reduce( (matches, task) => arrayUnion(matches, fastGlob.sync(task.pattern, task.options)), [] - ).filter(p => !filter(p)); + ).filter(path_ => !filter(path_)); }; module.exports.generateGlobTasks = generateGlobTasks; diff --git a/package.json b/package.json index 570174f..cf84a8e 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "url": "sindresorhus.com" }, "engines": { - "node": ">=6" + "node": ">=8" }, "scripts": { "bench": "npm update glob-stream fast-glob && matcha bench.js", @@ -25,7 +25,6 @@ "all", "array", "directories", - "dirs", "expand", "files", "filesystem", @@ -57,16 +56,15 @@ ], "dependencies": { "@types/glob": "^7.1.1", - "array-union": "^1.0.2", + "array-union": "^2.1.0", "dir-glob": "^2.2.2", "fast-glob": "^2.2.6", "glob": "^7.1.3", "ignore": "^5.1.1", - "pify": "^4.0.1", - "slash": "^2.0.0" + "slash": "^3.0.0" }, "devDependencies": { - "ava": "^1.4.1", + "ava": "^2.1.0", "glob-stream": "^6.1.0", "globby": "sindresorhus/globby#master", "matcha": "^0.7.0", diff --git a/test.js b/test.js index b19930d..656bdfc 100644 --- a/test.js +++ b/test.js @@ -171,60 +171,70 @@ test.failing('relative paths and ignores option', t => { [5], function () {}, [function () {}] -].forEach(v => { - const valstring = util.format(v); - const msg = 'Patterns must be a string or an array of strings'; +].forEach(value => { + const valueString = util.format(value); + const message = 'Patterns must be a string or an array of strings'; - test(`rejects the promise for invalid patterns input: ${valstring} - async`, async t => { - await t.throwsAsync(globby(v), TypeError); - await t.throwsAsync(globby(v), msg); + test(`rejects the promise for invalid patterns input: ${valueString} - async`, async t => { + await t.throwsAsync(globby(value), TypeError); + await t.throwsAsync(globby(value), message); }); - test(`throws for invalid patterns input: ${valstring}`, t => { - t.throws(() => globby.sync(v), TypeError); - t.throws(() => globby.sync(v), msg); + test(`throws for invalid patterns input: ${valueString}`, t => { + t.throws(() => { + globby.sync(value); + }, TypeError); + + t.throws(() => { + globby.sync(value); + }, message); }); - test(`generateGlobTasks throws for invalid patterns input: ${valstring}`, t => { - t.throws(() => globby.generateGlobTasks(v), TypeError); - t.throws(() => globby.generateGlobTasks(v), msg); + test(`generateGlobTasks throws for invalid patterns input: ${valueString}`, t => { + t.throws(() => { + globby.generateGlobTasks(value); + }, TypeError); + + t.throws(() => { + globby.generateGlobTasks(value); + }, message); }); }); test('gitignore option defaults to false', async t => { const actual = await globby('*', {onlyFiles: false}); - t.true(actual.indexOf('node_modules') > -1); + t.true(actual.includes('node_modules')); }); test('gitignore option defaults to false - sync', t => { const actual = globby.sync('*', {onlyFiles: false}); - t.true(actual.indexOf('node_modules') > -1); + t.true(actual.includes('node_modules')); }); test('respects gitignore option true', async t => { const actual = await globby('*', {gitignore: true, onlyFiles: false}); - t.false(actual.indexOf('node_modules') > -1); + t.false(actual.includes('node_modules')); }); test('respects gitignore option true - sync', t => { const actual = globby.sync('*', {gitignore: true, onlyFiles: false}); - t.false(actual.indexOf('node_modules') > -1); + t.false(actual.includes('node_modules')); }); test('respects gitignore option false', async t => { const actual = await globby('*', {gitignore: false, onlyFiles: false}); - t.true(actual.indexOf('node_modules') > -1); + t.true(actual.includes('node_modules')); }); test('respects gitignore option false - sync', t => { const actual = globby.sync('*', {gitignore: false, onlyFiles: false}); - t.true(actual.indexOf('node_modules') > -1); + t.true(actual.includes('node_modules')); }); test('gitignore option with stats option', async t => { - const res = await globby('*', {gitignore: true, stats: true}); - const actual = res.map(s => s.path); - t.false(actual.indexOf('node_modules') > -1); + const result = await globby('*', {gitignore: true, stats: true}); + const actual = result.map(x => x.path); + t.false(actual.includes('node_modules')); }); // https://github.com/sindresorhus/globby/issues/97