From 3eb1ba85cf1bea4f980a80a07e4c38f680282aff Mon Sep 17 00:00:00 2001 From: Daniel Rahmanto Date: Sun, 28 Sep 2025 21:50:15 +0700 Subject: [PATCH 1/3] fix(ext/node): fs.stat and fs.statSync compatibility --- cli/rt/file_system.rs | 6 +- cli/tsc/dts/lib.deno.ns.d.ts | 14 +- ext/fs/30_fs.js | 38 +- ext/fs/ops.rs | 17 +- ext/io/fs.rs | 26 +- ext/io/lib.rs | 6 + ext/node/polyfills/_fs/_fs_stat.ts | 522 ++++++++--------------- ext/node/polyfills/internal/fs/utils.mjs | 70 ++- 8 files changed, 313 insertions(+), 386 deletions(-) diff --git a/cli/rt/file_system.rs b/cli/rt/file_system.rs index b4ed8c2bff1079..9c9ad57bfc1f85 100644 --- a/cli/rt/file_system.rs +++ b/cli/rt/file_system.rs @@ -1443,13 +1443,13 @@ impl FileBackedVfsMetadata { blksize: 0, size: self.len, dev: 0, - ino: 0, + ino: None, mode: 0, - nlink: 0, + nlink: None, uid: 0, gid: 0, rdev: 0, - blocks: 0, + blocks: None, is_block_device: false, is_char_device: false, is_fifo: false, diff --git a/cli/tsc/dts/lib.deno.ns.d.ts b/cli/tsc/dts/lib.deno.ns.d.ts index 4ac2ec96880218..3097f59eea5927 100644 --- a/cli/tsc/dts/lib.deno.ns.d.ts +++ b/cli/tsc/dts/lib.deno.ns.d.ts @@ -3054,17 +3054,15 @@ declare namespace Deno { ctime: Date | null; /** ID of the device containing the file. */ dev: number; - /** Inode number. - * - * _Linux/Mac OS only._ */ + /** Corresponds to the inode number on Unix systems. On Windows, this is + * the file index number that is unique within a volume. This may not be + * available on all platforms. */ ino: number | null; /** The underlying raw `st_mode` bits that contain the standard Unix * permissions for this file/directory. */ mode: number | null; - /** Number of hard links pointing to this file. - * - * _Linux/Mac OS only._ */ + /** Number of hard links pointing to this file. */ nlink: number | null; /** User ID of the owner of this file. * @@ -3082,9 +3080,7 @@ declare namespace Deno { * * _Linux/Mac OS only._ */ blksize: number | null; - /** Number of blocks allocated to the file, in 512-byte units. - * - * _Linux/Mac OS only._ */ + /** Number of blocks allocated to the file, in 512-byte units. */ blocks: number | null; /** True if this is info for a block device. * diff --git a/ext/fs/30_fs.js b/ext/fs/30_fs.js index f371090e415494..16653592826edd 100644 --- a/ext/fs/30_fs.js +++ b/ext/fs/30_fs.js @@ -278,7 +278,7 @@ async function rename(oldpath, newpath) { // Extract the FsStat object from the encoded buffer. // See `runtime/ops/fs.rs` for the encoder. // -// This is not a general purpose decoder. There are 4 types: +// This is not a general purpose decoder. There are 5 types: // // 1. date // offset += 4 @@ -295,6 +295,14 @@ async function rename(oldpath, newpath) { // // 4. ?u64 converts a zero u64 value to JS null on Windows. // ?bool converts a false bool value to JS null on Windows. +// +// 5. !u64 persists the u64 value even if it's zero, +// only if the corresponding "_set" field is set to true. +// Unlike ?u64, this is OS agnostic. +// offset += 4 +// 1/0 | extra padding | high u32 | low u32 +// if value[0] == 1, u64 else null +// function createByteStruct(types) { // types can be "date", "bool" or "u64". let offset = 0; @@ -304,18 +312,24 @@ function createByteStruct(types) { for (let i = 0; i < typeEntries.length; ++i) { let { 0: name, 1: type } = typeEntries[i]; - const optional = StringPrototypeStartsWith(type, "?"); - if (optional) type = StringPrototypeSlice(type, 1); + const optionalLoose = StringPrototypeStartsWith(type, "?"); + const optionalStrict = StringPrototypeStartsWith(type, "!"); + if (optionalLoose || optionalStrict) type = StringPrototypeSlice(type, 1); if (type == "u64") { - if (!optional) { + if (!optionalLoose && !optionalStrict) { str += `${name}: view[${offset}] + view[${offset + 1}] * 2**32,`; - } else { + } else if (optionalLoose) { str += `${name}: (unix ? (view[${offset}] + view[${ offset + 1 }] * 2**32) : (view[${offset}] + view[${ offset + 1 }] * 2**32) || null),`; + } else { + str += `${name}: (view[${offset}] === 1 ? (view[${offset + 2}] + view[${ + offset + 3 + }] * 2**32) : null),`; + offset += 2; } } else if (type == "date") { str += `${name}: view[${offset}] === 0 ? null : new Date(view[${ @@ -323,7 +337,7 @@ function createByteStruct(types) { }] + view[${offset + 3}] * 2**32),`; offset += 2; } else { - if (!optional) { + if (!optionalLoose) { str += `${name}: !!(view[${offset}] + view[${offset + 1}] * 2**32),`; } else { str += `${name}: (unix ? !!((view[${offset}] + view[${ @@ -350,14 +364,14 @@ const { 0: statStruct, 1: statBuf } = createByteStruct({ birthtime: "date", ctime: "date", dev: "u64", - ino: "?u64", + ino: "!u64", mode: "u64", - nlink: "?u64", + nlink: "!u64", uid: "?u64", gid: "?u64", rdev: "?u64", blksize: "?u64", - blocks: "?u64", + blocks: "!u64", isBlockDevice: "?bool", isCharDevice: "?bool", isFifo: "?bool", @@ -383,13 +397,13 @@ function parseFileInfo(response) { ctime: response.ctimeSet === true ? new Date(Number(response.ctime)) : null, dev: response.dev, mode: response.mode, - ino: unix ? response.ino : null, - nlink: unix ? response.nlink : null, + ino: response.inoSet ? Number(response.ino) : null, + nlink: response.nlinkSet ? response.nlink : null, uid: unix ? response.uid : null, gid: unix ? response.gid : null, rdev: unix ? response.rdev : null, blksize: unix ? response.blksize : null, - blocks: unix ? response.blocks : null, + blocks: response.blocksSet ? response.blocks : null, isBlockDevice: unix ? response.isBlockDevice : null, isCharDevice: unix ? response.isCharDevice : null, isFifo: unix ? response.isFifo : null, diff --git a/ext/fs/ops.rs b/ext/fs/ops.rs index 191025e0bc56ce..16e4c1681da748 100644 --- a/ext/fs/ops.rs +++ b/ext/fs/ops.rs @@ -2059,15 +2059,21 @@ create_struct_writer! { birthtime: u64, ctime_set: bool, ctime: u64, - // Following are only valid under Unix. + // Stats below are platform dependent. + // On Unix, they are always available. + // On Windows, the `*_set` fields are used + // to indicate if the corresponding field is resolved. dev: u64, + ino_set: bool, ino: u64, mode: u32, + nlink_set: bool, nlink: u64, uid: u32, gid: u32, rdev: u64, blksize: u64, + blocks_set: bool, blocks: u64, is_block_device: bool, is_char_device: bool, @@ -2094,14 +2100,17 @@ impl From for SerializableStat { ctime: stat.ctime.unwrap_or(0), dev: stat.dev, - ino: stat.ino, + ino_set: stat.ino.is_some(), + ino: stat.ino.unwrap_or(0), mode: stat.mode, - nlink: stat.nlink, + nlink_set: stat.nlink.is_some(), + nlink: stat.nlink.unwrap_or(0), uid: stat.uid, gid: stat.gid, rdev: stat.rdev, blksize: stat.blksize, - blocks: stat.blocks, + blocks_set: stat.blocks.is_some(), + blocks: stat.blocks.unwrap_or(0), is_block_device: stat.is_block_device, is_char_device: stat.is_char_device, is_fifo: stat.is_fifo, diff --git a/ext/io/fs.rs b/ext/io/fs.rs index 22366ca3389d55..bff0383bdbceeb 100644 --- a/ext/io/fs.rs +++ b/ext/io/fs.rs @@ -110,14 +110,14 @@ pub struct FsStat { pub ctime: Option, pub dev: u64, - pub ino: u64, + pub ino: Option, pub mode: u32, - pub nlink: u64, + pub nlink: Option, pub uid: u32, pub gid: u32, pub rdev: u64, pub blksize: u64, - pub blocks: u64, + pub blocks: Option, pub is_block_device: bool, pub is_char_device: bool, pub is_fifo: bool, @@ -126,6 +126,20 @@ pub struct FsStat { impl FsStat { pub fn from_std(metadata: std::fs::Metadata) -> Self { + macro_rules! unix_some_or_none { + ($member:ident) => {{ + #[cfg(unix)] + { + use std::os::unix::fs::MetadataExt; + Some(metadata.$member()) + } + #[cfg(not(unix))] + { + None + } + }}; + } + macro_rules! unix_or_zero { ($member:ident) => {{ #[cfg(unix)] @@ -189,14 +203,14 @@ impl FsStat { ctime: get_ctime(unix_or_zero!(ctime)), dev: unix_or_zero!(dev), - ino: unix_or_zero!(ino), + ino: unix_some_or_none!(ino), mode: unix_or_zero!(mode), - nlink: unix_or_zero!(nlink), + nlink: unix_some_or_none!(nlink), uid: unix_or_zero!(uid), gid: unix_or_zero!(gid), rdev: unix_or_zero!(rdev), blksize: unix_or_zero!(blksize), - blocks: unix_or_zero!(blocks), + blocks: unix_some_or_none!(blocks), is_block_device: unix_or_false!(is_block_device), is_char_device: unix_or_false!(is_char_device), is_fifo: unix_or_false!(is_fifo), diff --git a/ext/io/lib.rs b/ext/io/lib.rs index d2cb8056d4db56..f17bb03c8f0d3d 100644 --- a/ext/io/lib.rs +++ b/ext/io/lib.rs @@ -1305,6 +1305,12 @@ pub fn stat_extra(file: &std::fs::File, fsstat: &mut FsStat) -> FsResult<()> { | ((libc::S_IREAD | libc::S_IWRITE) >> 6)) as u32; } + + /* The on-disk allocation size in 512-byte units. */ + fsstat.blocks = + Some(file_info.StandardInformation.AllocationSize as u64 >> 9); + fsstat.ino = Some(file_info.InternalInformation.IndexNumber as u64); + fsstat.nlink = Some(file_info.StandardInformation.NumberOfLinks as u64); } Ok(()) diff --git a/ext/node/polyfills/_fs/_fs_stat.ts b/ext/node/polyfills/_fs/_fs_stat.ts index 290e17da1c00e9..e0b574eedbb1af 100644 --- a/ext/node/polyfills/_fs/_fs_stat.ts +++ b/ext/node/polyfills/_fs/_fs_stat.ts @@ -1,375 +1,186 @@ // Copyright 2018-2025 the Deno authors. MIT license. -// TODO(petamoriken): enable prefer-primordials for node polyfills -// deno-lint-ignore-file prefer-primordials - import { denoErrorToNodeError } from "ext:deno_node/internal/errors.ts"; import { promisify } from "ext:deno_node/internal/util.mjs"; import { primordials } from "ext:core/mod.js"; -import { getValidatedPath } from "ext:deno_node/internal/fs/utils.mjs"; +import { + BigIntStats, + getValidatedPathToString, + Stats, +} from "ext:deno_node/internal/fs/utils.mjs"; import { makeCallback } from "ext:deno_node/_fs/_fs_common.ts"; +import { isWindows } from "ext:deno_node/_util/os.ts"; +import { Buffer } from "node:buffer"; +import console from "node:console"; + +export { BigIntStats, Stats }; -const { ObjectCreate, ObjectAssign } = primordials; +const { + BigInt, + Date, + DatePrototypeGetTime, + ErrorPrototype, + ObjectDefineProperties, + ObjectPrototypeIsPrototypeOf, + PromisePrototypeThen, +} = primordials; export type statOptions = { bigint: boolean; throwIfNoEntry?: boolean; }; -interface IStats { - /** ID of the device containing the file. - * - * _Linux/Mac OS only._ */ - dev: number | null; - /** Inode number. - * - * _Linux/Mac OS only._ */ - ino: number | null; - /** **UNSTABLE**: Match behavior with Go on Windows for `mode`. - * - * The underlying raw `st_mode` bits that contain the standard Unix - * permissions for this file/directory. */ - mode: number | null; - /** Number of hard links pointing to this file. - * - * _Linux/Mac OS only._ */ - nlink: number | null; - /** User ID of the owner of this file. - * - * _Linux/Mac OS only._ */ - uid: number | null; - /** Group ID of the owner of this file. - * - * _Linux/Mac OS only._ */ - gid: number | null; - /** Device ID of this file. - * - * _Linux/Mac OS only._ */ - rdev: number | null; - /** The size of the file, in bytes. */ - size: number; - /** Blocksize for filesystem I/O. - * - * _Linux/Mac OS only._ */ - blksize: number | null; - /** Number of blocks allocated to the file, in 512-byte units. - * - * _Linux/Mac OS only._ */ - blocks: number | null; - /** The last modification time of the file. This corresponds to the `mtime` - * field from `stat` on Linux/Mac OS and `ftLastWriteTime` on Windows. This - * may not be available on all platforms. */ - mtime: Date | null; - /** The last access time of the file. This corresponds to the `atime` - * field from `stat` on Unix and `ftLastAccessTime` on Windows. This may not - * be available on all platforms. */ - atime: Date | null; - /** The creation time of the file. This corresponds to the `birthtime` - * field from `stat` on Mac/BSD and `ftCreationTime` on Windows. This may - * not be available on all platforms. */ - birthtime: Date | null; - /** change time */ - ctime: Date | null; - /** atime in milliseconds */ - atimeMs: number | null; - /** atime in milliseconds */ - mtimeMs: number | null; - /** atime in milliseconds */ - ctimeMs: number | null; - /** atime in milliseconds */ - birthtimeMs: number | null; - isBlockDevice: () => boolean; - isCharacterDevice: () => boolean; - isDirectory: () => boolean; - isFIFO: () => boolean; - isFile: () => boolean; - isSocket: () => boolean; - isSymbolicLink: () => boolean; -} - -class StatsBase { - constructor( - dev, - mode, - nlink, - uid, - gid, - rdev, - blksize, - ino, - size, - blocks, - ) { - this.dev = dev; - this.mode = mode; - this.nlink = nlink; - this.uid = uid; - this.gid = gid; - this.rdev = rdev; - this.blksize = blksize; - this.ino = ino; - this.size = size; - this.blocks = blocks; - } - - isFile() { - return false; - } - isDirectory() { - return false; - } - isSymbolicLink() { - return false; - } - isBlockDevice() { - return false; - } - isFIFO() { - return false; - } - isCharacterDevice() { - return false; - } - isSocket() { - return false; - } -} +export function convertFileInfoToStats(origin: Deno.FileInfo): Stats { + const atime = origin.atime ?? new Date(0); + const birthtime = origin.birthtime ?? new Date(0); + const ctime = origin.ctime ?? new Date(0); + const mtime = origin.mtime ?? new Date(0); -// The Date constructor performs Math.floor() to the timestamp. -// https://www.ecma-international.org/ecma-262/#sec-timeclip -// Since there may be a precision loss when the timestamp is -// converted to a floating point number, we manually round -// the timestamp here before passing it to Date(). -function dateFromMs(ms) { - return new Date(Number(ms) + 0.5); -} + const stats = new Stats( + origin.dev, + origin.mode || 0, + origin.nlink || 0, + isWindows ? 0 : origin.uid, + isWindows ? 0 : origin.gid, + isWindows ? 0 : origin.rdev, + // https://github.com/nodejs/node/blob/591ba692bfe30408e6a67397e7d18bfa1b9c3561/deps/uv/src/win/fs.c#L1929-L1930 + isWindows ? 4096 : origin.blksize, + origin.ino || 0, + origin.size, + origin.blocks || 0, + DatePrototypeGetTime(atime), + DatePrototypeGetTime(mtime), + DatePrototypeGetTime(ctime), + DatePrototypeGetTime(birthtime), + ); -export class Stats extends StatsBase { - constructor( - dev, - mode, - nlink, - uid, - gid, - rdev, - blksize, - ino, - size, - blocks, - atimeMs, - mtimeMs, - ctimeMs, - birthtimeMs, - ) { - super( - dev, - mode, - nlink, - uid, - gid, - rdev, - blksize, - ino, - size, - blocks, - ); - this.atimeMs = atimeMs; - this.mtimeMs = mtimeMs; - this.ctimeMs = ctimeMs; - this.birthtimeMs = birthtimeMs; - this.atime = dateFromMs(atimeMs); - this.mtime = dateFromMs(mtimeMs); - this.ctime = dateFromMs(ctimeMs); - this.birthtime = dateFromMs(birthtimeMs); - } + return defineExtraProps(stats, origin); } -export interface IBigIntStats { - /** ID of the device containing the file. - * - * _Linux/Mac OS only._ */ - dev: bigint | null; - /** Inode number. - * - * _Linux/Mac OS only._ */ - ino: bigint | null; - /** **UNSTABLE**: Match behavior with Go on Windows for `mode`. - * - * The underlying raw `st_mode` bits that contain the standard Unix - * permissions for this file/directory. */ - mode: bigint | null; - /** Number of hard links pointing to this file. - * - * _Linux/Mac OS only._ */ - nlink: bigint | null; - /** User ID of the owner of this file. - * - * _Linux/Mac OS only._ */ - uid: bigint | null; - /** Group ID of the owner of this file. - * - * _Linux/Mac OS only._ */ - gid: bigint | null; - /** Device ID of this file. - * - * _Linux/Mac OS only._ */ - rdev: bigint | null; - /** The size of the file, in bytes. */ - size: bigint; - /** Blocksize for filesystem I/O. - * - * _Linux/Mac OS only._ */ - blksize: bigint | null; - /** Number of blocks allocated to the file, in 512-byte units. - * - * _Linux/Mac OS only._ */ - blocks: bigint | null; - /** The last modification time of the file. This corresponds to the `mtime` - * field from `stat` on Linux/Mac OS and `ftLastWriteTime` on Windows. This - * may not be available on all platforms. */ - mtime: Date | null; - /** The last access time of the file. This corresponds to the `atime` - * field from `stat` on Unix and `ftLastAccessTime` on Windows. This may not - * be available on all platforms. */ - atime: Date | null; - /** The creation time of the file. This corresponds to the `birthtime` - * field from `stat` on Mac/BSD and `ftCreationTime` on Windows. This may - * not be available on all platforms. */ - birthtime: Date | null; - /** change time */ - ctime: Date | null; - /** atime in milliseconds */ - atimeMs: bigint | null; - /** atime in milliseconds */ - mtimeMs: bigint | null; - /** atime in milliseconds */ - ctimeMs: bigint | null; - /** atime in nanoseconds */ - birthtimeMs: bigint | null; - /** atime in nanoseconds */ - atimeNs: bigint | null; - /** atime in nanoseconds */ - mtimeNs: bigint | null; - /** atime in nanoseconds */ - ctimeNs: bigint | null; - /** atime in nanoseconds */ - birthtimeNs: bigint | null; - isBlockDevice: () => boolean; - isCharacterDevice: () => boolean; - isDirectory: () => boolean; - isFIFO: () => boolean; - isFile: () => boolean; - isSocket: () => boolean; - isSymbolicLink: () => boolean; +function toBigInt(number?: number | null): bigint { + if (number === null || number === undefined) return 0n; + return BigInt(number); } -export class BigIntStats {} - -export function convertFileInfoToStats(origin: Deno.FileInfo): Stats { - const stats = ObjectCreate(Stats.prototype); - ObjectAssign(stats, { - dev: origin.dev, - ino: origin.ino, - mode: origin.mode, - nlink: origin.nlink, - uid: origin.uid, - gid: origin.gid, - rdev: origin.rdev, - size: origin.size, - blksize: origin.blksize, - blocks: origin.blocks, - mtime: origin.mtime, - atime: origin.atime, - birthtime: origin.birthtime, - mtimeMs: origin.mtime?.getTime() || null, - atimeMs: origin.atime?.getTime() || null, - birthtimeMs: origin.birthtime?.getTime() || null, - isFile: () => origin.isFile, - isDirectory: () => origin.isDirectory, - isSymbolicLink: () => origin.isSymlink, - // not sure about those - isBlockDevice: () => false, - isFIFO: () => false, - isCharacterDevice: () => false, - isSocket: () => false, - ctime: origin.ctime, - ctimeMs: origin.ctime?.getTime() || null, - }); +export function convertFileInfoToBigIntStats( + origin: Deno.FileInfo, +): BigIntStats { + const atime = origin.atime ?? new Date(0); + const birthtime = origin.birthtime ?? new Date(0); + const ctime = origin.ctime ?? new Date(0); + const mtime = origin.mtime ?? new Date(0); - return stats; -} + const bigIntStats = new BigIntStats( + toBigInt(origin.dev), + toBigInt(origin.mode), + toBigInt(origin.nlink), + toBigInt(origin.uid), + toBigInt(origin.gid), + toBigInt(origin.rdev), + // https://github.com/nodejs/node/blob/591ba692bfe30408e6a67397e7d18bfa1b9c3561/deps/uv/src/win/fs.c#L1929-L1930 + isWindows ? 4096n : toBigInt(origin.blksize), + toBigInt(origin.ino), + toBigInt(origin.size), + toBigInt(origin.blocks), + BigInt(DatePrototypeGetTime(atime)) * 1000000n, + BigInt(DatePrototypeGetTime(mtime)) * 1000000n, + BigInt(DatePrototypeGetTime(ctime)) * 1000000n, + BigInt(DatePrototypeGetTime(birthtime)) * 1000000n, + ); -function toBigInt(number?: number | null) { - if (number === null || number === undefined) return null; - return BigInt(number); + return defineExtraProps(bigIntStats, origin); } -export function convertFileInfoToBigIntStats( +const defineExtraProps = ( + stats: T, origin: Deno.FileInfo, -): BigIntStats { - const stats = ObjectCreate(BigIntStats.prototype); - ObjectAssign(stats, { - dev: toBigInt(origin.dev), - ino: toBigInt(origin.ino), - mode: toBigInt(origin.mode), - nlink: toBigInt(origin.nlink), - uid: toBigInt(origin.uid), - gid: toBigInt(origin.gid), - rdev: toBigInt(origin.rdev), - size: toBigInt(origin.size) || 0n, - blksize: toBigInt(origin.blksize), - blocks: toBigInt(origin.blocks), - mtime: origin.mtime, - atime: origin.atime, - birthtime: origin.birthtime, - mtimeMs: origin.mtime ? BigInt(origin.mtime.getTime()) : null, - atimeMs: origin.atime ? BigInt(origin.atime.getTime()) : null, - birthtimeMs: origin.birthtime ? BigInt(origin.birthtime.getTime()) : null, - mtimeNs: origin.mtime ? BigInt(origin.mtime.getTime()) * 1000000n : null, - atimeNs: origin.atime ? BigInt(origin.atime.getTime()) * 1000000n : null, - birthtimeNs: origin.birthtime - ? BigInt(origin.birthtime.getTime()) * 1000000n - : null, - isFile: () => origin.isFile, - isDirectory: () => origin.isDirectory, - isSymbolicLink: () => origin.isSymlink, - // not sure about those - isBlockDevice: () => false, - isFIFO: () => false, - isCharacterDevice: () => false, - isSocket: () => false, - ctime: origin.ctime, - ctimeMs: origin.ctime ? BigInt(origin.ctime.getTime()) : null, - ctimeNs: origin.ctime ? BigInt(origin.ctime.getTime()) * 1000000n : null, +): T => { + ObjectDefineProperties(stats, { + isDirectory: { + __proto__: null, + value: () => origin.isDirectory, + writable: true, + configurable: true, + }, + isFile: { + __proto__: null, + value: () => origin.isFile, + writable: true, + configurable: true, + }, + isSymbolicLink: { + __proto__: null, + value: () => origin.isSymlink, + writable: true, + configurable: true, + }, + isBlockDevice: { + __proto__: null, + value: () => isWindows ? false : origin.isBlockDevice, + writable: true, + configurable: true, + }, + isFIFO: { + __proto__: null, + value: () => isWindows ? false : origin.isFifo, + writable: true, + configurable: true, + }, + isCharacterDevice: { + __proto__: null, + value: () => isWindows ? false : origin.isCharDevice, + writable: true, + configurable: true, + }, + isSocket: { + __proto__: null, + value: () => isWindows ? false : origin.isSocket, + writable: true, + configurable: true, + }, }); return stats; -} +}; // shortcut for Convert File Info to Stats or BigIntStats -export function CFISBIS(fileInfo: Deno.FileInfo, bigInt: boolean) { +export function CFISBIS(fileInfo: Deno.FileInfo, bigInt: false): Stats; +export function CFISBIS(fileInfo: Deno.FileInfo, bigInt: true): BigIntStats; +export function CFISBIS( + fileInfo: Deno.FileInfo, + bigInt: boolean, +): Stats | BigIntStats { + console.log(fileInfo, bigInt); if (bigInt) return convertFileInfoToBigIntStats(fileInfo); return convertFileInfoToStats(fileInfo); } -export type statCallbackBigInt = (err: Error | null, stat: BigIntStats) => void; +export type statCallbackBigInt = ( + err: Error | null, + stat?: BigIntStats, +) => void; -export type statCallback = (err: Error | null, stat: Stats) => void; +export type statCallback = (err: Error | null, stat?: Stats) => void; -const defaultOptions = { bigint: false }; +const defaultOptions = { __proto__: null, bigint: false }; +const defaultSyncOptions = { + __proto__: null, + bigint: false, + throwIfNoEntry: true, +}; -export function stat(path: string | URL, callback: statCallback): void; +export function stat(path: string | Buffer | URL, callback: statCallback): void; export function stat( - path: string | URL, + path: string | Buffer | URL, options: { bigint: false }, callback: statCallback, ): void; export function stat( - path: string | URL, + path: string | Buffer | URL, options: { bigint: true }, callback: statCallbackBigInt, ): void; export function stat( - path: string | URL, + path: string | Buffer | URL, options: statCallback | statCallbackBigInt | statOptions = defaultOptions, callback?: statCallback | statCallbackBigInt, ) { @@ -378,37 +189,52 @@ export function stat( options = defaultOptions; } callback = makeCallback(callback); - path = getValidatedPath(path).toString(); + path = getValidatedPathToString(path); - Deno.stat(path).then( + PromisePrototypeThen( + Deno.stat(path), (stat) => callback(null, CFISBIS(stat, options.bigint)), (err) => callback( - denoErrorToNodeError(err, { syscall: "stat", path: getPathname(path) }), + denoErrorToNodeError(err, { syscall: "stat", path }), ), ); } export const statPromise = promisify(stat) as ( - & ((path: string | URL) => Promise) - & ((path: string | URL, options: { bigint: false }) => Promise) - & ((path: string | URL, options: { bigint: true }) => Promise) + & ((path: string | Buffer | URL) => Promise) + & (( + path: string | Buffer | URL, + options: { bigint: false }, + ) => Promise) + & (( + path: string | Buffer | URL, + options: { bigint: true }, + ) => Promise) ); -export function statSync(path: string | URL): Stats; +export function statSync(path: string | Buffer | URL): Stats; export function statSync( - path: string | URL, - options: { bigint: false; throwIfNoEntry?: boolean }, + path: string | Buffer | URL, + options: { bigint: false; throwIfNoEntry: true }, ): Stats; export function statSync( - path: string | URL, - options: { bigint: true; throwIfNoEntry?: boolean }, + path: string | Buffer | URL, + options: { bigint: false; throwIfNoEntry: false }, +): Stats | undefined; +export function statSync( + path: string | Buffer | URL, + options: { bigint: true; throwIfNoEntry: true }, ): BigIntStats; export function statSync( - path: string | URL, - options: statOptions = { ...defaultOptions, throwIfNoEntry: true }, + path: string | Buffer | URL, + options: { bigint: true; throwIfNoEntry: false }, +): BigIntStats | undefined; +export function statSync( + path: string | Buffer | URL, + options: statOptions = defaultSyncOptions, ): Stats | BigIntStats | undefined { - path = getValidatedPath(path).toString(); + path = getValidatedPathToString(path); try { const origin = Deno.statSync(path); @@ -416,21 +242,17 @@ export function statSync( } catch (err) { if ( options?.throwIfNoEntry === false && - err instanceof Deno.errors.NotFound + ObjectPrototypeIsPrototypeOf(Deno.errors.NotFound.prototype, err) ) { return; } - if (err instanceof Error) { - throw denoErrorToNodeError(err, { + if (ObjectPrototypeIsPrototypeOf(ErrorPrototype, err)) { + throw denoErrorToNodeError(err as Error, { syscall: "stat", - path: getPathname(path), + path, }); } else { throw err; } } } - -function getPathname(path: string | URL) { - return typeof path === "string" ? path : path.pathname; -} diff --git a/ext/node/polyfills/internal/fs/utils.mjs b/ext/node/polyfills/internal/fs/utils.mjs index 10439c419ad350..21edd0b97eb46e 100644 --- a/ext/node/polyfills/internal/fs/utils.mjs +++ b/ext/node/polyfills/internal/fs/utils.mjs @@ -19,6 +19,8 @@ const { Number, NumberIsFinite, NumberIsInteger, + ObjectDefineProperties, + ObjectDefineProperty, ObjectIs, ObjectPrototypeIsPrototypeOf, ObjectSetPrototypeOf, @@ -508,6 +510,70 @@ function dateFromMs(ms) { return new Date(Number(ms) + 0.5); } +const lazyDateFields = { + __proto__: null, + atime: { + __proto__: null, + enumerable: true, + configurable: true, + get() { + return this.atime = dateFromMs(this.atimeMs); + }, + set(value) { + ObjectDefineProperty(this, "atime", { + __proto__: null, + value, + writable: true, + }); + }, + }, + mtime: { + __proto__: null, + enumerable: true, + configurable: true, + get() { + return this.mtime = dateFromMs(this.mtimeMs); + }, + set(value) { + ObjectDefineProperty(this, "mtime", { + __proto__: null, + value, + writable: true, + }); + }, + }, + ctime: { + __proto__: null, + enumerable: true, + configurable: true, + get() { + return this.ctime = dateFromMs(this.ctimeMs); + }, + set(value) { + ObjectDefineProperty(this, "ctime", { + __proto__: null, + value, + writable: true, + }); + }, + }, + birthtime: { + __proto__: null, + enumerable: true, + configurable: true, + get() { + return this.birthtime = dateFromMs(this.birthtimeMs); + }, + set(value) { + ObjectDefineProperty(this, "birthtime", { + __proto__: null, + value, + writable: true, + }); + }, + }, +}; + export function BigIntStats( dev, mode, @@ -548,11 +614,11 @@ export function BigIntStats( this.atime = dateFromMs(this.atimeMs); this.mtime = dateFromMs(this.mtimeMs); this.ctime = dateFromMs(this.ctimeMs); - this.birthtime = dateFromMs(this.birthtimeMs); } ObjectSetPrototypeOf(BigIntStats.prototype, StatsBase.prototype); ObjectSetPrototypeOf(BigIntStats, StatsBase); +ObjectDefineProperties(BigIntStats.prototype, lazyDateFields); BigIntStats.prototype._checkModeProperty = function (property) { if ( @@ -601,11 +667,11 @@ export function Stats( this.atime = dateFromMs(atimeMs); this.mtime = dateFromMs(mtimeMs); this.ctime = dateFromMs(ctimeMs); - this.birthtime = dateFromMs(birthtimeMs); } ObjectSetPrototypeOf(Stats.prototype, StatsBase.prototype); ObjectSetPrototypeOf(Stats, StatsBase); +ObjectDefineProperties(Stats.prototype, lazyDateFields); // HACK: Workaround for https://github.com/standard-things/esm/issues/821. // TODO(ronag): Remove this as soon as `esm` publishes a fixed version. From 7d9547be9c142f44cb3010df0d4e9aacf675cd66 Mon Sep 17 00:00:00 2001 From: Daniel Rahmanto Date: Sun, 28 Sep 2025 21:52:12 +0700 Subject: [PATCH 2/3] test --- tests/unit/stat_test.ts | 6 +- tests/unit_node/_fs/_fs_fstat_test.ts | 2 +- tests/unit_node/_fs/_fs_lstat_test.ts | 7 +- tests/unit_node/_fs/_fs_stat_test.ts | 79 +------ tests/unit_node/_test_utils.ts | 315 +++++++++++++++++++++++++- 5 files changed, 328 insertions(+), 81 deletions(-) diff --git a/tests/unit/stat_test.ts b/tests/unit/stat_test.ts index 5e09be4400cc36..14c739a0e66a7d 100644 --- a/tests/unit/stat_test.ts +++ b/tests/unit/stat_test.ts @@ -285,13 +285,13 @@ Deno.test( Deno.writeFileSync(filename, data, { mode: 0o666 }); const s = Deno.statSync(filename); assert(s.dev !== 0); - assert(s.ino === null); - assert(s.nlink === null); + assert(s.ino !== null); + assert(s.nlink !== null); assert(s.uid === null); assert(s.gid === null); assert(s.rdev === null); assert(s.blksize === null); - assert(s.blocks === null); + assert(s.blocks !== null); assert(s.isBlockDevice === null); assert(s.isCharDevice === null); assert(s.isFifo === null); diff --git a/tests/unit_node/_fs/_fs_fstat_test.ts b/tests/unit_node/_fs/_fs_fstat_test.ts index 79e5106525f923..1289a5e34025ad 100644 --- a/tests/unit_node/_fs/_fs_fstat_test.ts +++ b/tests/unit_node/_fs/_fs_fstat_test.ts @@ -2,7 +2,7 @@ import { fstat, fstatSync } from "node:fs"; import { fail } from "@std/assert"; -import { assertStats, assertStatsBigInt } from "./_fs_stat_test.ts"; +import { assertStats, assertStatsBigInt } from "../_test_utils.ts"; import type { BigIntStats, Stats } from "node:fs"; Deno.test({ diff --git a/tests/unit_node/_fs/_fs_lstat_test.ts b/tests/unit_node/_fs/_fs_lstat_test.ts index 196d5f23b73a10..1e01fcbe697a3d 100644 --- a/tests/unit_node/_fs/_fs_lstat_test.ts +++ b/tests/unit_node/_fs/_fs_lstat_test.ts @@ -1,8 +1,11 @@ // Copyright 2018-2025 the Deno authors. MIT license. import { lstat, lstatSync } from "node:fs"; import { fail } from "@std/assert"; -import { assertCallbackErrorUncaught } from "../_test_utils.ts"; -import { assertStats, assertStatsBigInt } from "./_fs_stat_test.ts"; +import { + assertCallbackErrorUncaught, + assertStats, + assertStatsBigInt, +} from "../_test_utils.ts"; import type { BigIntStats, Stats } from "node:fs"; Deno.test({ diff --git a/tests/unit_node/_fs/_fs_stat_test.ts b/tests/unit_node/_fs/_fs_stat_test.ts index d10521d0cde12e..ee68e30e4fc124 100644 --- a/tests/unit_node/_fs/_fs_stat_test.ts +++ b/tests/unit_node/_fs/_fs_stat_test.ts @@ -1,81 +1,12 @@ // Copyright 2018-2025 the Deno authors. MIT license. -import { assertCallbackErrorUncaught } from "../_test_utils.ts"; +import { + assertCallbackErrorUncaught, + assertStats, + assertStatsBigInt, +} from "../_test_utils.ts"; import { BigIntStats, stat, Stats, statSync } from "node:fs"; import { assert, assertEquals, fail } from "@std/assert"; -export function assertStats(actual: Stats, expected: Deno.FileInfo) { - assertEquals(actual.dev, expected.dev); - assertEquals(actual.gid, expected.gid); - assertEquals(actual.size, expected.size); - assertEquals(actual.blksize, expected.blksize); - assertEquals(actual.blocks, expected.blocks); - assertEquals(actual.ino, expected.ino); - assertEquals(actual.gid, expected.gid); - assertEquals(actual.mode, expected.mode); - assertEquals(actual.nlink, expected.nlink); - assertEquals(actual.rdev, expected.rdev); - assertEquals(actual.uid, expected.uid); - assertEquals(actual.atime?.getTime(), expected.atime?.getTime()); - assertEquals(actual.mtime?.getTime(), expected.mtime?.getTime()); - assertEquals(actual.birthtime?.getTime(), expected.birthtime?.getTime()); - assertEquals(actual.ctime?.getTime(), expected.ctime?.getTime()); - assertEquals(actual.atimeMs ?? undefined, expected.atime?.getTime()); - assertEquals(actual.mtimeMs ?? undefined, expected.mtime?.getTime()); - assertEquals(actual.birthtimeMs ?? undefined, expected.birthtime?.getTime()); - assertEquals(actual.ctimeMs ?? undefined, expected.ctime?.getTime()); - assertEquals(actual.isFile(), expected.isFile); - assertEquals(actual.isDirectory(), expected.isDirectory); - assertEquals(actual.isSymbolicLink(), expected.isSymlink); -} - -function toBigInt(num?: number | null) { - if (num === undefined || num === null) return null; - return BigInt(num); -} - -export function assertStatsBigInt( - actual: BigIntStats, - expected: Deno.FileInfo, -) { - assertEquals(actual.dev, toBigInt(expected.dev)); - assertEquals(actual.gid, toBigInt(expected.gid)); - assertEquals(actual.size, toBigInt(expected.size)); - assertEquals(actual.blksize, toBigInt(expected.blksize)); - assertEquals(actual.blocks, toBigInt(expected.blocks)); - assertEquals(actual.ino, toBigInt(expected.ino)); - assertEquals(actual.gid, toBigInt(expected.gid)); - assertEquals(actual.mode, toBigInt(expected.mode)); - assertEquals(actual.nlink, toBigInt(expected.nlink)); - assertEquals(actual.rdev, toBigInt(expected.rdev)); - assertEquals(actual.uid, toBigInt(expected.uid)); - assertEquals(actual.atime?.getTime(), expected.atime?.getTime()); - assertEquals(actual.mtime?.getTime(), expected.mtime?.getTime()); - assertEquals(actual.birthtime?.getTime(), expected.birthtime?.getTime()); - assertEquals(actual.ctime?.getTime(), expected.ctime?.getTime()); - assertEquals( - actual.atimeMs === null ? undefined : Number(actual.atimeMs), - expected.atime?.getTime(), - ); - assertEquals( - actual.mtimeMs === null ? undefined : Number(actual.mtimeMs), - expected.mtime?.getTime(), - ); - assertEquals( - actual.birthtimeMs === null ? undefined : Number(actual.birthtimeMs), - expected.birthtime?.getTime(), - ); - assertEquals( - actual.ctimeMs === null ? undefined : Number(actual.ctimeMs), - expected.ctime?.getTime(), - ); - assertEquals(actual.atimeNs === null, actual.atime === null); - assertEquals(actual.mtimeNs === null, actual.mtime === null); - assertEquals(actual.birthtimeNs === null, actual.birthtime === null); - assertEquals(actual.isFile(), expected.isFile); - assertEquals(actual.isDirectory(), expected.isDirectory); - assertEquals(actual.isSymbolicLink(), expected.isSymlink); -} - Deno.test({ name: "ASYNC: get a file Stats", async fn() { diff --git a/tests/unit_node/_test_utils.ts b/tests/unit_node/_test_utils.ts index a78444fd4ad19e..95cfe3d1ef5a75 100644 --- a/tests/unit_node/_test_utils.ts +++ b/tests/unit_node/_test_utils.ts @@ -1,6 +1,13 @@ // Copyright 2018-2025 the Deno authors. MIT license. -import { assert, assertStringIncludes } from "@std/assert"; +import { BigIntStats, Stats } from "node:fs"; +import { + assert, + assertEquals, + assertNotStrictEquals, + assertStrictEquals, + assertStringIncludes, +} from "@std/assert"; /** Asserts that an error thrown in a callback will not be wrongly caught. */ export async function assertCallbackErrorUncaught( @@ -37,3 +44,309 @@ export async function assertCallbackErrorUncaught( assert(!success); assertStringIncludes(error, "Error: success"); } + +const numberFields = [ + "dev", + "mode", + "nlink", + "uid", + "gid", + "rdev", + "blksize", + "ino", + "size", + "blocks", + "atimeMs", + "mtimeMs", + "ctimeMs", + "birthtimeMs", +]; + +const bigintFields = [ + ...numberFields, + "atimeNs", + "mtimeNs", + "ctimeNs", + "birthtimeNs", +]; + +const dateFields = [ + "atime", + "mtime", + "ctime", + "birthtime", +]; + +export function assertStats(actual: Stats, expected: Deno.FileInfo) { + [...numberFields, ...dateFields].forEach(function (k) { + assert(k in actual, `${k} should be in Stats`); + assertNotStrictEquals( + actual[k as keyof Stats], + undefined, + `${k} should not be undefined`, + ); + assertNotStrictEquals( + actual[k as keyof Stats], + null, + `${k} should not be null`, + ); + }); + + numberFields.forEach((k) => { + assertStrictEquals( + typeof actual[k as keyof Stats], + "number", + `${k} should be a number`, + ); + }); + + dateFields.forEach((k) => { + assert(actual[k as keyof Stats] instanceof Date, `${k} should be a Date`); + }); + + // Some properties from Deno.FileInfo may be null, + // while node:fs Stats always has number / Date properties. + // So we only check properties that are not null in Deno.FileInfo. + assertEquals(actual.dev, expected.dev); + if (expected.gid) assertEquals(actual.gid, expected.gid, "Stats.gid"); + assertEquals(actual.size, expected.size, "Stats.size"); + if (expected.blksize) { + assertEquals(actual.blksize, expected.blksize, "Stats.blksize"); + } + if (expected.blocks) { + assertEquals(actual.blocks, expected.blocks, "Stats.blocks"); + } + if (expected.ino) assertEquals(actual.ino, expected.ino, "Stats.ino"); + if (expected.mode) assertEquals(actual.mode, expected.mode, "Stats.mode"); + if (expected.nlink) assertEquals(actual.nlink, expected.nlink, "Stats.nlink"); + if (expected.rdev) assertEquals(actual.rdev, expected.rdev, "Stats.rdev"); + if (expected.uid) assertEquals(actual.uid, expected.uid, "Stats.uid"); + if (expected.atime?.getTime()) { + assertEquals( + actual.atime.getTime(), + expected.atime.getTime(), + "Stats.atime", + ); + assertEquals(actual.atimeMs, expected.atime.getTime(), "Stats.atimeMs"); + } + if (expected.mtime?.getTime()) { + assertEquals( + actual.mtime.getTime(), + expected.mtime.getTime(), + "Stats.mtime", + ); + assertEquals(actual.mtimeMs, expected.mtime.getTime(), "Stats.mtimeMs"); + } + if (expected.birthtime?.getTime()) { + assertEquals( + actual.birthtime.getTime(), + expected.birthtime.getTime(), + "Stats.birthtime", + ); + assertEquals( + actual.birthtimeMs, + expected.birthtime.getTime(), + "Stats.birthtimeMs", + ); + } + if (expected.ctime?.getTime()) { + assertEquals( + actual.ctime.getTime(), + expected.ctime.getTime(), + "Stats.ctime", + ); + assertEquals(actual.ctimeMs, expected.ctime.getTime(), "Stats.ctimeMs"); + } + assertEquals(actual.isFile(), expected.isFile, "Stats.isFile"); + assertEquals(actual.isDirectory(), expected.isDirectory, "Stats.isDirectory"); + assertEquals( + actual.isSymbolicLink(), + expected.isSymlink, + "Stats.isSymbolicLink", + ); + assertEquals( + actual.isBlockDevice(), + Deno.build.os === "windows" ? false : expected.isBlockDevice, + "Stats.isBlockDevice", + ); + assertEquals( + actual.isFIFO(), + Deno.build.os === "windows" ? false : expected.isFifo, + "Stats.isFIFO", + ); + assertEquals( + actual.isCharacterDevice(), + Deno.build.os === "windows" ? false : expected.isCharDevice, + "Stats.isCharacterDevice", + ); + assertEquals( + actual.isSocket(), + Deno.build.os === "windows" ? false : expected.isSocket, + "Stats.isSocket", + ); +} + +function toBigInt(num?: number | null) { + if (num === undefined || num === null) return null; + return BigInt(num); +} + +export function assertStatsBigInt( + actual: BigIntStats, + expected: Deno.FileInfo, +) { + [...bigintFields, ...dateFields].forEach(function (k) { + assert(k in actual, `${k} should be in BigIntStats`); + assertNotStrictEquals( + actual[k as keyof BigIntStats], + undefined, + `${k} should not be undefined`, + ); + assertNotStrictEquals( + actual[k as keyof BigIntStats], + null, + `${k} should not be null`, + ); + }); + + bigintFields.forEach((k) => { + assertStrictEquals( + typeof actual[k as keyof BigIntStats], + "bigint", + `${k} should be a bigint`, + ); + }); + + dateFields.forEach((k) => { + assert( + actual[k as keyof BigIntStats] instanceof Date, + `${k} should be a Date`, + ); + }); + + // Some properties from Deno.FileInfo may be null, + // while node:fs BigIntStats always has bigint / Date properties. + // So we only check properties that are not null in Deno.FileInfo. + assertEquals(actual.dev, toBigInt(expected.dev), "BigIntStats.dev"); + if (expected.gid) { + assertEquals(actual.gid, toBigInt(expected.gid), "BigIntStats.gid"); + } + assertEquals(actual.size, toBigInt(expected.size), "BigIntStats.size"); + if (expected.blksize) { + assertEquals( + actual.blksize, + toBigInt(expected.blksize), + "BigIntStats.blksize", + ); + } + if (expected.blocks) { + assertEquals( + actual.blocks, + toBigInt(expected.blocks), + "BigIntStats.blocks", + ); + } + if (expected.ino) { + assertEquals(actual.ino, toBigInt(expected.ino), "BigIntStats.ino"); + } + if (expected.mode) { + assertEquals(actual.mode, toBigInt(expected.mode), "BigIntStats.mode"); + } + if (expected.nlink) { + assertEquals(actual.nlink, toBigInt(expected.nlink), "BigIntStats.nlink"); + } + if (expected.rdev) { + assertEquals(actual.rdev, toBigInt(expected.rdev), "BigIntStats.rdev"); + } + if (expected.uid) { + assertEquals(actual.uid, toBigInt(expected.uid), "BigIntStats.uid"); + } + if (expected.atime?.getTime()) { + assertEquals( + actual.atime.getTime(), + expected.atime.getTime(), + "BigIntStats.atime", + ); + assertEquals( + actual.atimeMs, + toBigInt(expected.atime.getTime()), + "BigIntStats.atimeMs", + ); + assertEquals( + actual.atimeNs, + toBigInt(expected.atime.getTime()) as bigint * 1000000n, + "BigIntStats.atimeNs", + ); + } + if (expected.mtime?.getTime()) { + assertEquals( + actual.mtime.getTime(), + expected.mtime.getTime(), + "BigIntStats.mtime", + ); + assertEquals( + actual.mtimeMs, + toBigInt(expected.mtime.getTime()), + "BigIntStats.mtimeMs", + ); + assertEquals( + actual.mtimeNs, + toBigInt(expected.mtime.getTime()) as bigint * 1000000n, + "BigIntStats.mtimeNs", + ); + } + if (expected.birthtime?.getTime()) { + assertEquals( + actual.birthtime.getTime(), + expected.birthtime.getTime(), + "BigIntStats.birthtime", + ); + assertEquals( + actual.birthtimeMs, + toBigInt(expected.birthtime.getTime()), + "BigIntStats.birthtimeMs", + ); + assertEquals( + actual.birthtimeNs, + toBigInt(expected.birthtime.getTime()) as bigint * 1000000n, + "BigIntStats.birthtimeNs", + ); + } + if (expected.ctime?.getTime()) { + assertEquals( + actual.ctime.getTime(), + expected.ctime.getTime(), + "BigIntStats.ctime", + ); + assertEquals( + actual.ctimeMs, + toBigInt(expected.ctime.getTime()), + "BigIntStats.ctimeMs", + ); + assertEquals( + actual.ctimeNs, + toBigInt(expected.ctime.getTime()) as bigint * 1000000n, + "BigIntStats.ctimeNs", + ); + } + assertEquals( + actual.isBlockDevice(), + Deno.build.os === "windows" ? false : expected.isBlockDevice, + "BigIntStats.isBlockDevice", + ); + assertEquals( + actual.isFIFO(), + Deno.build.os === "windows" ? false : expected.isFifo, + "BigIntStats.isFIFO", + ); + assertEquals( + actual.isCharacterDevice(), + Deno.build.os === "windows" ? false : expected.isCharDevice, + "BigIntStats.isCharacterDevice", + ); + assertEquals( + actual.isSocket(), + Deno.build.os === "windows" ? false : expected.isSocket, + "BigIntStats.isSocket", + ); +} From 5ffd37e859666de85ca1461ac84f4fd1ddbf84a0 Mon Sep 17 00:00:00 2001 From: Daniel Rahmanto Date: Sun, 28 Sep 2025 22:43:51 +0700 Subject: [PATCH 3/3] fix: omit console log --- ext/node/polyfills/_fs/_fs_stat.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/ext/node/polyfills/_fs/_fs_stat.ts b/ext/node/polyfills/_fs/_fs_stat.ts index e0b574eedbb1af..664dc6b07bc5f2 100644 --- a/ext/node/polyfills/_fs/_fs_stat.ts +++ b/ext/node/polyfills/_fs/_fs_stat.ts @@ -11,7 +11,6 @@ import { import { makeCallback } from "ext:deno_node/_fs/_fs_common.ts"; import { isWindows } from "ext:deno_node/_util/os.ts"; import { Buffer } from "node:buffer"; -import console from "node:console"; export { BigIntStats, Stats }; @@ -149,7 +148,6 @@ export function CFISBIS( fileInfo: Deno.FileInfo, bigInt: boolean, ): Stats | BigIntStats { - console.log(fileInfo, bigInt); if (bigInt) return convertFileInfoToBigIntStats(fileInfo); return convertFileInfoToStats(fileInfo); }