Skip to content

Commit 2c06ae5

Browse files
committed
Require Node.js 18
1 parent 76c70ab commit 2c06ae5

12 files changed

+130
-128
lines changed

.github/funding.yml

-4
This file was deleted.

.github/workflows/main.yml

+3-4
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,15 @@ jobs:
1010
fail-fast: false
1111
matrix:
1212
node-version:
13+
- 20
1314
- 18
14-
- 16
15-
- 14
1615
os:
1716
- ubuntu-latest
1817
- macos-latest
1918
- windows-latest
2019
steps:
21-
- uses: actions/checkout@v3
22-
- uses: actions/setup-node@v3
20+
- uses: actions/checkout@v4
21+
- uses: actions/setup-node@v4
2322
with:
2423
node-version: ${{ matrix.node-version }}
2524
- run: npm install

bench.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import fs from 'node:fs';
33
import path from 'node:path';
44
import {fileURLToPath} from 'node:url';
55
import Benchmark from 'benchmark';
6-
import rimraf from 'rimraf';
76
import * as globbyMainBranch from '@globby/main-branch';
87
import gs from 'glob-stream';
98
import fastGlob from 'fast-glob';
@@ -83,7 +82,7 @@ const benchs = [
8382

8483
const before = () => {
8584
process.chdir(__dirname);
86-
rimraf.sync(BENCH_DIR);
85+
fs.rmdirSync(BENCH_DIR, {recursive: true});
8786
fs.mkdirSync(BENCH_DIR);
8887
process.chdir(BENCH_DIR);
8988

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

101100
const after = () => {
102101
process.chdir(__dirname);
103-
rimraf.sync(BENCH_DIR);
102+
fs.rmdirSync(BENCH_DIR, {recursive: true});
104103
};
105104

106105
const suites = [];

ignore.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import process from 'node:process';
22
import fs from 'node:fs';
3+
import fsPromises from 'node:fs/promises';
34
import path from 'node:path';
45
import fastGlob from 'fast-glob';
56
import gitIgnore from 'ignore';
67
import slash from 'slash';
7-
import {toPath, isNegativePattern} from './utilities.js';
8+
import {toPath} from 'unicorn-magic';
9+
import {isNegativePattern} from './utilities.js';
810

911
const ignoreFilesGlobOptions = {
1012
ignore: [
@@ -57,7 +59,7 @@ const getIsIgnoredPredicate = (files, cwd) => {
5759
};
5860

5961
const normalizeOptions = (options = {}) => ({
60-
cwd: toPath(options.cwd) || process.cwd(),
62+
cwd: toPath(options.cwd) ?? process.cwd(),
6163
suppressErrors: Boolean(options.suppressErrors),
6264
deep: typeof options.deep === 'number' ? options.deep : Number.POSITIVE_INFINITY,
6365
});
@@ -70,7 +72,7 @@ export const isIgnoredByIgnoreFiles = async (patterns, options) => {
7072
const files = await Promise.all(
7173
paths.map(async filePath => ({
7274
filePath,
73-
content: await fs.promises.readFile(filePath, 'utf8'),
75+
content: await fsPromises.readFile(filePath, 'utf8'),
7476
})),
7577
);
7678

index.d.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import {Options as FastGlobOptions, Entry} from 'fast-glob';
1+
import {type Options as FastGlobOptions, type Entry} from 'fast-glob';
22

33
export type GlobEntry = Entry;
44

5-
export interface GlobTask {
5+
export type GlobTask = {
66
readonly patterns: string[];
77
readonly options: Options;
8-
}
8+
};
99

1010
export type ExpandDirectoriesOption =
1111
| boolean
@@ -14,7 +14,7 @@ export type ExpandDirectoriesOption =
1414

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

17-
export interface Options extends FastGlobOptionsWithoutCwd {
17+
export type Options = {
1818
/**
1919
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.
2020
@@ -61,11 +61,11 @@ export interface Options extends FastGlobOptionsWithoutCwd {
6161
@default process.cwd()
6262
*/
6363
readonly cwd?: URL | string;
64-
}
64+
} & FastGlobOptionsWithoutCwd;
6565

66-
export interface GitignoreOptions {
66+
export type GitignoreOptions = {
6767
readonly cwd?: URL | string;
68-
}
68+
};
6969

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

index.js

+64-31
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,67 @@
1+
import process from 'node:process';
12
import fs from 'node:fs';
23
import nodePath from 'node:path';
3-
import merge2 from 'merge2';
4+
import mergeStreams from '@sindresorhus/merge-streams';
45
import fastGlob from 'fast-glob';
5-
import dirGlob from 'dir-glob';
6+
import {isDirectory, isDirectorySync} from 'path-type';
7+
import {toPath} from 'unicorn-magic';
68
import {
79
GITIGNORE_FILES_PATTERN,
810
isIgnoredByIgnoreFiles,
911
isIgnoredByIgnoreFilesSync,
1012
} from './ignore.js';
11-
import {FilterStream, toPath, isNegativePattern} from './utilities.js';
13+
import {isNegativePattern} from './utilities.js';
1214

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

21+
const normalizePathForDirectoryGlob = (filePath, cwd) => {
22+
const path = isNegativePattern(filePath) ? filePath.slice(1) : filePath;
23+
return nodePath.isAbsolute(path) ? path : nodePath.join(cwd, path);
24+
};
25+
26+
const getDirectoryGlob = ({directoryPath, files, extensions}) => {
27+
const extensionGlob = extensions?.length > 0 ? `.${extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]}` : '';
28+
return files
29+
? files.map(file => nodePath.posix.join(directoryPath, `**/${nodePath.extname(file) ? file : `${file}${extensionGlob}`}`))
30+
: [nodePath.posix.join(directoryPath, `**${extensionGlob ? `/${extensionGlob}` : ''}`)];
31+
};
32+
33+
const directoryToGlob = async (directoryPaths, {
34+
cwd = process.cwd(),
35+
files,
36+
extensions,
37+
} = {}) => {
38+
const globs = await Promise.all(directoryPaths.map(async directoryPath =>
39+
(await isDirectory(normalizePathForDirectoryGlob(directoryPath, cwd))) ? getDirectoryGlob({directoryPath, files, extensions}) : directoryPath),
40+
);
41+
42+
return globs.flat();
43+
};
44+
45+
const directoryToGlobSync = (directoryPaths, {
46+
cwd = process.cwd(),
47+
files,
48+
extensions,
49+
} = {}) => directoryPaths.flatMap(directoryPath => isDirectorySync(normalizePathForDirectoryGlob(directoryPath, cwd)) ? getDirectoryGlob({directoryPath, files, extensions}) : directoryPath);
50+
1951
const toPatternsArray = patterns => {
2052
patterns = [...new Set([patterns].flat())];
2153
assertPatternsInput(patterns);
2254
return patterns;
2355
};
2456

25-
const checkCwdOption = options => {
26-
if (!options.cwd) {
57+
const checkCwdOption = cwd => {
58+
if (!cwd) {
2759
return;
2860
}
2961

3062
let stat;
3163
try {
32-
stat = fs.statSync(options.cwd);
64+
stat = fs.statSync(cwd);
3365
} catch {
3466
return;
3567
}
@@ -42,20 +74,18 @@ const checkCwdOption = options => {
4274
const normalizeOptions = (options = {}) => {
4375
options = {
4476
...options,
45-
ignore: options.ignore || [],
46-
expandDirectories: options.expandDirectories === undefined
47-
? true
48-
: options.expandDirectories,
77+
ignore: options.ignore ?? [],
78+
expandDirectories: options.expandDirectories ?? true,
4979
cwd: toPath(options.cwd),
5080
};
5181

52-
checkCwdOption(options);
82+
checkCwdOption(options.cwd);
5383

5484
return options;
5585
};
5686

57-
const normalizeArguments = fn => async (patterns, options) => fn(toPatternsArray(patterns), normalizeOptions(options));
58-
const normalizeArgumentsSync = fn => (patterns, options) => fn(toPatternsArray(patterns), normalizeOptions(options));
87+
const normalizeArguments = function_ => async (patterns, options) => function_(toPatternsArray(patterns), normalizeOptions(options));
88+
const normalizeArgumentsSync = function_ => (patterns, options) => function_(toPatternsArray(patterns), normalizeOptions(options));
5989

6090
const getIgnoreFilesPatterns = options => {
6191
const {ignoreFiles, gitignore} = options;
@@ -86,16 +116,19 @@ const createFilterFunction = isIgnored => {
86116
const seen = new Set();
87117

88118
return fastGlobResult => {
89-
const path = fastGlobResult.path || fastGlobResult;
90-
const pathKey = nodePath.normalize(path);
91-
const seenOrIgnored = seen.has(pathKey) || (isIgnored && isIgnored(path));
119+
const pathKey = nodePath.normalize(fastGlobResult.path ?? fastGlobResult);
120+
121+
if (seen.has(pathKey) || (isIgnored && isIgnored(pathKey))) {
122+
return false;
123+
}
124+
92125
seen.add(pathKey);
93-
return !seenOrIgnored;
126+
127+
return true;
94128
};
95129
};
96130

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

100133
const convertNegativePatterns = (patterns, options) => {
101134
const tasks = [];
@@ -133,7 +166,7 @@ const convertNegativePatterns = (patterns, options) => {
133166
return tasks;
134167
};
135168

136-
const getDirGlobOptions = (options, cwd) => ({
169+
const normalizeExpandDirectoriesOption = (options, cwd) => ({
137170
...(cwd ? {cwd} : {}),
138171
...(Array.isArray(options) ? {files: options} : options),
139172
});
@@ -147,8 +180,7 @@ const generateTasks = async (patterns, options) => {
147180
return globTasks;
148181
}
149182

150-
const patternExpandOptions = getDirGlobOptions(expandDirectories, cwd);
151-
const ignoreExpandOptions = cwd ? {cwd} : undefined;
183+
const directoryToGlobOptions = normalizeExpandDirectoriesOption(expandDirectories, cwd);
152184

153185
return Promise.all(
154186
globTasks.map(async task => {
@@ -158,8 +190,8 @@ const generateTasks = async (patterns, options) => {
158190
patterns,
159191
options.ignore,
160192
] = await Promise.all([
161-
dirGlob(patterns, patternExpandOptions),
162-
dirGlob(options.ignore, ignoreExpandOptions),
193+
directoryToGlob(patterns, directoryToGlobOptions),
194+
directoryToGlob(options.ignore, {cwd}),
163195
]);
164196

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

170202
const generateTasksSync = (patterns, options) => {
171203
const globTasks = convertNegativePatterns(patterns, options);
172-
173204
const {cwd, expandDirectories} = options;
174205

175206
if (!expandDirectories) {
176207
return globTasks;
177208
}
178209

179-
const patternExpandOptions = getDirGlobOptions(expandDirectories, cwd);
180-
const ignoreExpandOptions = cwd ? {cwd} : undefined;
210+
const directoryToGlobSyncOptions = normalizeExpandDirectoriesOption(expandDirectories, cwd);
181211

182212
return globTasks.map(task => {
183213
let {patterns, options} = task;
184-
patterns = dirGlob.sync(patterns, patternExpandOptions);
185-
options.ignore = dirGlob.sync(options.ignore, ignoreExpandOptions);
214+
patterns = directoryToGlobSync(patterns, directoryToGlobSyncOptions);
215+
options.ignore = directoryToGlobSync(options.ignore, {cwd});
186216
return {patterns, options};
187217
});
188218
};
@@ -195,25 +225,28 @@ export const globby = normalizeArguments(async (patterns, options) => {
195225
generateTasks(patterns, options),
196226
getFilter(options),
197227
]);
198-
const results = await Promise.all(tasks.map(task => fastGlob(task.patterns, task.options)));
199228

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

203233
export const globbySync = normalizeArgumentsSync((patterns, options) => {
204234
const tasks = generateTasksSync(patterns, options);
205235
const filter = getFilterSync(options);
206236
const results = tasks.map(task => fastGlob.sync(task.patterns, task.options));
207-
208237
return unionFastGlobResults(results, filter);
209238
});
210239

211240
export const globbyStream = normalizeArgumentsSync((patterns, options) => {
212241
const tasks = generateTasksSync(patterns, options);
213242
const filter = getFilterSync(options);
214243
const streams = tasks.map(task => fastGlob.stream(task.patterns, task.options));
244+
const stream = mergeStreams(streams).filter(fastGlobResult => filter(fastGlobResult));
245+
246+
// TODO: Make it return a web stream at some point.
247+
// return Readable.toWeb(stream);
215248

216-
return unionFastGlobStreams(streams, filter);
249+
return stream;
217250
});
218251

219252
export const isDynamicPattern = normalizeArgumentsSync(

index.test-d.ts

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import {Buffer} from 'node:buffer';
2-
import {URL} from 'node:url';
1+
import {type Buffer} from 'node:buffer';
32
import {expectType} from 'tsd';
43
import {
5-
GlobTask,
6-
GlobEntry,
7-
GlobbyFilterFunction,
4+
type GlobTask,
5+
type GlobEntry,
6+
type GlobbyFilterFunction,
87
globby,
98
globbySync,
109
globbyStream,

0 commit comments

Comments
 (0)