Skip to content

Commit 5e0847d

Browse files
bartlomiejuclaude
andcommitted
refactor(ext/node): consolidate _fs_readFile.ts and _fs_readlink.ts into fs.ts
Inline `_fs_readFile.ts` and `_fs_readlink.ts` into the main `fs.ts` module. Skip `_fs_read.ts` and `_fs_readdir.ts` for now as they cause circular dependency issues when imported from `_fs_glob.ts` and `promises.ts`. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 9b44f42 commit 5e0847d

File tree

6 files changed

+478
-450
lines changed

6 files changed

+478
-450
lines changed

ext/node/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,8 @@ deno_core::extension!(deno_node,
386386
"_fs/_fs_glob.ts",
387387
"_fs/_fs_lstat.ts",
388388
"_fs/_fs_lutimes.ts",
389+
"_fs/_fs_read.ts",
390+
"_fs/_fs_readdir.ts",
389391
"_next_tick.ts",
390392
"_process/exiting.ts",
391393
"_process/process.ts",

ext/node/polyfills/_fs/_fs_glob.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ import { isMacOS, isWindows } from "ext:deno_node/_util/os.ts";
1313
import { kEmptyObject } from "ext:deno_node/internal/util.mjs";
1414
import process from "node:process";
1515

16-
import { readdirPromise as readdir, readdirSync } from "node:fs";
16+
import {
17+
readdirPromise as readdir,
18+
readdirSync,
19+
} from "ext:deno_node/_fs/_fs_readdir.ts";
1720
import {
1821
lstatPromise as lstat,
1922
lstatSync,

ext/node/polyfills/_fs/_fs_read.ts

Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
// Copyright 2018-2026 the Deno authors. MIT license.
2+
3+
// TODO(petamoriken): enable prefer-primordials for node polyfills
4+
// deno-lint-ignore-file prefer-primordials
5+
6+
import { Buffer } from "node:buffer";
7+
import { ERR_INVALID_ARG_VALUE } from "ext:deno_node/internal/errors.ts";
8+
import * as io from "ext:deno_io/12_io.js";
9+
import {
10+
arrayBufferViewToUint8Array,
11+
getValidatedFd,
12+
validateOffsetLengthRead,
13+
validatePosition,
14+
} from "ext:deno_node/internal/fs/utils.mjs";
15+
import {
16+
validateBuffer,
17+
validateFunction,
18+
validateInteger,
19+
validateObject,
20+
} from "ext:deno_node/internal/validators.mjs";
21+
import { isArrayBufferView } from "ext:deno_node/internal/util/types.ts";
22+
import { op_fs_seek_async, op_fs_seek_sync } from "ext:core/ops";
23+
import { primordials } from "ext:core/mod.js";
24+
import {
25+
customPromisifyArgs,
26+
kEmptyObject,
27+
} from "ext:deno_node/internal/util.mjs";
28+
import * as process from "node:process";
29+
import type { ReadAsyncOptions, ReadSyncOptions } from "node:fs";
30+
31+
const { ObjectDefineProperty } = primordials;
32+
33+
const validateOptionArgs = { __proto__: null, nullable: true };
34+
35+
type BinaryCallback = (
36+
err: Error | null,
37+
bytesRead: number | null,
38+
data?: ArrayBufferView,
39+
) => void;
40+
type Callback = BinaryCallback;
41+
42+
export function read(fd: number, callback: Callback): void;
43+
export function read(
44+
fd: number,
45+
options: ReadAsyncOptions<NodeJS.ArrayBufferView>,
46+
callback: Callback,
47+
): void;
48+
export function read(
49+
fd: number,
50+
buffer: ArrayBufferView,
51+
options: ReadSyncOptions,
52+
callback: Callback,
53+
): void;
54+
export function read(
55+
fd: number,
56+
buffer: ArrayBufferView,
57+
offset: number,
58+
length: number,
59+
position: number | null,
60+
callback: Callback,
61+
): void;
62+
export function read(
63+
fd: number,
64+
optOrBufferOrCb?:
65+
| ArrayBufferView
66+
| ReadAsyncOptions<NodeJS.ArrayBufferView>
67+
| Callback,
68+
offsetOrOpt?:
69+
| number
70+
| ReadAsyncOptions<NodeJS.ArrayBufferView>
71+
| Callback,
72+
lengthOrCb?: number | Callback,
73+
position?: number | null,
74+
callback?: Callback,
75+
) {
76+
fd = getValidatedFd(fd);
77+
78+
let offset = offsetOrOpt;
79+
let buffer = optOrBufferOrCb;
80+
let length = lengthOrCb;
81+
let params = null;
82+
if (arguments.length <= 4) {
83+
if (arguments.length === 4) {
84+
// This is fs.read(fd, buffer, options, callback)
85+
validateObject(offsetOrOpt, "options", validateOptionArgs);
86+
callback = length as Callback;
87+
params = offsetOrOpt;
88+
} else if (arguments.length === 3) {
89+
// This is fs.read(fd, bufferOrParams, callback)
90+
if (!isArrayBufferView(buffer)) {
91+
// This is fs.read(fd, params, callback)
92+
params = buffer;
93+
({ buffer = Buffer.alloc(16384) } = params ?? kEmptyObject);
94+
}
95+
callback = offsetOrOpt as Callback;
96+
} else {
97+
// This is fs.read(fd, callback)
98+
callback = buffer as Callback;
99+
buffer = Buffer.alloc(16384);
100+
}
101+
102+
if (params !== undefined) {
103+
validateObject(params, "options", validateOptionArgs);
104+
}
105+
({
106+
offset = 0,
107+
length = buffer?.byteLength - (offset as number),
108+
position = null,
109+
} = params ?? kEmptyObject);
110+
}
111+
112+
validateBuffer(buffer);
113+
validateFunction(callback, "cb");
114+
115+
if (offset == null) {
116+
offset = 0;
117+
} else {
118+
validateInteger(offset, "offset", 0);
119+
}
120+
121+
(length as number) |= 0;
122+
123+
if (length === 0) {
124+
return process.nextTick(function tick() {
125+
callback!(null, 0, buffer);
126+
});
127+
}
128+
129+
if (buffer.byteLength === 0) {
130+
throw new ERR_INVALID_ARG_VALUE(
131+
"buffer",
132+
buffer,
133+
"is empty and cannot be written",
134+
);
135+
}
136+
137+
validateOffsetLengthRead(offset, length, buffer.byteLength);
138+
139+
if (position == null) {
140+
position = -1;
141+
} else {
142+
validatePosition(position, "position", length as number);
143+
}
144+
145+
(async () => {
146+
try {
147+
let nread: number | null;
148+
if (typeof position === "number" && position >= 0) {
149+
const currentPosition = await op_fs_seek_async(
150+
fd,
151+
0,
152+
io.SeekMode.Current,
153+
);
154+
// We use sync calls below to avoid being affected by others during
155+
// these calls.
156+
op_fs_seek_sync(fd, position, io.SeekMode.Start);
157+
nread = io.readSync(
158+
fd,
159+
arrayBufferViewToUint8Array(buffer).subarray(
160+
offset,
161+
offset + (length as number),
162+
),
163+
);
164+
op_fs_seek_sync(fd, currentPosition, io.SeekMode.Start);
165+
} else {
166+
nread = await io.read(
167+
fd,
168+
arrayBufferViewToUint8Array(buffer).subarray(
169+
offset,
170+
offset + (length as number),
171+
),
172+
);
173+
}
174+
callback!(null, nread ?? 0, buffer);
175+
} catch (error) {
176+
callback!(error as Error, null);
177+
}
178+
})();
179+
}
180+
181+
ObjectDefineProperty(read, customPromisifyArgs, {
182+
__proto__: null,
183+
value: ["bytesRead", "buffer"],
184+
enumerable: false,
185+
});
186+
187+
export function readSync(
188+
fd: number,
189+
buffer: ArrayBufferView,
190+
offset: number,
191+
length: number,
192+
position: number | null,
193+
): number;
194+
export function readSync(
195+
fd: number,
196+
buffer: ArrayBufferView,
197+
opt: ReadSyncOptions,
198+
): number;
199+
export function readSync(
200+
fd: number,
201+
buffer: ArrayBufferView,
202+
offsetOrOpt?: number | ReadSyncOptions,
203+
length?: number,
204+
position?: number | null,
205+
): number {
206+
fd = getValidatedFd(fd);
207+
208+
validateBuffer(buffer);
209+
210+
let offset = offsetOrOpt;
211+
if (arguments.length <= 3 || typeof offsetOrOpt === "object") {
212+
if (offsetOrOpt !== undefined) {
213+
validateObject(offsetOrOpt, "options", validateOptionArgs);
214+
}
215+
216+
({
217+
offset = 0,
218+
length = buffer.byteLength - (offset as number),
219+
position = null,
220+
} = offsetOrOpt ?? kEmptyObject);
221+
}
222+
223+
if (offset === undefined) {
224+
offset = 0;
225+
} else {
226+
validateInteger(offset, "offset", 0);
227+
}
228+
229+
length! |= 0;
230+
231+
if (length === 0) {
232+
return 0;
233+
}
234+
235+
if (buffer.byteLength === 0) {
236+
throw new ERR_INVALID_ARG_VALUE(
237+
"buffer",
238+
buffer,
239+
"is empty and cannot be written",
240+
);
241+
}
242+
243+
validateOffsetLengthRead(offset, length, buffer.byteLength);
244+
245+
if (position == null) {
246+
position = -1;
247+
} else {
248+
validatePosition(position, "position", length);
249+
}
250+
251+
let currentPosition = 0;
252+
if (typeof position === "number" && position >= 0) {
253+
currentPosition = op_fs_seek_sync(fd, 0, io.SeekMode.Current);
254+
op_fs_seek_sync(fd, position, io.SeekMode.Start);
255+
}
256+
257+
const numberOfBytesRead = io.readSync(
258+
fd,
259+
arrayBufferViewToUint8Array(buffer).subarray(offset, offset + length!),
260+
);
261+
262+
if (typeof position === "number" && position >= 0) {
263+
op_fs_seek_sync(fd, currentPosition, io.SeekMode.Start);
264+
}
265+
266+
return numberOfBytesRead ?? 0;
267+
}

0 commit comments

Comments
 (0)