Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f05a1b0

Browse files
committed
feat: migrate glob implementation to use Node's built-in glob functionality
1 parent d93febe commit f05a1b0

3 files changed

Lines changed: 179 additions & 54 deletions

File tree

src/fs/safe/glob.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { Result } from "@/result";
2+
3+
import { glob as unsafeGlob, globSync as unsafeGlobSync } from "../unsafe/glob";
4+
5+
import type { Glob as UnsafeGlob, GlobSync as UnsafeGlobSync } from "../unsafe/glob";
6+
import type { SetReturnType } from "@/types";
7+
8+
export type {
9+
GlobOptions,
10+
GlobOptionsWithFileTypes,
11+
GlobOptionsWithoutFileTypes,
12+
} from "../unsafe/glob";
13+
14+
export type Glob = SetReturnType<UnsafeGlob, Promise<Result<Awaited<ReturnType<UnsafeGlob>>>>>;
15+
export type GlobSync = SetReturnType<UnsafeGlobSync, Result<ReturnType<UnsafeGlobSync>>>;
16+
17+
const safeGlob = /* #__PURE__ */ Result.wrap(unsafeGlob, Error);
18+
export const glob: Glob = async (...args: [any]) =>
19+
(await safeGlob(...args)).context("Failed to perform glob operation");
20+
21+
const safeGlobSync = /* #__PURE__ */ Result.wrap(unsafeGlobSync, Error);
22+
export const globSync: GlobSync = (...args: [any]) =>
23+
safeGlobSync(...args).context("Failed to perform glob operation");

src/fs/unsafe/glob.ts

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
import fs, { promises as fsp } from "node:fs";
2+
import path from "node:path";
3+
import url from "node:url";
4+
5+
import { isArray, isString, omit } from "@/fp";
6+
7+
import type {
8+
Dirent,
9+
GlobOptions as NodeGlobOptions,
10+
GlobOptionsWithFileTypes as NodeGlobOptionsWithFileTypes,
11+
GlobOptionsWithoutFileTypes as NodeGlobOptionsWithoutFileTypes,
12+
} from "node:fs";
13+
14+
interface BaseGlobOptions {
15+
patterns: string | string[];
16+
17+
/**
18+
* Return absolute paths in the results.
19+
*
20+
* @default false
21+
*/
22+
absolute?: boolean;
23+
/**
24+
* Include files in the results.
25+
*
26+
* @default true
27+
*/
28+
includeFiles?: boolean;
29+
/**
30+
* Include directories in the results.
31+
*
32+
* @default false
33+
*/
34+
includeDirectories?: boolean;
35+
}
36+
37+
export interface GlobOptions extends BaseGlobOptions, NodeGlobOptions {}
38+
39+
export interface GlobOptionsWithFileTypes extends BaseGlobOptions, NodeGlobOptionsWithFileTypes {}
40+
41+
export interface GlobOptionsWithoutFileTypes
42+
extends BaseGlobOptions, NodeGlobOptionsWithoutFileTypes {}
43+
44+
export type Glob = {
45+
(
46+
patterns: GlobOptionsWithFileTypes["patterns"],
47+
options?: Omit<GlobOptionsWithFileTypes, "patterns">,
48+
): Promise<Dirent[]>;
49+
(
50+
patterns: GlobOptionsWithoutFileTypes["patterns"],
51+
options?: Omit<GlobOptionsWithoutFileTypes, "patterns">,
52+
): Promise<string[]>;
53+
(
54+
patterns: GlobOptions["patterns"],
55+
options?: Omit<GlobOptions, "patterns">,
56+
): Promise<(Dirent | string)[]>;
57+
(options: GlobOptionsWithFileTypes): Promise<Dirent[]>;
58+
(options: GlobOptionsWithoutFileTypes): Promise<string[]>;
59+
(options: GlobOptions): Promise<(Dirent | string)[]>;
60+
};
61+
62+
export type GlobSync = {
63+
(
64+
patterns: GlobOptionsWithFileTypes["patterns"],
65+
options?: Omit<GlobOptionsWithFileTypes, "patterns">,
66+
): Dirent[];
67+
(
68+
patterns: GlobOptionsWithoutFileTypes["patterns"],
69+
options?: Omit<GlobOptionsWithoutFileTypes, "patterns">,
70+
): string[];
71+
(
72+
patterns: GlobOptions["patterns"],
73+
options?: Omit<GlobOptions, "patterns">,
74+
): (Dirent | string)[];
75+
(options: GlobOptionsWithFileTypes): Dirent[];
76+
(options: GlobOptionsWithoutFileTypes): string[];
77+
(options: GlobOptions): (Dirent | string)[];
78+
};
79+
80+
const normalizeArgs = (
81+
patternsOrOptions: string | string[] | GlobOptions,
82+
maybeOptions?: Omit<GlobOptions, "patterns">,
83+
) => {
84+
const patternsAsArgument = isString(patternsOrOptions) || isArray(patternsOrOptions);
85+
86+
const patterns = patternsAsArgument ? patternsOrOptions : patternsOrOptions.patterns;
87+
const options = patternsAsArgument ? maybeOptions || {} : omit(patternsOrOptions, ["patterns"]);
88+
89+
if (options.includeFiles === undefined && options.includeDirectories === undefined) {
90+
options.includeFiles = true;
91+
options.includeDirectories = false;
92+
} else if (options.includeFiles === undefined) {
93+
options.includeFiles = !options.includeDirectories;
94+
} else if (options.includeDirectories === undefined) {
95+
options.includeDirectories = !options.includeFiles;
96+
}
97+
98+
return { patterns, options };
99+
};
100+
101+
const processEntries = (entries: Dirent[], options: Omit<GlobOptions, "patterns">) => {
102+
const result = entries.filter(
103+
entry =>
104+
(options.includeFiles && entry.isFile()) ||
105+
(options.includeDirectories && entry.isDirectory()) ||
106+
(!options.includeFiles && !options.includeDirectories),
107+
);
108+
109+
if (options.absolute) {
110+
const cwd =
111+
(options.cwd instanceof URL ? url.fileURLToPath(options.cwd) : options.cwd) ??
112+
process.cwd();
113+
114+
if (!options.withFileTypes) {
115+
return result.map(entry => path.resolve(cwd, entry.parentPath, entry.name));
116+
} else {
117+
for (const entry of entries) {
118+
entry.parentPath = path.resolve(cwd, entry.parentPath);
119+
}
120+
121+
return result;
122+
}
123+
}
124+
125+
if (!options.withFileTypes) {
126+
return result.map(entry => path.join(entry.parentPath, entry.name));
127+
}
128+
129+
return result;
130+
};
131+
132+
/* #__NO_SIDE_EFFECTS__ */
133+
export const glob: Glob = async (...args: [any, any?]): Promise<any[]> => {
134+
const { patterns, options } = normalizeArgs(...args);
135+
136+
const entries = await Array.fromAsync(
137+
fsp.glob(patterns, {
138+
...options,
139+
withFileTypes: true,
140+
}),
141+
);
142+
143+
return processEntries(entries, options);
144+
};
145+
146+
/* #__NO_SIDE_EFFECTS__ */
147+
export const globSync: GlobSync = (...args: [any, any?]): any[] => {
148+
const { patterns, options } = normalizeArgs(...args);
149+
150+
const entries = fs.globSync(patterns, {
151+
...options,
152+
withFileTypes: true,
153+
});
154+
155+
return processEntries(entries, options);
156+
};

src/glob/index.ts

Lines changed: 0 additions & 54 deletions
This file was deleted.

0 commit comments

Comments
 (0)