Skip to content

Commit

Permalink
Require Node.js 18
Browse files Browse the repository at this point in the history
  • Loading branch information
sindresorhus committed Nov 9, 2023
1 parent 76c70ab commit 2c06ae5
Show file tree
Hide file tree
Showing 12 changed files with 130 additions and 128 deletions.
4 changes: 0 additions & 4 deletions .github/funding.yml

This file was deleted.

7 changes: 3 additions & 4 deletions .github/workflows/main.yml
Expand Up @@ -10,16 +10,15 @@ jobs:
fail-fast: false
matrix:
node-version:
- 20
- 18
- 16
- 14
os:
- ubuntu-latest
- macos-latest
- windows-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm install
Expand Down
5 changes: 2 additions & 3 deletions bench.js
Expand Up @@ -3,7 +3,6 @@ import fs from 'node:fs';
import path from 'node:path';
import {fileURLToPath} from 'node:url';
import Benchmark from 'benchmark';
import rimraf from 'rimraf';
import * as globbyMainBranch from '@globby/main-branch';
import gs from 'glob-stream';
import fastGlob from 'fast-glob';
Expand Down Expand Up @@ -83,7 +82,7 @@ const benchs = [

const before = () => {
process.chdir(__dirname);
rimraf.sync(BENCH_DIR);
fs.rmdirSync(BENCH_DIR, {recursive: true});
fs.mkdirSync(BENCH_DIR);
process.chdir(BENCH_DIR);

Expand All @@ -100,7 +99,7 @@ const before = () => {

const after = () => {
process.chdir(__dirname);
rimraf.sync(BENCH_DIR);
fs.rmdirSync(BENCH_DIR, {recursive: true});
};

const suites = [];
Expand Down
8 changes: 5 additions & 3 deletions ignore.js
@@ -1,10 +1,12 @@
import process from 'node:process';
import fs from 'node:fs';
import fsPromises from 'node:fs/promises';
import path from 'node:path';
import fastGlob from 'fast-glob';
import gitIgnore from 'ignore';
import slash from 'slash';
import {toPath, isNegativePattern} from './utilities.js';
import {toPath} from 'unicorn-magic';
import {isNegativePattern} from './utilities.js';

const ignoreFilesGlobOptions = {
ignore: [
Expand Down Expand Up @@ -57,7 +59,7 @@ const getIsIgnoredPredicate = (files, cwd) => {
};

const normalizeOptions = (options = {}) => ({
cwd: toPath(options.cwd) || process.cwd(),
cwd: toPath(options.cwd) ?? process.cwd(),
suppressErrors: Boolean(options.suppressErrors),
deep: typeof options.deep === 'number' ? options.deep : Number.POSITIVE_INFINITY,
});
Expand All @@ -70,7 +72,7 @@ export const isIgnoredByIgnoreFiles = async (patterns, options) => {
const files = await Promise.all(
paths.map(async filePath => ({
filePath,
content: await fs.promises.readFile(filePath, 'utf8'),
content: await fsPromises.readFile(filePath, 'utf8'),
})),
);

Expand Down
14 changes: 7 additions & 7 deletions index.d.ts
@@ -1,11 +1,11 @@
import {Options as FastGlobOptions, Entry} from 'fast-glob';
import {type Options as FastGlobOptions, type Entry} from 'fast-glob';

export type GlobEntry = Entry;

export interface GlobTask {
export type GlobTask = {
readonly patterns: string[];
readonly options: Options;
}
};

export type ExpandDirectoriesOption =
| boolean
Expand All @@ -14,7 +14,7 @@ export type ExpandDirectoriesOption =

type FastGlobOptionsWithoutCwd = Omit<FastGlobOptions, 'cwd'>;

export interface Options extends FastGlobOptionsWithoutCwd {
export type Options = {
/**
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.
Expand Down Expand Up @@ -61,11 +61,11 @@ export interface Options extends FastGlobOptionsWithoutCwd {
@default process.cwd()
*/
readonly cwd?: URL | string;
}
} & FastGlobOptionsWithoutCwd;

export interface GitignoreOptions {
export type GitignoreOptions = {
readonly cwd?: URL | string;
}
};

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

Expand Down
95 changes: 64 additions & 31 deletions index.js
@@ -1,35 +1,67 @@
import process from 'node:process';
import fs from 'node:fs';
import nodePath from 'node:path';
import merge2 from 'merge2';
import mergeStreams from '@sindresorhus/merge-streams';
import fastGlob from 'fast-glob';
import dirGlob from 'dir-glob';
import {isDirectory, isDirectorySync} from 'path-type';
import {toPath} from 'unicorn-magic';
import {
GITIGNORE_FILES_PATTERN,
isIgnoredByIgnoreFiles,
isIgnoredByIgnoreFilesSync,
} from './ignore.js';
import {FilterStream, toPath, isNegativePattern} from './utilities.js';
import {isNegativePattern} from './utilities.js';

const assertPatternsInput = patterns => {
if (patterns.some(pattern => typeof pattern !== 'string')) {
throw new TypeError('Patterns must be a string or an array of strings');
}
};

const normalizePathForDirectoryGlob = (filePath, cwd) => {
const path = isNegativePattern(filePath) ? filePath.slice(1) : filePath;
return nodePath.isAbsolute(path) ? path : nodePath.join(cwd, path);
};

const getDirectoryGlob = ({directoryPath, files, extensions}) => {
const extensionGlob = extensions?.length > 0 ? `.${extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]}` : '';
return files
? files.map(file => nodePath.posix.join(directoryPath, `**/${nodePath.extname(file) ? file : `${file}${extensionGlob}`}`))
: [nodePath.posix.join(directoryPath, `**${extensionGlob ? `/${extensionGlob}` : ''}`)];
};

const directoryToGlob = async (directoryPaths, {
cwd = process.cwd(),
files,
extensions,
} = {}) => {
const globs = await Promise.all(directoryPaths.map(async directoryPath =>
(await isDirectory(normalizePathForDirectoryGlob(directoryPath, cwd))) ? getDirectoryGlob({directoryPath, files, extensions}) : directoryPath),
);

return globs.flat();
};

const directoryToGlobSync = (directoryPaths, {
cwd = process.cwd(),
files,
extensions,
} = {}) => directoryPaths.flatMap(directoryPath => isDirectorySync(normalizePathForDirectoryGlob(directoryPath, cwd)) ? getDirectoryGlob({directoryPath, files, extensions}) : directoryPath);

const toPatternsArray = patterns => {
patterns = [...new Set([patterns].flat())];
assertPatternsInput(patterns);
return patterns;
};

const checkCwdOption = options => {
if (!options.cwd) {
const checkCwdOption = cwd => {
if (!cwd) {
return;
}

let stat;
try {
stat = fs.statSync(options.cwd);
stat = fs.statSync(cwd);
} catch {
return;
}
Expand All @@ -42,20 +74,18 @@ const checkCwdOption = options => {
const normalizeOptions = (options = {}) => {
options = {
...options,
ignore: options.ignore || [],
expandDirectories: options.expandDirectories === undefined
? true
: options.expandDirectories,
ignore: options.ignore ?? [],
expandDirectories: options.expandDirectories ?? true,
cwd: toPath(options.cwd),
};

checkCwdOption(options);
checkCwdOption(options.cwd);

return options;
};

const normalizeArguments = fn => async (patterns, options) => fn(toPatternsArray(patterns), normalizeOptions(options));
const normalizeArgumentsSync = fn => (patterns, options) => fn(toPatternsArray(patterns), normalizeOptions(options));
const normalizeArguments = function_ => async (patterns, options) => function_(toPatternsArray(patterns), normalizeOptions(options));
const normalizeArgumentsSync = function_ => (patterns, options) => function_(toPatternsArray(patterns), normalizeOptions(options));

const getIgnoreFilesPatterns = options => {
const {ignoreFiles, gitignore} = options;
Expand Down Expand Up @@ -86,16 +116,19 @@ const createFilterFunction = isIgnored => {
const seen = new Set();

return fastGlobResult => {
const path = fastGlobResult.path || fastGlobResult;
const pathKey = nodePath.normalize(path);
const seenOrIgnored = seen.has(pathKey) || (isIgnored && isIgnored(path));
const pathKey = nodePath.normalize(fastGlobResult.path ?? fastGlobResult);

if (seen.has(pathKey) || (isIgnored && isIgnored(pathKey))) {
return false;
}

seen.add(pathKey);
return !seenOrIgnored;

return true;
};
};

const unionFastGlobResults = (results, filter) => results.flat().filter(fastGlobResult => filter(fastGlobResult));
const unionFastGlobStreams = (streams, filter) => merge2(streams).pipe(new FilterStream(fastGlobResult => filter(fastGlobResult)));

const convertNegativePatterns = (patterns, options) => {
const tasks = [];
Expand Down Expand Up @@ -133,7 +166,7 @@ const convertNegativePatterns = (patterns, options) => {
return tasks;
};

const getDirGlobOptions = (options, cwd) => ({
const normalizeExpandDirectoriesOption = (options, cwd) => ({
...(cwd ? {cwd} : {}),
...(Array.isArray(options) ? {files: options} : options),
});
Expand All @@ -147,8 +180,7 @@ const generateTasks = async (patterns, options) => {
return globTasks;
}

const patternExpandOptions = getDirGlobOptions(expandDirectories, cwd);
const ignoreExpandOptions = cwd ? {cwd} : undefined;
const directoryToGlobOptions = normalizeExpandDirectoriesOption(expandDirectories, cwd);

return Promise.all(
globTasks.map(async task => {
Expand All @@ -158,8 +190,8 @@ const generateTasks = async (patterns, options) => {
patterns,
options.ignore,
] = await Promise.all([
dirGlob(patterns, patternExpandOptions),
dirGlob(options.ignore, ignoreExpandOptions),
directoryToGlob(patterns, directoryToGlobOptions),
directoryToGlob(options.ignore, {cwd}),
]);

return {patterns, options};
Expand All @@ -169,20 +201,18 @@ const generateTasks = async (patterns, options) => {

const generateTasksSync = (patterns, options) => {
const globTasks = convertNegativePatterns(patterns, options);

const {cwd, expandDirectories} = options;

if (!expandDirectories) {
return globTasks;
}

const patternExpandOptions = getDirGlobOptions(expandDirectories, cwd);
const ignoreExpandOptions = cwd ? {cwd} : undefined;
const directoryToGlobSyncOptions = normalizeExpandDirectoriesOption(expandDirectories, cwd);

return globTasks.map(task => {
let {patterns, options} = task;
patterns = dirGlob.sync(patterns, patternExpandOptions);
options.ignore = dirGlob.sync(options.ignore, ignoreExpandOptions);
patterns = directoryToGlobSync(patterns, directoryToGlobSyncOptions);
options.ignore = directoryToGlobSync(options.ignore, {cwd});
return {patterns, options};
});
};
Expand All @@ -195,25 +225,28 @@ export const globby = normalizeArguments(async (patterns, options) => {
generateTasks(patterns, options),
getFilter(options),
]);
const results = await Promise.all(tasks.map(task => fastGlob(task.patterns, task.options)));

const results = await Promise.all(tasks.map(task => fastGlob(task.patterns, task.options)));
return unionFastGlobResults(results, filter);
});

export const globbySync = normalizeArgumentsSync((patterns, options) => {
const tasks = generateTasksSync(patterns, options);
const filter = getFilterSync(options);
const results = tasks.map(task => fastGlob.sync(task.patterns, task.options));

return unionFastGlobResults(results, filter);
});

export const globbyStream = normalizeArgumentsSync((patterns, options) => {
const tasks = generateTasksSync(patterns, options);
const filter = getFilterSync(options);
const streams = tasks.map(task => fastGlob.stream(task.patterns, task.options));
const stream = mergeStreams(streams).filter(fastGlobResult => filter(fastGlobResult));

// TODO: Make it return a web stream at some point.
// return Readable.toWeb(stream);

return unionFastGlobStreams(streams, filter);
return stream;
});

export const isDynamicPattern = normalizeArgumentsSync(
Expand Down
9 changes: 4 additions & 5 deletions index.test-d.ts
@@ -1,10 +1,9 @@
import {Buffer} from 'node:buffer';
import {URL} from 'node:url';
import {type Buffer} from 'node:buffer';
import {expectType} from 'tsd';
import {
GlobTask,
GlobEntry,
GlobbyFilterFunction,
type GlobTask,
type GlobEntry,
type GlobbyFilterFunction,
globby,
globbySync,
globbyStream,
Expand Down

0 comments on commit 2c06ae5

Please sign in to comment.