1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-24 08:09:08 -05:00

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>
This commit is contained in:
Divy Srivastava 2024-03-06 18:29:10 +05:30 committed by GitHub
parent 156950828e
commit 6ba0b7952d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 111 additions and 12 deletions

View file

@ -5,13 +5,16 @@
import { denoErrorToNodeError } from "ext:deno_node/internal/errors.ts"; import { denoErrorToNodeError } from "ext:deno_node/internal/errors.ts";
import { promisify } from "ext:deno_node/internal/util.mjs"; import { promisify } from "ext:deno_node/internal/util.mjs";
import { primordials } from "ext:core/mod.js";
const { ObjectCreate, ObjectAssign } = primordials;
export type statOptions = { export type statOptions = {
bigint: boolean; bigint: boolean;
throwIfNoEntry?: boolean; throwIfNoEntry?: boolean;
}; };
export type Stats = { interface IStats {
/** ID of the device containing the file. /** ID of the device containing the file.
* *
* _Linux/Mac OS only._ */ * _Linux/Mac OS only._ */
@ -80,9 +83,84 @@ export type Stats = {
isFile: () => boolean; isFile: () => boolean;
isSocket: () => boolean; isSocket: () => boolean;
isSymbolicLink: () => boolean; isSymbolicLink: () => boolean;
}; }
export type BigIntStats = { 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 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. /** ID of the device containing the file.
* *
* _Linux/Mac OS only._ */ * _Linux/Mac OS only._ */
@ -159,10 +237,13 @@ export type BigIntStats = {
isFile: () => boolean; isFile: () => boolean;
isSocket: () => boolean; isSocket: () => boolean;
isSymbolicLink: () => boolean; isSymbolicLink: () => boolean;
}; }
export class BigIntStats {}
export function convertFileInfoToStats(origin: Deno.FileInfo): Stats { export function convertFileInfoToStats(origin: Deno.FileInfo): Stats {
return { const stats = ObjectCreate(Stats.prototype);
ObjectAssign(stats, {
dev: origin.dev, dev: origin.dev,
ino: origin.ino, ino: origin.ino,
mode: origin.mode, mode: origin.mode,
@ -189,7 +270,9 @@ export function convertFileInfoToStats(origin: Deno.FileInfo): Stats {
isSocket: () => false, isSocket: () => false,
ctime: origin.mtime, ctime: origin.mtime,
ctimeMs: origin.mtime?.getTime() || null, ctimeMs: origin.mtime?.getTime() || null,
}; });
return stats;
} }
function toBigInt(number?: number | null) { function toBigInt(number?: number | null) {
@ -200,7 +283,8 @@ function toBigInt(number?: number | null) {
export function convertFileInfoToBigIntStats( export function convertFileInfoToBigIntStats(
origin: Deno.FileInfo, origin: Deno.FileInfo,
): BigIntStats { ): BigIntStats {
return { const stats = ObjectCreate(BigIntStats.prototype);
ObjectAssign(stats, {
dev: toBigInt(origin.dev), dev: toBigInt(origin.dev),
ino: toBigInt(origin.ino), ino: toBigInt(origin.ino),
mode: toBigInt(origin.mode), mode: toBigInt(origin.mode),
@ -233,7 +317,8 @@ export function convertFileInfoToBigIntStats(
ctime: origin.mtime, ctime: origin.mtime,
ctimeMs: origin.mtime ? BigInt(origin.mtime.getTime()) : null, ctimeMs: origin.mtime ? BigInt(origin.mtime.getTime()) : null,
ctimeNs: origin.mtime ? BigInt(origin.mtime.getTime()) * 1000000n : null, ctimeNs: origin.mtime ? BigInt(origin.mtime.getTime()) * 1000000n : null,
}; });
return stats;
} }
// shortcut for Convert File Info to Stats or BigIntStats // shortcut for Convert File Info to Stats or BigIntStats

View file

@ -10,7 +10,6 @@ import { promisify } from "node:util";
import { getValidatedPath } from "ext:deno_node/internal/fs/utils.mjs"; import { getValidatedPath } from "ext:deno_node/internal/fs/utils.mjs";
import { validateFunction } from "ext:deno_node/internal/validators.mjs"; import { validateFunction } from "ext:deno_node/internal/validators.mjs";
import { stat, Stats } from "ext:deno_node/_fs/_fs_stat.ts"; 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 { Buffer } from "node:buffer";
import { delay } from "ext:deno_node/_util/async.ts"; import { delay } from "ext:deno_node/_util/async.ts";
@ -22,7 +21,7 @@ const statAsync = async (filename: string): Promise<Stats | null> => {
return emptyStats; return emptyStats;
} }
}; };
const emptyStats = new StatsClass( const emptyStats = new Stats(
0, 0,
0, 0,
0, 0,

View file

@ -69,7 +69,12 @@ import {
} from "ext:deno_node/_fs/_fs_rename.ts"; } from "ext:deno_node/_fs/_fs_rename.ts";
import { rmdir, rmdirPromise, rmdirSync } from "ext:deno_node/_fs/_fs_rmdir.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 { 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 { import {
symlink, symlink,
symlinkPromise, symlinkPromise,
@ -105,7 +110,6 @@ import {
writeFilePromise, writeFilePromise,
writeFileSync, writeFileSync,
} from "ext:deno_node/_fs/_fs_writeFile.ts"; } 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" // @deno-types="./internal/fs/streams.d.ts"
import { import {
createReadStream, createReadStream,

View file

@ -9,6 +9,8 @@ import {
mkdtempSync, mkdtempSync,
promises, promises,
readFileSync, readFileSync,
Stats,
statSync,
writeFileSync, writeFileSync,
} from "node:fs"; } from "node:fs";
import { constants as fsPromiseConstants, cp } from "node:fs/promises"; import { constants as fsPromiseConstants, cp } from "node:fs/promises";
@ -97,6 +99,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( Deno.test(
"[node/fs/promises cp] copy file", "[node/fs/promises cp] copy file",
async () => { async () => {