diff options
author | Divy Srivastava <dj.srivastava23@gmail.com> | 2024-03-06 18:29:10 +0530 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-06 13:59:10 +0100 |
commit | 6ba0b7952d1ca867d0e166de4d36dcd6fe489e89 (patch) | |
tree | 9791b1dca4dbba002d61123d295ffca017785e7a | |
parent | 156950828e8c25f9de346c7cd737f1d0ebc8c1fb (diff) |
fix(node): stat/statSync returns instance of fs.Stats (#22294)
Fixes https://github.com/denoland/deno/issues/22291
---------
Signed-off-by: Divy Srivastava <dj.srivastava23@gmail.com>
-rw-r--r-- | ext/node/polyfills/_fs/_fs_stat.ts | 101 | ||||
-rw-r--r-- | ext/node/polyfills/_fs/_fs_watch.ts | 3 | ||||
-rw-r--r-- | ext/node/polyfills/fs.ts | 8 | ||||
-rw-r--r-- | tests/unit_node/fs_test.ts | 11 |
4 files changed, 111 insertions, 12 deletions
diff --git a/ext/node/polyfills/_fs/_fs_stat.ts b/ext/node/polyfills/_fs/_fs_stat.ts index 119faecee..de9b69ba3 100644 --- a/ext/node/polyfills/_fs/_fs_stat.ts +++ b/ext/node/polyfills/_fs/_fs_stat.ts @@ -5,13 +5,16 @@ 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"; + +const { ObjectCreate, ObjectAssign } = primordials; export type statOptions = { bigint: boolean; throwIfNoEntry?: boolean; }; -export type Stats = { +interface IStats { /** ID of the device containing the file. * * _Linux/Mac OS only._ */ @@ -80,9 +83,84 @@ export type Stats = { 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; + } +} + +// 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); +} -export type BigIntStats = { +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); + } +} + +export interface IBigIntStats { /** ID of the device containing the file. * * _Linux/Mac OS only._ */ @@ -159,10 +237,13 @@ export type BigIntStats = { isFile: () => boolean; isSocket: () => boolean; isSymbolicLink: () => boolean; -}; +} + +export class BigIntStats {} export function convertFileInfoToStats(origin: Deno.FileInfo): Stats { - return { + const stats = ObjectCreate(Stats.prototype); + ObjectAssign(stats, { dev: origin.dev, ino: origin.ino, mode: origin.mode, @@ -189,7 +270,9 @@ export function convertFileInfoToStats(origin: Deno.FileInfo): Stats { isSocket: () => false, ctime: origin.mtime, ctimeMs: origin.mtime?.getTime() || null, - }; + }); + + return stats; } function toBigInt(number?: number | null) { @@ -200,7 +283,8 @@ function toBigInt(number?: number | null) { export function convertFileInfoToBigIntStats( origin: Deno.FileInfo, ): BigIntStats { - return { + const stats = ObjectCreate(BigIntStats.prototype); + ObjectAssign(stats, { dev: toBigInt(origin.dev), ino: toBigInt(origin.ino), mode: toBigInt(origin.mode), @@ -233,7 +317,8 @@ export function convertFileInfoToBigIntStats( ctime: origin.mtime, ctimeMs: origin.mtime ? BigInt(origin.mtime.getTime()) : null, ctimeNs: origin.mtime ? BigInt(origin.mtime.getTime()) * 1000000n : null, - }; + }); + return stats; } // shortcut for Convert File Info to Stats or BigIntStats diff --git a/ext/node/polyfills/_fs/_fs_watch.ts b/ext/node/polyfills/_fs/_fs_watch.ts index 2ba372e34..78903cd55 100644 --- a/ext/node/polyfills/_fs/_fs_watch.ts +++ b/ext/node/polyfills/_fs/_fs_watch.ts @@ -10,7 +10,6 @@ import { promisify } from "node:util"; import { getValidatedPath } from "ext:deno_node/internal/fs/utils.mjs"; import { validateFunction } from "ext:deno_node/internal/validators.mjs"; import { stat, Stats } from "ext:deno_node/_fs/_fs_stat.ts"; -import { Stats as StatsClass } from "ext:deno_node/internal/fs/utils.mjs"; import { Buffer } from "node:buffer"; import { delay } from "ext:deno_node/_util/async.ts"; @@ -22,7 +21,7 @@ const statAsync = async (filename: string): Promise<Stats | null> => { return emptyStats; } }; -const emptyStats = new StatsClass( +const emptyStats = new Stats( 0, 0, 0, diff --git a/ext/node/polyfills/fs.ts b/ext/node/polyfills/fs.ts index 38a7a2bfb..bf43dd92e 100644 --- a/ext/node/polyfills/fs.ts +++ b/ext/node/polyfills/fs.ts @@ -69,7 +69,12 @@ import { } from "ext:deno_node/_fs/_fs_rename.ts"; import { rmdir, rmdirPromise, rmdirSync } from "ext:deno_node/_fs/_fs_rmdir.ts"; import { rm, rmPromise, rmSync } from "ext:deno_node/_fs/_fs_rm.ts"; -import { stat, statPromise, statSync } from "ext:deno_node/_fs/_fs_stat.ts"; +import { + stat, + statPromise, + Stats, + statSync, +} from "ext:deno_node/_fs/_fs_stat.ts"; import { symlink, symlinkPromise, @@ -105,7 +110,6 @@ import { writeFilePromise, writeFileSync, } from "ext:deno_node/_fs/_fs_writeFile.ts"; -import { Stats } from "ext:deno_node/internal/fs/utils.mjs"; // @deno-types="./internal/fs/streams.d.ts" import { createReadStream, diff --git a/tests/unit_node/fs_test.ts b/tests/unit_node/fs_test.ts index 4a8ef89f3..caa266ef2 100644 --- a/tests/unit_node/fs_test.ts +++ b/tests/unit_node/fs_test.ts @@ -9,6 +9,8 @@ import { mkdtempSync, promises, readFileSync, + Stats, + statSync, writeFileSync, } from "node:fs"; import { constants as fsPromiseConstants, cp } from "node:fs/promises"; @@ -98,6 +100,15 @@ Deno.test( ); Deno.test( + "[node/fs statSync] instanceof fs.Stats", + () => { + const stat = statSync("tests/testdata/assets/fixture.json"); + assert(stat); + assert(stat instanceof Stats); + }, +); + +Deno.test( "[node/fs/promises cp] copy file", async () => { const src = mkdtempSync(join(tmpdir(), "foo-")) + "/test.txt"; |