Skip to content

Commit

Permalink
fix: 🐛 BigInt type handling
Browse files Browse the repository at this point in the history
  • Loading branch information
pizzafroide committed Feb 15, 2019
1 parent b774590 commit c640f25
Show file tree
Hide file tree
Showing 9 changed files with 79 additions and 65 deletions.
19 changes: 10 additions & 9 deletions package.json
Expand Up @@ -9,7 +9,7 @@
],
"scripts": {
"clean": "rimraf lib types",
"build": "tsc -p .",
"build": "tsc -p . && cpy src/*.js lib",
"test": "jest",
"test:coverage": "jest --coverage",
"test:watch": "jest --watch",
Expand All @@ -30,22 +30,23 @@
"fs-monkey": "^0.3.3"
},
"devDependencies": {
"@semantic-release/changelog": "3.0.2",
"@semantic-release/git": "7.0.8",
"@semantic-release/npm": "5.1.4",
"@types/jest": "23.3.14",
"@types/node": "10.12.26",
"cpy-cli": "^2.0.0",
"husky": "1.3.1",
"jest": "21.2.1",
"prettier": "1.16.4",
"pretty-quick": "1.10.0",
"rimraf": "2.6.3",
"semantic-release": "15.13.3",
"@semantic-release/changelog": "3.0.2",
"@semantic-release/npm": "5.1.4",
"@semantic-release/git": "7.0.8",
"ts-jest": "23.10.5",
"ts-node": "7.0.1",
"typescript": "3.3.3",
"prettier": "1.16.4",
"pretty-quick": "1.10.0",
"husky": "1.3.1",
"tslint": "5.12.1",
"tslint-config-common": "1.6.0"
"tslint-config-common": "1.6.0",
"typescript": "3.3.3"
},
"config": {
"commitizen": {
Expand Down
67 changes: 35 additions & 32 deletions src/Stats.ts
@@ -1,25 +1,23 @@
import { Node } from './node';
import { constants } from './constants';
import getBigInt from './getBigInt';

const { S_IFMT, S_IFDIR, S_IFREG, S_IFBLK, S_IFCHR, S_IFLNK, S_IFIFO, S_IFSOCK } = constants;

export type TStatNumber = number | BigInt;
export type TStatNumber = number | bigint;

/**
* Statistics about a file/directory, like `fs.Stats`.
*/
export class Stats {
static build(node: Node, bigint: boolean = false) {
const stats = new Stats();
export class Stats<T = TStatNumber> {
static build(node: Node, bigint: false): Stats<number>;
static build(node: Node, bigint: true): Stats<bigint>;
static build(node: Node, bigint?: boolean): Stats<TStatNumber>;
static build(node: Node, bigint: boolean = false): Stats<TStatNumber> {
const stats = new Stats<TStatNumber>();
const { uid, gid, atime, mtime, ctime } = node;

const getStatNumber = !bigint
? number => number
: typeof BigInt === 'function'
? BigInt
: () => {
throw new Error('BigInt is not supported in this environment.');
};
const getStatNumber = !bigint ? number => number : getBigInt;

// Copy all values on Stats from Node, so that if Node values
// change, values on Stats would still be the old ones,
Expand All @@ -28,6 +26,12 @@ export class Stats {
stats.uid = getStatNumber(uid);
stats.gid = getStatNumber(gid);

stats.rdev = getStatNumber(0);
stats.blksize = getStatNumber(4096);
stats.ino = getStatNumber(node.ino);
stats.size = getStatNumber(node.getSize());
stats.blocks = getStatNumber(1);

stats.atime = atime;
stats.mtime = mtime;
stats.ctime = ctime;
Expand All @@ -39,39 +43,38 @@ export class Stats {
stats.ctimeMs = ctimeMs;
stats.birthtimeMs = ctimeMs;

stats.size = getStatNumber(node.getSize());
stats.dev = getStatNumber(0);
stats.mode = getStatNumber(node.mode);
stats.ino = getStatNumber(node.ino);
stats.nlink = getStatNumber(node.nlink);

return stats;
}

uid: TStatNumber = 0;
gid: TStatNumber = 0;
uid: T;
gid: T;

rdev: TStatNumber = 0;
blksize: TStatNumber = 4096;
ino: TStatNumber = 0;
size: TStatNumber = 0;
blocks: TStatNumber = 1;
rdev: T;
blksize: T;
ino: T;
size: T;
blocks: T;

atime: Date = null;
mtime: Date = null;
ctime: Date = null;
birthtime: Date = null;
atime: Date;
mtime: Date;
ctime: Date;
birthtime: Date;

atimeMs: TStatNumber = 0.0;
mtimeMs: TStatNumber = 0.0;
ctimeMs: TStatNumber = 0.0;
birthtimeMs: TStatNumber = 0.0;
atimeMs: T;
mtimeMs: T;
ctimeMs: T;
birthtimeMs: T;

dev: TStatNumber = 0;
mode: TStatNumber = 0;
nlink: TStatNumber = 0;
dev: T;
mode: T;
nlink: T;

private _checkModeProperty(property: number): boolean {
return (this.mode & S_IFMT) === property;
return (Number(this.mode) & S_IFMT) === property;
}

isDirectory(): boolean {
Expand Down
1 change: 1 addition & 0 deletions src/__tests__/hasBigInt.js
@@ -0,0 +1 @@
exports.default = typeof BigInt === 'function';
11 changes: 4 additions & 7 deletions src/__tests__/volume.test.ts
Expand Up @@ -3,10 +3,7 @@ import { Link, Node } from '../node';
import Stats from '../Stats';
import Dirent from '../Dirent';
import { Volume, filenameToSteps, StatWatcher } from '../volume';

// I did not find how to include '../bigint.d.ts' here!
type BigInt = number;
declare const BigInt: typeof Number;
import hasBigInt from './hasBigInt';

describe('volume', () => {
describe('filenameToSteps(filename): string[]', () => {
Expand Down Expand Up @@ -670,7 +667,7 @@ describe('volume', () => {
expect(stats.isDirectory()).toBe(false);
});
it('Returns file stats using BigInt', () => {
if (typeof BigInt === 'function') {
if (hasBigInt) {
const stats = vol.lstatSync('/dojo.js', { bigint: true });
expect(typeof stats.ino).toBe('bigint');
} else {
Expand Down Expand Up @@ -701,7 +698,7 @@ describe('volume', () => {
expect(stats.isDirectory()).toBe(false);
});
it('Returns file stats using BigInt', () => {
if (typeof BigInt === 'function') {
if (hasBigInt) {
const stats = vol.statSync('/dojo.js', { bigint: true });
expect(typeof stats.ino).toBe('bigint');
} else {
Expand Down Expand Up @@ -745,7 +742,7 @@ describe('volume', () => {
});
it('Returns file stats using BigInt', () => {
const fd = vol.openSync('/dojo.js', 'r');
if (typeof BigInt === 'function') {
if (hasBigInt) {
const stats = vol.fstatSync(fd, { bigint: true });
expect(typeof stats.ino).toBe('bigint');
} else {
Expand Down
6 changes: 0 additions & 6 deletions src/bigint.d.ts

This file was deleted.

5 changes: 5 additions & 0 deletions src/getBigInt.js
@@ -0,0 +1,5 @@
if (typeof BigInt === 'function') exports.default = BigInt;
else
exports.default = function BigIntNotSupported() {
throw new Error('BigInt is not supported in this environment.');
};
4 changes: 2 additions & 2 deletions src/node.ts
Expand Up @@ -416,8 +416,8 @@ export class File {
this.position = position;
}

stats(): Stats {
return Stats.build(this.node);
stats(): Stats<number> {
return Stats.build(this.node) as Stats<number>;
}

write(buf: Buffer, offset: number = 0, length: number = buf.length, position?: number): number {
Expand Down
23 changes: 20 additions & 3 deletions src/volume.ts
Expand Up @@ -1430,14 +1430,19 @@ export class Volume {
this.wrapAsync(this.realpathBase, [pathFilename, opts.encoding], callback);
}

private lstatBase(filename: string, bigint: false): Stats<number>;
private lstatBase(filename: string, bigint: true): Stats<bigint>;
private lstatBase(filename: string, bigint: boolean = false): Stats {
const link: Link = this.getLink(filenameToSteps(filename));
if (!link) throwError(ENOENT, 'lstat', filename);
return Stats.build(link.getNode(), bigint);
}

lstatSync(path: TFilePath): Stats<number>;
lstatSync(path: TFilePath, options: { bigint: false }): Stats<number>;
lstatSync(path: TFilePath, options: { bigint: true }): Stats<bigint>;
lstatSync(path: TFilePath, options?: IStatOptions): Stats {
return this.lstatBase(pathToFilename(path), getStatOptions(options).bigint);
return this.lstatBase(pathToFilename(path), getStatOptions(options).bigint as any);
}

lstat(path: TFilePath, callback: TCallback<Stats>);
Expand All @@ -1447,6 +1452,9 @@ export class Volume {
this.wrapAsync(this.lstatBase, [pathToFilename(path), opts.bigint], callback);
}

private statBase(filename: string): Stats<number>;
private statBase(filename: string, bigint: false): Stats<number>;
private statBase(filename: string, bigint: true): Stats<bigint>;
private statBase(filename: string, bigint: boolean = false): Stats {
let link: Link = this.getLink(filenameToSteps(filename));
if (!link) throwError(ENOENT, 'stat', filename);
Expand All @@ -1458,8 +1466,11 @@ export class Volume {
return Stats.build(link.getNode(), bigint);
}

statSync(path: TFilePath): Stats<number>;
statSync(path: TFilePath, options: { bigint: false }): Stats<number>;
statSync(path: TFilePath, options: { bigint: true }): Stats<bigint>;
statSync(path: TFilePath, options?: IStatOptions): Stats {
return this.statBase(pathToFilename(path), getStatOptions(options).bigint);
return this.statBase(pathToFilename(path), getStatOptions(options).bigint as any);
}

stat(path: TFilePath, callback: TCallback<Stats>);
Expand All @@ -1469,14 +1480,20 @@ export class Volume {
this.wrapAsync(this.statBase, [pathToFilename(path), opts.bigint], callback);
}

private fstatBase(fd: number): Stats<number>;
private fstatBase(fd: number, bigint: false): Stats<number>;
private fstatBase(fd: number, bigint: true): Stats<bigint>;
private fstatBase(fd: number, bigint: boolean = false): Stats {
const file = this.getFileByFd(fd);
if (!file) throwError(EBADF, 'fstat');
return Stats.build(file.node, bigint);
}

fstatSync(fd: number): Stats<number>;
fstatSync(fd: number, options: { bigint: false }): Stats<number>;
fstatSync(fd: number, options: { bigint: true }): Stats<bigint>;
fstatSync(fd: number, options?: IStatOptions): Stats {
return this.fstatBase(fd, getStatOptions(options).bigint);
return this.fstatBase(fd, getStatOptions(options).bigint as any);
}

fstat(fd: number, callback: TCallback<Stats>);
Expand Down
8 changes: 2 additions & 6 deletions tsconfig.json
Expand Up @@ -9,10 +9,6 @@
"outDir": "lib",
"declaration": true
},
"include": [
"src"
],
"exclude": [
"src/__tests__"
]
"include": ["src"],
"exclude": ["src/__tests__"]
}

0 comments on commit c640f25

Please sign in to comment.