mirror of
https://github.com/denoland/deno.git
synced 2025-07-07 13:25:07 +00:00
feat(node API): add fs.glob
, fs.globSync
, fs.promises.glob
(#28972)
Some checks are pending
ci / pre-build (push) Waiting to run
ci / test debug linux-aarch64 (push) Blocked by required conditions
ci / test release linux-aarch64 (push) Blocked by required conditions
ci / test debug macos-aarch64 (push) Blocked by required conditions
ci / test release macos-aarch64 (push) Blocked by required conditions
ci / bench release linux-x86_64 (push) Blocked by required conditions
ci / lint debug linux-x86_64 (push) Blocked by required conditions
ci / lint debug macos-x86_64 (push) Blocked by required conditions
ci / lint debug windows-x86_64 (push) Blocked by required conditions
ci / test debug linux-x86_64 (push) Blocked by required conditions
ci / test release linux-x86_64 (push) Blocked by required conditions
ci / test debug macos-x86_64 (push) Blocked by required conditions
ci / test release macos-x86_64 (push) Blocked by required conditions
ci / test debug windows-x86_64 (push) Blocked by required conditions
ci / test release windows-x86_64 (push) Blocked by required conditions
ci / build libs (push) Blocked by required conditions
ci / publish canary (push) Blocked by required conditions
Some checks are pending
ci / pre-build (push) Waiting to run
ci / test debug linux-aarch64 (push) Blocked by required conditions
ci / test release linux-aarch64 (push) Blocked by required conditions
ci / test debug macos-aarch64 (push) Blocked by required conditions
ci / test release macos-aarch64 (push) Blocked by required conditions
ci / bench release linux-x86_64 (push) Blocked by required conditions
ci / lint debug linux-x86_64 (push) Blocked by required conditions
ci / lint debug macos-x86_64 (push) Blocked by required conditions
ci / lint debug windows-x86_64 (push) Blocked by required conditions
ci / test debug linux-x86_64 (push) Blocked by required conditions
ci / test release linux-x86_64 (push) Blocked by required conditions
ci / test debug macos-x86_64 (push) Blocked by required conditions
ci / test release macos-x86_64 (push) Blocked by required conditions
ci / test debug windows-x86_64 (push) Blocked by required conditions
ci / test release windows-x86_64 (push) Blocked by required conditions
ci / build libs (push) Blocked by required conditions
ci / publish canary (push) Blocked by required conditions
This commit is contained in:
parent
033da85781
commit
2f72884425
17 changed files with 2730 additions and 178 deletions
|
@ -33,6 +33,7 @@
|
|||
"cli/tsc/dts/typescript.d.ts",
|
||||
"cli/tools/doc/prism.css",
|
||||
"cli/tools/doc/prism.js",
|
||||
"ext/node/polyfills/deps",
|
||||
"ext/websocket/autobahn/reports",
|
||||
"gh-pages",
|
||||
"libs/config/testdata",
|
||||
|
|
|
@ -533,7 +533,6 @@ deno_core::extension!(deno_node,
|
|||
"_fs/_fs_copy.ts",
|
||||
"_fs/_fs_cp.js",
|
||||
"_fs/_fs_dir.ts",
|
||||
"_fs/_fs_dirent.ts",
|
||||
"_fs/_fs_exists.ts",
|
||||
"_fs/_fs_fchmod.ts",
|
||||
"_fs/_fs_fchown.ts",
|
||||
|
@ -542,6 +541,7 @@ deno_core::extension!(deno_node,
|
|||
"_fs/_fs_fsync.ts",
|
||||
"_fs/_fs_ftruncate.ts",
|
||||
"_fs/_fs_futimes.ts",
|
||||
"_fs/_fs_glob.ts",
|
||||
"_fs/_fs_lchmod.ts",
|
||||
"_fs/_fs_lchown.ts",
|
||||
"_fs/_fs_link.ts",
|
||||
|
@ -773,6 +773,10 @@ deno_core::extension!(deno_node,
|
|||
"node:worker_threads" = "worker_threads.ts",
|
||||
"node:zlib" = "zlib.ts",
|
||||
],
|
||||
lazy_loaded_esm = [
|
||||
dir "polyfills",
|
||||
"deps/minimatch.js",
|
||||
],
|
||||
options = {
|
||||
maybe_init: Option<NodeExtInitServices<TInNpmPackageChecker, TNpmPackageFolderResolver, TSys>>,
|
||||
fs: deno_fs::FileSystemRc,
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
import { primordials } from "ext:core/mod.js";
|
||||
import Dirent from "ext:deno_node/_fs/_fs_dirent.ts";
|
||||
import {
|
||||
type Dirent,
|
||||
direntFromDeno,
|
||||
} from "ext:deno_node/internal/fs/utils.mjs";
|
||||
import { assert } from "ext:deno_node/_util/asserts.ts";
|
||||
import { ERR_MISSING_ARGS } from "ext:deno_node/internal/errors.ts";
|
||||
import { TextDecoder } from "ext:deno_web/08_text_encoding.js";
|
||||
|
@ -47,12 +50,12 @@ export default class Dir {
|
|||
AsyncGeneratorPrototypeNext(this.#asyncIterator),
|
||||
(iteratorResult) => {
|
||||
resolve(
|
||||
iteratorResult.done ? null : new Dirent(iteratorResult.value),
|
||||
iteratorResult.done ? null : direntFromDeno(iteratorResult.value),
|
||||
);
|
||||
if (callback) {
|
||||
callback(
|
||||
null,
|
||||
iteratorResult.done ? null : new Dirent(iteratorResult.value),
|
||||
iteratorResult.done ? null : direntFromDeno(iteratorResult.value),
|
||||
);
|
||||
}
|
||||
},
|
||||
|
@ -75,7 +78,7 @@ export default class Dir {
|
|||
if (iteratorResult.done) {
|
||||
return null;
|
||||
} else {
|
||||
return new Dirent(iteratorResult.value);
|
||||
return direntFromDeno(iteratorResult.value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
import { notImplemented } from "ext:deno_node/_utils.ts";
|
||||
|
||||
export default class Dirent {
|
||||
constructor(private entry: Deno.DirEntry & { parentPath: string }) {}
|
||||
|
||||
isBlockDevice(): boolean {
|
||||
notImplemented("Deno does not yet support identification of block devices");
|
||||
return false;
|
||||
}
|
||||
|
||||
isCharacterDevice(): boolean {
|
||||
notImplemented(
|
||||
"Deno does not yet support identification of character devices",
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
isDirectory(): boolean {
|
||||
return this.entry.isDirectory;
|
||||
}
|
||||
|
||||
isFIFO(): boolean {
|
||||
notImplemented(
|
||||
"Deno does not yet support identification of FIFO named pipes",
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
isFile(): boolean {
|
||||
return this.entry.isFile;
|
||||
}
|
||||
|
||||
isSocket(): boolean {
|
||||
notImplemented("Deno does not yet support identification of sockets");
|
||||
return false;
|
||||
}
|
||||
|
||||
isSymbolicLink(): boolean {
|
||||
return this.entry.isSymlink;
|
||||
}
|
||||
|
||||
get name(): string | null {
|
||||
return this.entry.name;
|
||||
}
|
||||
|
||||
get parentPath(): string {
|
||||
return this.entry.parentPath;
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
get path(): string {
|
||||
return this.parentPath;
|
||||
}
|
||||
}
|
1028
ext/node/polyfills/_fs/_fs_glob.ts
Normal file
1028
ext/node/polyfills/_fs/_fs_glob.ts
Normal file
File diff suppressed because it is too large
Load diff
|
@ -4,18 +4,17 @@
|
|||
// deno-lint-ignore-file prefer-primordials
|
||||
|
||||
import { TextDecoder, TextEncoder } from "ext:deno_web/08_text_encoding.js";
|
||||
import Dirent from "ext:deno_node/_fs/_fs_dirent.ts";
|
||||
import { denoErrorToNodeError } from "ext:deno_node/internal/errors.ts";
|
||||
import { getValidatedPath } from "ext:deno_node/internal/fs/utils.mjs";
|
||||
import {
|
||||
type Dirent,
|
||||
direntFromDeno,
|
||||
getValidatedPath,
|
||||
} from "ext:deno_node/internal/fs/utils.mjs";
|
||||
import { Buffer } from "node:buffer";
|
||||
import { promisify } from "ext:deno_node/internal/util.mjs";
|
||||
import { op_fs_read_dir_async, op_fs_read_dir_sync } from "ext:core/ops";
|
||||
import { join, relative } from "node:path";
|
||||
|
||||
function toDirent(val: Deno.DirEntry & { parentPath: string }): Dirent {
|
||||
return new Dirent(val);
|
||||
}
|
||||
|
||||
type readDirOptions = {
|
||||
encoding?: string;
|
||||
withFileTypes?: boolean;
|
||||
|
@ -83,7 +82,7 @@ export function readdir(
|
|||
|
||||
if (options?.withFileTypes) {
|
||||
entry.parentPath = current;
|
||||
result.push(toDirent(entry));
|
||||
result.push(direntFromDeno(entry));
|
||||
} else {
|
||||
let name = decode(entry.name, options?.encoding);
|
||||
if (options?.recursive) {
|
||||
|
@ -166,7 +165,7 @@ export function readdirSync(
|
|||
|
||||
if (options?.withFileTypes) {
|
||||
entry.parentPath = current;
|
||||
result.push(toDirent(entry));
|
||||
result.push(direntFromDeno(entry));
|
||||
} else {
|
||||
let name = decode(entry.name, options?.encoding);
|
||||
if (options?.recursive) {
|
||||
|
|
1615
ext/node/polyfills/deps/minimatch.js
Normal file
1615
ext/node/polyfills/deps/minimatch.js
Normal file
File diff suppressed because it is too large
Load diff
|
@ -20,7 +20,6 @@ import {
|
|||
} from "ext:deno_node/_fs/_fs_copy.ts";
|
||||
import { cp, cpPromise, cpSync } from "ext:deno_node/_fs/_fs_cp.js";
|
||||
import Dir from "ext:deno_node/_fs/_fs_dir.ts";
|
||||
import Dirent from "ext:deno_node/_fs/_fs_dirent.ts";
|
||||
import { exists, existsSync } from "ext:deno_node/_fs/_fs_exists.ts";
|
||||
import { fchmod, fchmodSync } from "ext:deno_node/_fs/_fs_fchmod.ts";
|
||||
import { fchown, fchownSync } from "ext:deno_node/_fs/_fs_fchown.ts";
|
||||
|
@ -140,7 +139,11 @@ import {
|
|||
ReadStream,
|
||||
WriteStream,
|
||||
} from "ext:deno_node/internal/fs/streams.mjs";
|
||||
import { toUnixTimestamp as _toUnixTimestamp } from "ext:deno_node/internal/fs/utils.mjs";
|
||||
import {
|
||||
Dirent,
|
||||
toUnixTimestamp as _toUnixTimestamp,
|
||||
} from "ext:deno_node/internal/fs/utils.mjs";
|
||||
import { glob, globPromise, globSync } from "ext:deno_node/_fs/_fs_glob.ts";
|
||||
|
||||
const {
|
||||
F_OK,
|
||||
|
@ -168,6 +171,7 @@ const promises = {
|
|||
constants,
|
||||
copyFile: copyFilePromise,
|
||||
cp: cpPromise,
|
||||
glob: globPromise,
|
||||
open: openPromise,
|
||||
opendir: opendirPromise,
|
||||
rename: renamePromise,
|
||||
|
@ -235,6 +239,8 @@ export default {
|
|||
ftruncateSync,
|
||||
futimes,
|
||||
futimesSync,
|
||||
glob,
|
||||
globSync,
|
||||
lchmod,
|
||||
lchmodSync,
|
||||
lchown,
|
||||
|
@ -356,6 +362,8 @@ export {
|
|||
ftruncateSync,
|
||||
futimes,
|
||||
futimesSync,
|
||||
glob,
|
||||
globSync,
|
||||
lchmod,
|
||||
lchmodSync,
|
||||
link,
|
||||
|
|
|
@ -32,5 +32,6 @@ export const appendFile = fsPromises.appendFile;
|
|||
export const readFile = fsPromises.readFile;
|
||||
export const watch = fsPromises.watch;
|
||||
export const cp = fsPromises.cp;
|
||||
export const glob = fsPromises.glob;
|
||||
|
||||
export default fsPromises;
|
||||
|
|
|
@ -159,8 +159,9 @@ export function assertEncoding(encoding) {
|
|||
}
|
||||
|
||||
export class Dirent {
|
||||
constructor(name, type) {
|
||||
constructor(name, type, path) {
|
||||
this.name = name;
|
||||
this.parentPath = path;
|
||||
this[kType] = type;
|
||||
}
|
||||
|
||||
|
@ -193,9 +194,23 @@ export class Dirent {
|
|||
}
|
||||
}
|
||||
|
||||
class DirentFromStats extends Dirent {
|
||||
constructor(name, stats) {
|
||||
super(name, null);
|
||||
export function direntFromDeno(entry) {
|
||||
let type;
|
||||
|
||||
if (entry.isDirectory) {
|
||||
type = UV_DIRENT_DIR;
|
||||
} else if (entry.isFile) {
|
||||
type = UV_DIRENT_FILE;
|
||||
} else if (entry.isSymlink) {
|
||||
type = UV_DIRENT_LINK;
|
||||
}
|
||||
|
||||
return new Dirent(entry.name, type, entry.parentPath);
|
||||
}
|
||||
|
||||
export class DirentFromStats extends Dirent {
|
||||
constructor(name, stats, path) {
|
||||
super(name, null, path);
|
||||
this[kStats] = stats;
|
||||
}
|
||||
}
|
||||
|
@ -277,13 +292,13 @@ export function getDirents(path, { 0: names, 1: types }, callback) {
|
|||
callback(err);
|
||||
return;
|
||||
}
|
||||
names[idx] = new DirentFromStats(name, stats);
|
||||
names[idx] = new DirentFromStats(name, stats, path);
|
||||
if (--toFinish === 0) {
|
||||
callback(null, names);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
names[i] = new Dirent(names[i], types[i]);
|
||||
names[i] = new Dirent(names[i], types[i], path);
|
||||
}
|
||||
}
|
||||
if (toFinish === 0) {
|
||||
|
@ -313,16 +328,16 @@ export function getDirent(path, name, type, callback) {
|
|||
callback(err);
|
||||
return;
|
||||
}
|
||||
callback(null, new DirentFromStats(name, stats));
|
||||
callback(null, new DirentFromStats(name, stats, path));
|
||||
});
|
||||
} else {
|
||||
callback(null, new Dirent(name, type));
|
||||
callback(null, new Dirent(name, type, path));
|
||||
}
|
||||
} else if (type === UV_DIRENT_UNKNOWN) {
|
||||
const stats = lstatSync(join(path, name));
|
||||
return new DirentFromStats(name, stats);
|
||||
return new DirentFromStats(name, stats, path);
|
||||
} else {
|
||||
return new Dirent(name, type);
|
||||
return new Dirent(name, type, path);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@ util::unit_test_factory!(
|
|||
_fs_close_test = _fs / _fs_close_test,
|
||||
_fs_copy_test = _fs / _fs_copy_test,
|
||||
_fs_dir_test = _fs / _fs_dir_test,
|
||||
_fs_dirent_test = _fs / _fs_dirent_test,
|
||||
_fs_open_test = _fs / _fs_open_test,
|
||||
_fs_read_test = _fs / _fs_read_test,
|
||||
_fs_exists_test = _fs / _fs_exists_test,
|
||||
|
|
|
@ -1354,7 +1354,8 @@
|
|||
"sequential/test-debugger-pid.js" = {}
|
||||
"sequential/test-diagnostic-dir-cpu-prof.js" = {}
|
||||
"sequential/test-diagnostic-dir-heap-prof.js" = {}
|
||||
"sequential/test-fs-readdir-recursive.js" = {}
|
||||
# TODO(kt3k): Enable this when node_test is updated to v24.x
|
||||
# "sequential/test-fs-readdir-recursive.js" = {}
|
||||
"sequential/test-fs-stat-sync-overflow.js" = {}
|
||||
"sequential/test-http-server-keep-alive-timeout-slow-server.js" = {}
|
||||
"sequential/test-inspector-open-dispose.mjs" = {}
|
||||
|
|
|
@ -1,95 +0,0 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
import { assert, assertEquals, assertThrows } from "@std/assert";
|
||||
import { Dirent as Dirent_ } from "node:fs";
|
||||
|
||||
// deno-lint-ignore no-explicit-any
|
||||
const Dirent = Dirent_ as any;
|
||||
|
||||
class DirEntryMock implements Deno.DirEntry {
|
||||
parentPath = "";
|
||||
name = "";
|
||||
isFile = false;
|
||||
isDirectory = false;
|
||||
isSymlink = false;
|
||||
}
|
||||
|
||||
Deno.test({
|
||||
name: "Directories are correctly identified",
|
||||
fn() {
|
||||
const entry: DirEntryMock = new DirEntryMock();
|
||||
entry.isDirectory = true;
|
||||
entry.isFile = false;
|
||||
entry.isSymlink = false;
|
||||
assert(new Dirent(entry).isDirectory());
|
||||
assert(!new Dirent(entry).isFile());
|
||||
assert(!new Dirent(entry).isSymbolicLink());
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "Files are correctly identified",
|
||||
fn() {
|
||||
const entry: DirEntryMock = new DirEntryMock();
|
||||
entry.isDirectory = false;
|
||||
entry.isFile = true;
|
||||
entry.isSymlink = false;
|
||||
assert(!new Dirent(entry).isDirectory());
|
||||
assert(new Dirent(entry).isFile());
|
||||
assert(!new Dirent(entry).isSymbolicLink());
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "Symlinks are correctly identified",
|
||||
fn() {
|
||||
const entry: DirEntryMock = new DirEntryMock();
|
||||
entry.isDirectory = false;
|
||||
entry.isFile = false;
|
||||
entry.isSymlink = true;
|
||||
assert(!new Dirent(entry).isDirectory());
|
||||
assert(!new Dirent(entry).isFile());
|
||||
assert(new Dirent(entry).isSymbolicLink());
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "File name is correct",
|
||||
fn() {
|
||||
const entry: DirEntryMock = new DirEntryMock();
|
||||
entry.name = "my_file";
|
||||
assertEquals(new Dirent(entry).name, "my_file");
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "Socket and FIFO pipes aren't yet available",
|
||||
fn() {
|
||||
const entry: DirEntryMock = new DirEntryMock();
|
||||
assertThrows(
|
||||
() => {
|
||||
new Dirent(entry).isFIFO();
|
||||
},
|
||||
Error,
|
||||
"does not yet support",
|
||||
);
|
||||
assertThrows(
|
||||
() => {
|
||||
new Dirent(entry).isSocket();
|
||||
},
|
||||
Error,
|
||||
"does not yet support",
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "Path and parent path is correct",
|
||||
fn() {
|
||||
const entry: DirEntryMock = new DirEntryMock();
|
||||
entry.name = "my_file";
|
||||
entry.parentPath = "/home/user";
|
||||
assertEquals(new Dirent(entry).name, "my_file");
|
||||
assertEquals(new Dirent(entry).path, "/home/user");
|
||||
assertEquals(new Dirent(entry).parentPath, "/home/user");
|
||||
},
|
||||
});
|
|
@ -44,6 +44,7 @@ export async function checkCopyright() {
|
|||
":!:tests/unit_node/testdata/**",
|
||||
":!:tests/wpt/suite/**",
|
||||
":!:libs/config/testdata/**",
|
||||
":!:ext/node/polyfills/deps/**",
|
||||
|
||||
// rust
|
||||
"*.rs",
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
"ext:deno_node/_fs/_fs_common.ts": "../ext/node/polyfills/_fs/_fs_common.ts",
|
||||
"ext:deno_node/_fs/_fs_constants.ts": "../ext/node/polyfills/_fs/_fs_constants.ts",
|
||||
"ext:deno_node/_fs/_fs_dir.ts": "../ext/node/polyfills/_fs/_fs_dir.ts",
|
||||
"ext:deno_node/_fs/_fs_dirent.ts": "../ext/node/polyfills/_fs/_fs_dirent.ts",
|
||||
"ext:deno_node/_fs/_fs_exists.ts": "../ext/node/polyfills/_fs/_fs_exists.ts",
|
||||
"ext:deno_node/_fs/_fs_lstat.ts": "../ext/node/polyfills/_fs/_fs_lstat.ts",
|
||||
"ext:deno_node/_fs/_fs_mkdir.ts": "../ext/node/polyfills/_fs/_fs_mkdir.ts",
|
||||
|
|
26
tools/generate_minimatch_dep.js
Executable file
26
tools/generate_minimatch_dep.js
Executable file
|
@ -0,0 +1,26 @@
|
|||
#!/usr/bin/env -S deno run --allow-write --allow-run --allow-env --allow-read
|
||||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
import { join } from "./util.js";
|
||||
|
||||
const dir = await Deno.makeTempDir();
|
||||
|
||||
const installCommand = new Deno.Command(Deno.execPath(), {
|
||||
cwd: dir,
|
||||
args: ["install", "--node-modules-dir=auto", "npm:esbuild", "npm:minimatch"],
|
||||
});
|
||||
await installCommand.output();
|
||||
|
||||
const bundleCommand = new Deno.Command(
|
||||
join(dir, "./node_modules/.bin/esbuild"),
|
||||
{
|
||||
cwd: dir,
|
||||
args: [
|
||||
"./node_modules/minimatch/dist/commonjs/index.js",
|
||||
"--bundle",
|
||||
"--format=esm",
|
||||
],
|
||||
},
|
||||
);
|
||||
const output = await bundleCommand.output();
|
||||
|
||||
await Deno.writeFile("./ext/node/polyfills/deps/minimatch.js", output.stdout);
|
|
@ -66,6 +66,7 @@ async function dlint() {
|
|||
":!:cli/tsc/dts/**",
|
||||
":!:cli/tsc/*typescript.js",
|
||||
":!:cli/tsc/compiler.d.ts",
|
||||
":!:ext/node/polyfills/deps/**",
|
||||
":!:runtime/examples/",
|
||||
":!:target/",
|
||||
":!:tests/ffi/tests/test.js",
|
||||
|
@ -121,6 +122,7 @@ async function dlintPreferPrimordials() {
|
|||
"ext/**/*.ts",
|
||||
":!:ext/**/*.d.ts",
|
||||
"ext/node/polyfills/*.mjs",
|
||||
":!:ext/node/polyfills/deps/**",
|
||||
]);
|
||||
|
||||
if (!sourceFiles.length) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue