mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
Co-authored-by: Jarred-Sumner <709451+Jarred-Sumner@users.noreply.github.com> Co-authored-by: Dylan Conway <35280289+dylan-conway@users.noreply.github.com>
This commit is contained in:
@@ -1,13 +1,14 @@
|
|||||||
---
|
---
|
||||||
description: JavaScript class implemented in C++
|
description: JavaScript class implemented in C++
|
||||||
globs: *.cpp
|
globs: *.cpp
|
||||||
|
alwaysApply: false
|
||||||
---
|
---
|
||||||
|
|
||||||
# Implementing JavaScript classes in C++
|
# Implementing JavaScript classes in C++
|
||||||
|
|
||||||
If there is a publicly accessible Constructor and Prototype, then there are 3 classes:
|
If there is a publicly accessible Constructor and Prototype, then there are 3 classes:
|
||||||
|
|
||||||
- IF there are C++ class members we need a destructor, so `class Foo : public JSC::DestructibleObject`, if no C++ class fields (only JS properties) then we don't need a class at all usually. We can instead use JSC::constructEmptyObject(vm, structure) and `putDirectOffset` like in [NodeFSBinding.cpp](mdc:src/bun.js/bindings/NodeFSBinding.cpp).
|
- IF there are C++ class members we need a destructor, so `class Foo : public JSC::DestructibleObject`, if no C++ class fields (only JS properties) then we don't need a class at all usually. We can instead use JSC::constructEmptyObject(vm, structure) and `putDirectOffset` like in [NodeFSStatBinding.cpp](mdc:src/bun.js/bindings/NodeFSStatBinding.cpp).
|
||||||
- class FooPrototype : public JSC::JSNonFinalObject
|
- class FooPrototype : public JSC::JSNonFinalObject
|
||||||
- class FooConstructor : public JSC::InternalFunction
|
- class FooConstructor : public JSC::InternalFunction
|
||||||
|
|
||||||
@@ -18,6 +19,7 @@ If there are C++ fields on the Foo class, the Foo class will need an iso subspac
|
|||||||
Usually you'll need to #include "root.h" at the top of C++ files or you'll get lint errors.
|
Usually you'll need to #include "root.h" at the top of C++ files or you'll get lint errors.
|
||||||
|
|
||||||
Generally, defining the subspace looks like this:
|
Generally, defining the subspace looks like this:
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
|
|
||||||
class Foo : public JSC::DestructibleObject {
|
class Foo : public JSC::DestructibleObject {
|
||||||
@@ -45,6 +47,7 @@ It's better to put it in the .cpp file instead of the .h file, when possible.
|
|||||||
## Defining properties
|
## Defining properties
|
||||||
|
|
||||||
Define properties on the prototype. Use a const HashTableValues like this:
|
Define properties on the prototype. Use a const HashTableValues like this:
|
||||||
|
|
||||||
```C++
|
```C++
|
||||||
static JSC_DECLARE_HOST_FUNCTION(jsX509CertificateProtoFuncCheckEmail);
|
static JSC_DECLARE_HOST_FUNCTION(jsX509CertificateProtoFuncCheckEmail);
|
||||||
static JSC_DECLARE_HOST_FUNCTION(jsX509CertificateProtoFuncCheckHost);
|
static JSC_DECLARE_HOST_FUNCTION(jsX509CertificateProtoFuncCheckHost);
|
||||||
@@ -158,6 +161,7 @@ void JSX509CertificatePrototype::finishCreation(VM& vm)
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Getter definition:
|
### Getter definition:
|
||||||
|
|
||||||
```C++
|
```C++
|
||||||
|
|
||||||
JSC_DEFINE_CUSTOM_GETTER(jsX509CertificateGetter_ca, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName))
|
JSC_DEFINE_CUSTOM_GETTER(jsX509CertificateGetter_ca, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName))
|
||||||
@@ -212,7 +216,6 @@ JSC_DEFINE_HOST_FUNCTION(jsX509CertificateProtoFuncToJSON, (JSGlobalObject * glo
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Constructor definition
|
### Constructor definition
|
||||||
|
|
||||||
```C++
|
```C++
|
||||||
@@ -259,7 +262,6 @@ private:
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Structure caching
|
### Structure caching
|
||||||
|
|
||||||
If there's a class, prototype, and constructor:
|
If there's a class, prototype, and constructor:
|
||||||
@@ -279,6 +281,7 @@ void GlobalObject::finishCreation(VM& vm) {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Then, implement the function that creates the structure:
|
Then, implement the function that creates the structure:
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
void setupX509CertificateClassStructure(LazyClassStructure::Initializer& init)
|
void setupX509CertificateClassStructure(LazyClassStructure::Initializer& init)
|
||||||
{
|
{
|
||||||
@@ -301,11 +304,12 @@ If there's only a class, use `JSC::LazyProperty<JSGlobalObject, Structure>` inst
|
|||||||
1. Add the `JSC::LazyProperty<JSGlobalObject, Structure>` to @ZigGlobalObject.h
|
1. Add the `JSC::LazyProperty<JSGlobalObject, Structure>` to @ZigGlobalObject.h
|
||||||
2. Initialize the class structure in @ZigGlobalObject.cpp in `void GlobalObject::finishCreation(VM& vm)`
|
2. Initialize the class structure in @ZigGlobalObject.cpp in `void GlobalObject::finishCreation(VM& vm)`
|
||||||
3. Visit the lazy property in visitChildren in @ZigGlobalObject.cpp in `void GlobalObject::visitChildrenImpl`
|
3. Visit the lazy property in visitChildren in @ZigGlobalObject.cpp in `void GlobalObject::visitChildrenImpl`
|
||||||
void GlobalObject::finishCreation(VM& vm) {
|
void GlobalObject::finishCreation(VM& vm) {
|
||||||
// ...
|
// ...
|
||||||
this.m_myLazyProperty.initLater([](const JSC::LazyProperty<JSC::JSGlobalObject, JSC::Structure>::Initializer& init) {
|
this.m_myLazyProperty.initLater([](const JSC::LazyProperty<JSC::JSGlobalObject, JSC::Structure>::Initializer& init) {
|
||||||
init.set(Bun::initMyStructure(init.vm, reinterpret_cast<Zig::GlobalObject*>(init.owner)));
|
init.set(Bun::initMyStructure(init.vm, reinterpret_cast<Zig::GlobalObject\*>(init.owner)));
|
||||||
});
|
});
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Then, implement the function that creates the structure:
|
Then, implement the function that creates the structure:
|
||||||
@@ -316,7 +320,7 @@ Structure* setupX509CertificateStructure(JSC::VM &vm, Zig::GlobalObject* globalO
|
|||||||
auto* prototypeStructure = JSX509CertificatePrototype::createStructure(init.vm, init.global, init.global->objectPrototype());
|
auto* prototypeStructure = JSX509CertificatePrototype::createStructure(init.vm, init.global, init.global->objectPrototype());
|
||||||
auto* prototype = JSX509CertificatePrototype::create(init.vm, init.global, prototypeStructure);
|
auto* prototype = JSX509CertificatePrototype::create(init.vm, init.global, prototypeStructure);
|
||||||
|
|
||||||
// If there is no prototype or it only has
|
// If there is no prototype or it only has
|
||||||
|
|
||||||
auto* structure = JSX509Certificate::createStructure(init.vm, init.global, prototype);
|
auto* structure = JSX509Certificate::createStructure(init.vm, init.global, prototype);
|
||||||
init.setPrototype(prototype);
|
init.setPrototype(prototype);
|
||||||
@@ -325,7 +329,6 @@ Structure* setupX509CertificateStructure(JSC::VM &vm, Zig::GlobalObject* globalO
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
Then, use the structure by calling `globalObject.m_myStructureName.get(globalObject)`
|
Then, use the structure by calling `globalObject.m_myStructureName.get(globalObject)`
|
||||||
|
|
||||||
```C++
|
```C++
|
||||||
@@ -378,12 +381,14 @@ extern "C" JSC::EncodedJSValue Bun__JSBigIntStatsObjectConstructor(Zig::GlobalOb
|
|||||||
```
|
```
|
||||||
|
|
||||||
Zig:
|
Zig:
|
||||||
|
|
||||||
```zig
|
```zig
|
||||||
extern "c" fn Bun__JSBigIntStatsObjectConstructor(*JSC.JSGlobalObject) JSC.JSValue;
|
extern "c" fn Bun__JSBigIntStatsObjectConstructor(*JSC.JSGlobalObject) JSC.JSValue;
|
||||||
pub const getBigIntStatsConstructor = Bun__JSBigIntStatsObjectConstructor;
|
pub const getBigIntStatsConstructor = Bun__JSBigIntStatsObjectConstructor;
|
||||||
```
|
```
|
||||||
|
|
||||||
To create an object (instance) of a JS class defined in C++ from Zig, follow the __toJS convention like this:
|
To create an object (instance) of a JS class defined in C++ from Zig, follow the \_\_toJS convention like this:
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
// X509* is whatever we need to create the object
|
// X509* is whatever we need to create the object
|
||||||
extern "C" EncodedJSValue Bun__X509__toJS(Zig::GlobalObject* globalObject, X509* cert)
|
extern "C" EncodedJSValue Bun__X509__toJS(Zig::GlobalObject* globalObject, X509* cert)
|
||||||
@@ -395,12 +400,13 @@ extern "C" EncodedJSValue Bun__X509__toJS(Zig::GlobalObject* globalObject, X509*
|
|||||||
```
|
```
|
||||||
|
|
||||||
And from Zig:
|
And from Zig:
|
||||||
|
|
||||||
```zig
|
```zig
|
||||||
const X509 = opaque {
|
const X509 = opaque {
|
||||||
// ... class
|
// ... class
|
||||||
|
|
||||||
extern fn Bun__X509__toJS(*JSC.JSGlobalObject, *X509) JSC.JSValue;
|
extern fn Bun__X509__toJS(*JSC.JSGlobalObject, *X509) JSC.JSValue;
|
||||||
|
|
||||||
pub fn toJS(this: *X509, globalObject: *JSC.JSGlobalObject) JSC.JSValue {
|
pub fn toJS(this: *X509, globalObject: *JSC.JSGlobalObject) JSC.JSValue {
|
||||||
return Bun__X509__toJS(globalObject, this);
|
return Bun__X509__toJS(globalObject, this);
|
||||||
}
|
}
|
||||||
|
|||||||
460
src/bun.js/bindings/NodeFSStatFSBinding.cpp
Normal file
460
src/bun.js/bindings/NodeFSStatFSBinding.cpp
Normal file
@@ -0,0 +1,460 @@
|
|||||||
|
#include "root.h"
|
||||||
|
|
||||||
|
#include "JavaScriptCore/FunctionPrototype.h"
|
||||||
|
#include "JavaScriptCore/LazyClassStructure.h"
|
||||||
|
#include "JavaScriptCore/LazyClassStructureInlines.h"
|
||||||
|
#include "JavaScriptCore/VMTrapsInlines.h"
|
||||||
|
#include "BunBuiltinNames.h"
|
||||||
|
#include "JavaScriptCore/ArgList.h"
|
||||||
|
#include "JavaScriptCore/JSType.h"
|
||||||
|
#include "JavaScriptCore/ObjectInitializationScope.h"
|
||||||
|
|
||||||
|
#include "JavaScriptCore/ObjectConstructor.h"
|
||||||
|
#include <JavaScriptCore/InternalFunction.h>
|
||||||
|
#include <JavaScriptCore/JSGlobalObject.h>
|
||||||
|
#include <JavaScriptCore/Identifier.h>
|
||||||
|
#include <JavaScriptCore/JSCInlines.h>
|
||||||
|
#include <JavaScriptCore/JSObject.h>
|
||||||
|
#include <JavaScriptCore/Structure.h>
|
||||||
|
#include <JavaScriptCore/PropertyNameArray.h>
|
||||||
|
#include "ZigGlobalObject.h"
|
||||||
|
|
||||||
|
namespace Bun {
|
||||||
|
|
||||||
|
class JSStatFSPrototype;
|
||||||
|
class JSBigIntStatFSPrototype;
|
||||||
|
class JSStatFSConstructor;
|
||||||
|
class JSBigIntStatFSConstructor;
|
||||||
|
using namespace JSC;
|
||||||
|
using namespace WebCore;
|
||||||
|
|
||||||
|
JSC_DECLARE_HOST_FUNCTION(callStatFS);
|
||||||
|
JSC_DECLARE_HOST_FUNCTION(callBigIntStatFS);
|
||||||
|
JSC_DECLARE_HOST_FUNCTION(constructStatFS);
|
||||||
|
JSC_DECLARE_HOST_FUNCTION(constructBigIntStatFS);
|
||||||
|
|
||||||
|
template<bool isBigInt>
|
||||||
|
Structure* getStatFSStructure(Zig::GlobalObject* globalObject)
|
||||||
|
{
|
||||||
|
if (isBigInt) {
|
||||||
|
return globalObject->m_JSStatFSBigIntClassStructure.getInitializedOnMainThread(globalObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
return globalObject->m_JSStatFSClassStructure.getInitializedOnMainThread(globalObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isBigInt>
|
||||||
|
JSObject* getStatFSPrototype(Zig::GlobalObject* globalObject)
|
||||||
|
{
|
||||||
|
if (isBigInt) {
|
||||||
|
return globalObject->m_JSStatFSBigIntClassStructure.prototypeInitializedOnMainThread(globalObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
return globalObject->m_JSStatFSClassStructure.prototypeInitializedOnMainThread(globalObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isBigInt>
|
||||||
|
JSObject* getStatFSConstructor(Zig::GlobalObject* globalObject)
|
||||||
|
{
|
||||||
|
if (isBigInt) {
|
||||||
|
return globalObject->m_JSStatFSBigIntClassStructure.constructorInitializedOnMainThread(globalObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
return globalObject->m_JSStatFSClassStructure.constructorInitializedOnMainThread(globalObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
class JSStatFSPrototype final : public JSC::JSNonFinalObject {
|
||||||
|
public:
|
||||||
|
using Base = JSC::JSNonFinalObject;
|
||||||
|
static constexpr unsigned StructureFlags = Base::StructureFlags;
|
||||||
|
|
||||||
|
static JSStatFSPrototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)
|
||||||
|
{
|
||||||
|
JSStatFSPrototype* prototype = new (NotNull, JSC::allocateCell<JSStatFSPrototype>(vm)) JSStatFSPrototype(vm, structure);
|
||||||
|
prototype->finishCreation(vm);
|
||||||
|
return prototype;
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLARE_INFO;
|
||||||
|
|
||||||
|
template<typename CellType, JSC::SubspaceAccess>
|
||||||
|
static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
|
||||||
|
{
|
||||||
|
STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSStatFSPrototype, Base);
|
||||||
|
return &vm.plainObjectSpace();
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
|
||||||
|
{
|
||||||
|
auto* structure = JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
|
||||||
|
structure->setMayBePrototype(true);
|
||||||
|
return structure;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
JSStatFSPrototype(JSC::VM& vm, JSC::Structure* structure)
|
||||||
|
: Base(vm, structure)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void finishCreation(JSC::VM& vm);
|
||||||
|
};
|
||||||
|
|
||||||
|
class JSBigIntStatFSPrototype final : public JSC::JSNonFinalObject {
|
||||||
|
public:
|
||||||
|
using Base = JSC::JSNonFinalObject;
|
||||||
|
static constexpr unsigned StructureFlags = Base::StructureFlags;
|
||||||
|
|
||||||
|
static JSBigIntStatFSPrototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)
|
||||||
|
{
|
||||||
|
JSBigIntStatFSPrototype* prototype = new (NotNull, JSC::allocateCell<JSBigIntStatFSPrototype>(vm)) JSBigIntStatFSPrototype(vm, structure);
|
||||||
|
prototype->finishCreation(vm);
|
||||||
|
return prototype;
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLARE_INFO;
|
||||||
|
|
||||||
|
template<typename CellType, JSC::SubspaceAccess>
|
||||||
|
static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
|
||||||
|
{
|
||||||
|
STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSBigIntStatFSPrototype, Base);
|
||||||
|
return &vm.plainObjectSpace();
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
|
||||||
|
{
|
||||||
|
auto* structure = JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
|
||||||
|
structure->setMayBePrototype(true);
|
||||||
|
return structure;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
JSBigIntStatFSPrototype(JSC::VM& vm, JSC::Structure* structure)
|
||||||
|
: Base(vm, structure)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void finishCreation(JSC::VM& vm);
|
||||||
|
};
|
||||||
|
|
||||||
|
class JSStatFSConstructor final : public JSC::InternalFunction {
|
||||||
|
public:
|
||||||
|
using Base = JSC::InternalFunction;
|
||||||
|
static constexpr unsigned StructureFlags = Base::StructureFlags;
|
||||||
|
|
||||||
|
static JSStatFSConstructor* create(JSC::VM& vm, JSC::Structure* structure, JSC::JSObject* prototype)
|
||||||
|
{
|
||||||
|
JSStatFSConstructor* constructor = new (NotNull, JSC::allocateCell<JSStatFSConstructor>(vm)) JSStatFSConstructor(vm, structure);
|
||||||
|
constructor->finishCreation(vm, prototype);
|
||||||
|
return constructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLARE_INFO;
|
||||||
|
|
||||||
|
template<typename CellType, JSC::SubspaceAccess>
|
||||||
|
static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
|
||||||
|
{
|
||||||
|
return &vm.internalFunctionSpace();
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
|
||||||
|
{
|
||||||
|
return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::InternalFunctionType, StructureFlags), info());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
JSStatFSConstructor(JSC::VM& vm, JSC::Structure* structure)
|
||||||
|
: Base(vm, structure, callStatFS, constructStatFS)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void finishCreation(JSC::VM& vm, JSC::JSObject* prototype)
|
||||||
|
{
|
||||||
|
Base::finishCreation(vm, 0, "StatFs"_s);
|
||||||
|
putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class JSBigIntStatFSConstructor final : public JSC::InternalFunction {
|
||||||
|
public:
|
||||||
|
using Base = JSC::InternalFunction;
|
||||||
|
static constexpr unsigned StructureFlags = Base::StructureFlags;
|
||||||
|
|
||||||
|
static JSBigIntStatFSConstructor* create(JSC::VM& vm, JSC::Structure* structure, JSC::JSObject* prototype)
|
||||||
|
{
|
||||||
|
JSBigIntStatFSConstructor* constructor = new (NotNull, JSC::allocateCell<JSBigIntStatFSConstructor>(vm)) JSBigIntStatFSConstructor(vm, structure);
|
||||||
|
constructor->finishCreation(vm, prototype);
|
||||||
|
return constructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLARE_INFO;
|
||||||
|
|
||||||
|
template<typename CellType, JSC::SubspaceAccess>
|
||||||
|
static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
|
||||||
|
{
|
||||||
|
return &vm.internalFunctionSpace();
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
|
||||||
|
{
|
||||||
|
return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::InternalFunctionType, StructureFlags), info());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
JSBigIntStatFSConstructor(JSC::VM& vm, JSC::Structure* structure)
|
||||||
|
: Base(vm, structure, callBigIntStatFS, constructBigIntStatFS)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void finishCreation(JSC::VM& vm, JSC::JSObject* prototype)
|
||||||
|
{
|
||||||
|
Base::finishCreation(vm, 0, "BigIntStatFs"_s);
|
||||||
|
putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
JSC::Structure* createJSStatFSObjectStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
|
||||||
|
{
|
||||||
|
auto* prototype = JSStatFSPrototype::create(vm, globalObject, JSStatFSPrototype::createStructure(vm, globalObject, globalObject->objectPrototype()));
|
||||||
|
auto structure = JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::FinalObjectType, 0), JSFinalObject::info(), NonArray, 7);
|
||||||
|
|
||||||
|
// Add property transitions for all statfs fields
|
||||||
|
PropertyOffset offset = 0;
|
||||||
|
structure = structure->addPropertyTransition(vm, structure, vm.propertyNames->type, 0, offset);
|
||||||
|
structure = structure->addPropertyTransition(vm, structure, JSC::Identifier::fromString(vm, "bsize"_s), 0, offset);
|
||||||
|
structure = structure->addPropertyTransition(vm, structure, JSC::Identifier::fromString(vm, "blocks"_s), 0, offset);
|
||||||
|
structure = structure->addPropertyTransition(vm, structure, JSC::Identifier::fromString(vm, "bfree"_s), 0, offset);
|
||||||
|
structure = structure->addPropertyTransition(vm, structure, JSC::Identifier::fromString(vm, "bavail"_s), 0, offset);
|
||||||
|
structure = structure->addPropertyTransition(vm, structure, JSC::Identifier::fromString(vm, "files"_s), 0, offset);
|
||||||
|
structure = structure->addPropertyTransition(vm, structure, JSC::Identifier::fromString(vm, "ffree"_s), 0, offset);
|
||||||
|
|
||||||
|
return structure;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSC::Structure* createJSBigIntStatFSObjectStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
|
||||||
|
{
|
||||||
|
auto prototype = JSBigIntStatFSPrototype::create(vm, globalObject, JSBigIntStatFSPrototype::createStructure(vm, globalObject, globalObject->objectPrototype()));
|
||||||
|
auto structure = JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::FinalObjectType, 0), JSFinalObject::info(), NonArray, 7);
|
||||||
|
|
||||||
|
// Add property transitions for all bigint statfs fields
|
||||||
|
PropertyOffset offset = 0;
|
||||||
|
structure = structure->addPropertyTransition(vm, structure, vm.propertyNames->type, 0, offset);
|
||||||
|
structure = structure->addPropertyTransition(vm, structure, JSC::Identifier::fromString(vm, "bsize"_s), 0, offset);
|
||||||
|
structure = structure->addPropertyTransition(vm, structure, JSC::Identifier::fromString(vm, "blocks"_s), 0, offset);
|
||||||
|
structure = structure->addPropertyTransition(vm, structure, JSC::Identifier::fromString(vm, "bfree"_s), 0, offset);
|
||||||
|
structure = structure->addPropertyTransition(vm, structure, JSC::Identifier::fromString(vm, "bavail"_s), 0, offset);
|
||||||
|
structure = structure->addPropertyTransition(vm, structure, JSC::Identifier::fromString(vm, "files"_s), 0, offset);
|
||||||
|
structure = structure->addPropertyTransition(vm, structure, JSC::Identifier::fromString(vm, "ffree"_s), 0, offset);
|
||||||
|
|
||||||
|
return structure;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" JSC::EncodedJSValue Bun__createJSStatFSObject(Zig::GlobalObject* globalObject,
|
||||||
|
int64_t fstype,
|
||||||
|
int64_t bsize,
|
||||||
|
int64_t blocks,
|
||||||
|
int64_t bfree,
|
||||||
|
int64_t bavail,
|
||||||
|
int64_t files,
|
||||||
|
int64_t ffree)
|
||||||
|
{
|
||||||
|
auto& vm = globalObject->vm();
|
||||||
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||||
|
|
||||||
|
JSC::JSValue js_fstype = JSC::jsNumber(fstype);
|
||||||
|
JSC::JSValue js_bsize = JSC::jsNumber(bsize);
|
||||||
|
JSC::JSValue js_blocks = JSC::jsNumber(blocks);
|
||||||
|
JSC::JSValue js_bfree = JSC::jsNumber(bfree);
|
||||||
|
JSC::JSValue js_bavail = JSC::jsNumber(bavail);
|
||||||
|
JSC::JSValue js_files = JSC::jsNumber(files);
|
||||||
|
JSC::JSValue js_ffree = JSC::jsNumber(ffree);
|
||||||
|
|
||||||
|
auto* structure = getStatFSStructure<false>(globalObject);
|
||||||
|
auto* object = JSC::JSFinalObject::create(vm, structure);
|
||||||
|
|
||||||
|
object->putDirectOffset(vm, 0, js_fstype);
|
||||||
|
object->putDirectOffset(vm, 1, js_bsize);
|
||||||
|
object->putDirectOffset(vm, 2, js_blocks);
|
||||||
|
object->putDirectOffset(vm, 3, js_bfree);
|
||||||
|
object->putDirectOffset(vm, 4, js_bavail);
|
||||||
|
object->putDirectOffset(vm, 5, js_files);
|
||||||
|
object->putDirectOffset(vm, 6, js_ffree);
|
||||||
|
|
||||||
|
RELEASE_AND_RETURN(scope, JSC::JSValue::encode(object));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" JSC::EncodedJSValue Bun__createJSBigIntStatFSObject(Zig::GlobalObject* globalObject,
|
||||||
|
int64_t fstype,
|
||||||
|
int64_t bsize,
|
||||||
|
int64_t blocks,
|
||||||
|
int64_t bfree,
|
||||||
|
int64_t bavail,
|
||||||
|
int64_t files,
|
||||||
|
int64_t ffree)
|
||||||
|
{
|
||||||
|
auto& vm = globalObject->vm();
|
||||||
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||||
|
|
||||||
|
auto* structure = getStatFSStructure<true>(globalObject);
|
||||||
|
JSC::JSValue js_fstype = JSC::JSBigInt::createFrom(globalObject, fstype);
|
||||||
|
JSC::JSValue js_bsize = JSC::JSBigInt::createFrom(globalObject, bsize);
|
||||||
|
JSC::JSValue js_blocks = JSC::JSBigInt::createFrom(globalObject, blocks);
|
||||||
|
JSC::JSValue js_bfree = JSC::JSBigInt::createFrom(globalObject, bfree);
|
||||||
|
JSC::JSValue js_bavail = JSC::JSBigInt::createFrom(globalObject, bavail);
|
||||||
|
JSC::JSValue js_files = JSC::JSBigInt::createFrom(globalObject, files);
|
||||||
|
JSC::JSValue js_ffree = JSC::JSBigInt::createFrom(globalObject, ffree);
|
||||||
|
|
||||||
|
auto* object = JSC::JSFinalObject::create(vm, structure);
|
||||||
|
|
||||||
|
object->putDirectOffset(vm, 0, js_fstype);
|
||||||
|
object->putDirectOffset(vm, 1, js_bsize);
|
||||||
|
object->putDirectOffset(vm, 2, js_blocks);
|
||||||
|
object->putDirectOffset(vm, 3, js_bfree);
|
||||||
|
object->putDirectOffset(vm, 4, js_bavail);
|
||||||
|
object->putDirectOffset(vm, 5, js_files);
|
||||||
|
object->putDirectOffset(vm, 6, js_ffree);
|
||||||
|
|
||||||
|
RELEASE_AND_RETURN(scope, JSC::JSValue::encode(object));
|
||||||
|
}
|
||||||
|
|
||||||
|
const JSC::ClassInfo JSStatFSPrototype::s_info = { "StatFs"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSStatFSPrototype) };
|
||||||
|
const JSC::ClassInfo JSBigIntStatFSPrototype::s_info = { "BigIntStatFs"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSBigIntStatFSPrototype) };
|
||||||
|
const JSC::ClassInfo JSStatFSConstructor::s_info = { "StatFs"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSStatFSConstructor) };
|
||||||
|
const JSC::ClassInfo JSBigIntStatFSConstructor::s_info = { "BigIntStatFs"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSBigIntStatFSConstructor) };
|
||||||
|
|
||||||
|
template<bool isBigInt>
|
||||||
|
inline JSValue callJSStatFSFunction(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame)
|
||||||
|
{
|
||||||
|
auto& vm = globalObject->vm();
|
||||||
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||||
|
auto* structure = getStatFSStructure<isBigInt>(defaultGlobalObject(globalObject));
|
||||||
|
|
||||||
|
JSValue type = callFrame->argument(0);
|
||||||
|
JSValue bsize = callFrame->argument(1);
|
||||||
|
JSValue blocks = callFrame->argument(2);
|
||||||
|
JSValue bfree = callFrame->argument(3);
|
||||||
|
JSValue bavail = callFrame->argument(4);
|
||||||
|
JSValue files = callFrame->argument(5);
|
||||||
|
JSValue ffree = callFrame->argument(6);
|
||||||
|
|
||||||
|
auto* object = JSC::JSFinalObject::create(vm, structure);
|
||||||
|
|
||||||
|
object->putDirectOffset(vm, 0, type);
|
||||||
|
object->putDirectOffset(vm, 1, bsize);
|
||||||
|
object->putDirectOffset(vm, 2, blocks);
|
||||||
|
object->putDirectOffset(vm, 3, bfree);
|
||||||
|
object->putDirectOffset(vm, 4, bavail);
|
||||||
|
object->putDirectOffset(vm, 5, files);
|
||||||
|
object->putDirectOffset(vm, 6, ffree);
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isBigInt>
|
||||||
|
inline JSValue constructJSStatFSObject(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame)
|
||||||
|
{
|
||||||
|
auto& vm = lexicalGlobalObject->vm();
|
||||||
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||||
|
Zig::GlobalObject* globalObject = defaultGlobalObject(lexicalGlobalObject);
|
||||||
|
|
||||||
|
auto* structure = getStatFSStructure<isBigInt>(globalObject);
|
||||||
|
auto* constructor = getStatFSConstructor<isBigInt>(globalObject);
|
||||||
|
JSObject* newTarget = asObject(callFrame->newTarget());
|
||||||
|
|
||||||
|
if (constructor != newTarget) {
|
||||||
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||||
|
auto* functionGlobalObject = reinterpret_cast<Zig::GlobalObject*>(
|
||||||
|
// ShadowRealm functions belong to a different global object.
|
||||||
|
getFunctionRealm(lexicalGlobalObject, newTarget));
|
||||||
|
RETURN_IF_EXCEPTION(scope, {});
|
||||||
|
structure = InternalFunction::createSubclassStructure(
|
||||||
|
lexicalGlobalObject,
|
||||||
|
newTarget,
|
||||||
|
getStatFSStructure<isBigInt>(functionGlobalObject));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue type = callFrame->argument(0);
|
||||||
|
JSValue bsize = callFrame->argument(1);
|
||||||
|
JSValue blocks = callFrame->argument(2);
|
||||||
|
JSValue bfree = callFrame->argument(3);
|
||||||
|
JSValue bavail = callFrame->argument(4);
|
||||||
|
JSValue files = callFrame->argument(5);
|
||||||
|
JSValue ffree = callFrame->argument(6);
|
||||||
|
|
||||||
|
JSFinalObject* object = JSC::JSFinalObject::create(vm, structure);
|
||||||
|
object->putDirect(vm, vm.propertyNames->type, type, 0);
|
||||||
|
object->putDirect(vm, Identifier::fromString(vm, "bsize"_s), bsize, 0);
|
||||||
|
object->putDirect(vm, Identifier::fromString(vm, "blocks"_s), blocks, 0);
|
||||||
|
object->putDirect(vm, Identifier::fromString(vm, "bfree"_s), bfree, 0);
|
||||||
|
object->putDirect(vm, Identifier::fromString(vm, "bavail"_s), bavail, 0);
|
||||||
|
object->putDirect(vm, Identifier::fromString(vm, "files"_s), files, 0);
|
||||||
|
object->putDirect(vm, Identifier::fromString(vm, "ffree"_s), ffree, 0);
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSC_DEFINE_HOST_FUNCTION(constructStatFS, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame))
|
||||||
|
{
|
||||||
|
return JSValue::encode(constructJSStatFSObject<false>(lexicalGlobalObject, callFrame));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSC_DEFINE_HOST_FUNCTION(constructBigIntStatFS, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame))
|
||||||
|
{
|
||||||
|
return JSValue::encode(constructJSStatFSObject<true>(lexicalGlobalObject, callFrame));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSC_DEFINE_HOST_FUNCTION(callStatFS, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame))
|
||||||
|
{
|
||||||
|
return JSValue::encode(callJSStatFSFunction<false>(lexicalGlobalObject, callFrame));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSC_DEFINE_HOST_FUNCTION(callBigIntStatFS, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame))
|
||||||
|
{
|
||||||
|
return JSValue::encode(callJSStatFSFunction<true>(lexicalGlobalObject, callFrame));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" JSC::EncodedJSValue Bun__JSBigIntStatFSObjectConstructor(Zig::GlobalObject* globalobject)
|
||||||
|
{
|
||||||
|
return JSValue::encode(globalobject->m_JSStatFSBigIntClassStructure.constructor(globalobject));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" JSC::EncodedJSValue Bun__JSStatFSObjectConstructor(Zig::GlobalObject* globalobject)
|
||||||
|
{
|
||||||
|
return JSValue::encode(globalobject->m_JSStatFSClassStructure.constructor(globalobject));
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSStatFSPrototype::finishCreation(VM& vm)
|
||||||
|
{
|
||||||
|
Base::finishCreation(vm);
|
||||||
|
ASSERT(inherits(info()));
|
||||||
|
JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSBigIntStatFSPrototype::finishCreation(VM& vm)
|
||||||
|
{
|
||||||
|
Base::finishCreation(vm);
|
||||||
|
ASSERT(inherits(info()));
|
||||||
|
JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
|
||||||
|
}
|
||||||
|
|
||||||
|
void initJSStatFSClassStructure(JSC::LazyClassStructure::Initializer& init)
|
||||||
|
{
|
||||||
|
auto* prototype = JSStatFSPrototype::create(init.vm, init.global, JSStatFSPrototype::createStructure(init.vm, init.global, init.global->objectPrototype()));
|
||||||
|
auto* structure = createJSStatFSObjectStructure(init.vm, init.global);
|
||||||
|
auto* constructor = JSStatFSConstructor::create(init.vm, JSStatFSConstructor::createStructure(init.vm, init.global, init.global->functionPrototype()), prototype);
|
||||||
|
init.setPrototype(prototype);
|
||||||
|
init.setStructure(structure);
|
||||||
|
init.setConstructor(constructor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initJSBigIntStatFSClassStructure(JSC::LazyClassStructure::Initializer& init)
|
||||||
|
{
|
||||||
|
auto* prototype = JSBigIntStatFSPrototype::create(init.vm, init.global, JSBigIntStatFSPrototype::createStructure(init.vm, init.global, init.global->objectPrototype()));
|
||||||
|
auto* structure = createJSBigIntStatFSObjectStructure(init.vm, init.global);
|
||||||
|
auto* constructor = JSBigIntStatFSConstructor::create(init.vm, JSBigIntStatFSConstructor::createStructure(init.vm, init.global, init.global->functionPrototype()), prototype);
|
||||||
|
init.setPrototype(prototype);
|
||||||
|
init.setStructure(structure);
|
||||||
|
init.setConstructor(constructor);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Bun
|
||||||
8
src/bun.js/bindings/NodeFSStatFSBinding.h
Normal file
8
src/bun.js/bindings/NodeFSStatFSBinding.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#include "root.h"
|
||||||
|
|
||||||
|
namespace Bun {
|
||||||
|
|
||||||
|
void initJSStatFSClassStructure(JSC::LazyClassStructure::Initializer& init);
|
||||||
|
void initJSBigIntStatFSClassStructure(JSC::LazyClassStructure::Initializer& init);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -180,7 +180,8 @@
|
|||||||
#include "JavaScriptCore/RemoteInspectorServer.h"
|
#include "JavaScriptCore/RemoteInspectorServer.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "NodeFSBinding.h"
|
#include "NodeFSStatBinding.h"
|
||||||
|
#include "NodeFSStatFSBinding.h"
|
||||||
#include "NodeDirent.h"
|
#include "NodeDirent.h"
|
||||||
|
|
||||||
#if !OS(WINDOWS)
|
#if !OS(WINDOWS)
|
||||||
@@ -3016,6 +3017,16 @@ void GlobalObject::finishCreation(VM& vm)
|
|||||||
Bun::initJSBigIntStatsClassStructure(init);
|
Bun::initJSBigIntStatsClassStructure(init);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
m_JSStatFSClassStructure.initLater(
|
||||||
|
[](LazyClassStructure::Initializer& init) {
|
||||||
|
Bun::initJSStatFSClassStructure(init);
|
||||||
|
});
|
||||||
|
|
||||||
|
m_JSStatFSBigIntClassStructure.initLater(
|
||||||
|
[](LazyClassStructure::Initializer& init) {
|
||||||
|
Bun::initJSBigIntStatFSClassStructure(init);
|
||||||
|
});
|
||||||
|
|
||||||
m_memoryFootprintStructure.initLater(
|
m_memoryFootprintStructure.initLater(
|
||||||
[](const JSC::LazyProperty<JSC::JSGlobalObject, Structure>::Initializer& init) {
|
[](const JSC::LazyProperty<JSC::JSGlobalObject, Structure>::Initializer& init) {
|
||||||
init.set(
|
init.set(
|
||||||
@@ -4063,6 +4074,8 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor)
|
|||||||
thisObject->m_memoryFootprintStructure.visit(visitor);
|
thisObject->m_memoryFootprintStructure.visit(visitor);
|
||||||
thisObject->m_JSStatsClassStructure.visit(visitor);
|
thisObject->m_JSStatsClassStructure.visit(visitor);
|
||||||
thisObject->m_JSStatsBigIntClassStructure.visit(visitor);
|
thisObject->m_JSStatsBigIntClassStructure.visit(visitor);
|
||||||
|
thisObject->m_JSStatFSClassStructure.visit(visitor);
|
||||||
|
thisObject->m_JSStatFSBigIntClassStructure.visit(visitor);
|
||||||
thisObject->m_JSDirentClassStructure.visit(visitor);
|
thisObject->m_JSDirentClassStructure.visit(visitor);
|
||||||
thisObject->m_NapiClassStructure.visit(visitor);
|
thisObject->m_NapiClassStructure.visit(visitor);
|
||||||
thisObject->m_NapiExternalStructure.visit(visitor);
|
thisObject->m_NapiExternalStructure.visit(visitor);
|
||||||
|
|||||||
@@ -494,6 +494,8 @@ public:
|
|||||||
|
|
||||||
JSC::LazyClassStructure m_JSStatsClassStructure;
|
JSC::LazyClassStructure m_JSStatsClassStructure;
|
||||||
JSC::LazyClassStructure m_JSStatsBigIntClassStructure;
|
JSC::LazyClassStructure m_JSStatsBigIntClassStructure;
|
||||||
|
JSC::LazyClassStructure m_JSStatFSClassStructure;
|
||||||
|
JSC::LazyClassStructure m_JSStatFSBigIntClassStructure;
|
||||||
JSC::LazyClassStructure m_JSDirentClassStructure;
|
JSC::LazyClassStructure m_JSDirentClassStructure;
|
||||||
|
|
||||||
JSObject* cryptoObject() const { return m_cryptoObject.getInitializedOnMainThread(this); }
|
JSObject* cryptoObject() const { return m_cryptoObject.getInitializedOnMainThread(this); }
|
||||||
|
|||||||
@@ -82,7 +82,4 @@ pub const Classes = struct {
|
|||||||
pub const S3Client = JSC.WebCore.S3Client;
|
pub const S3Client = JSC.WebCore.S3Client;
|
||||||
pub const S3Stat = JSC.WebCore.S3Stat;
|
pub const S3Stat = JSC.WebCore.S3Stat;
|
||||||
pub const HTMLBundle = JSC.API.HTMLBundle;
|
pub const HTMLBundle = JSC.API.HTMLBundle;
|
||||||
|
|
||||||
pub const StatFs = JSC.Node.StatFSSmall;
|
|
||||||
pub const BigIntStatFs = JSC.Node.StatFSBig;
|
|
||||||
};
|
};
|
||||||
|
|||||||
207
src/bun.js/node/Stat.zig
Normal file
207
src/bun.js/node/Stat.zig
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
/// Stats and BigIntStats classes from node:fs
|
||||||
|
pub fn StatType(comptime big: bool) type {
|
||||||
|
return struct {
|
||||||
|
pub usingnamespace bun.New(@This());
|
||||||
|
value: bun.Stat,
|
||||||
|
|
||||||
|
const StatTimespec = if (Environment.isWindows) bun.windows.libuv.uv_timespec_t else std.posix.timespec;
|
||||||
|
const Float = if (big) i64 else f64;
|
||||||
|
|
||||||
|
inline fn toNanoseconds(ts: StatTimespec) u64 {
|
||||||
|
if (ts.sec < 0) {
|
||||||
|
return @intCast(@max(bun.timespec.nsSigned(&bun.timespec{
|
||||||
|
.sec = @intCast(ts.sec),
|
||||||
|
.nsec = @intCast(ts.nsec),
|
||||||
|
}), 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return bun.timespec.ns(&bun.timespec{
|
||||||
|
.sec = @intCast(ts.sec),
|
||||||
|
.nsec = @intCast(ts.nsec),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toTimeMS(ts: StatTimespec) Float {
|
||||||
|
// On windows, Node.js purposefully mis-interprets time values
|
||||||
|
// > On win32, time is stored in uint64_t and starts from 1601-01-01.
|
||||||
|
// > libuv calculates tv_sec and tv_nsec from it and converts to signed long,
|
||||||
|
// > which causes Y2038 overflow. On the other platforms it is safe to treat
|
||||||
|
// > negative values as pre-epoch time.
|
||||||
|
const tv_sec = if (Environment.isWindows) @as(u32, @bitCast(ts.sec)) else ts.sec;
|
||||||
|
const tv_nsec = if (Environment.isWindows) @as(u32, @bitCast(ts.nsec)) else ts.nsec;
|
||||||
|
if (big) {
|
||||||
|
const sec: i64 = tv_sec;
|
||||||
|
const nsec: i64 = tv_nsec;
|
||||||
|
return @as(i64, sec * std.time.ms_per_s) +|
|
||||||
|
@as(i64, @divTrunc(nsec, std.time.ns_per_ms));
|
||||||
|
} else {
|
||||||
|
return @floatFromInt(bun.timespec.ms(&bun.timespec{
|
||||||
|
.sec = @intCast(tv_sec),
|
||||||
|
.nsec = @intCast(tv_nsec),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toJS(this: *const @This(), globalObject: *JSC.JSGlobalObject) JSC.JSValue {
|
||||||
|
return statToJS(&this.value, globalObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getConstructor(globalObject: *JSC.JSGlobalObject) JSC.JSValue {
|
||||||
|
return if (big) Bun__JSBigIntStatsObjectConstructor(globalObject) else Bun__JSStatsObjectConstructor(globalObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clampedInt64(value: anytype) i64 {
|
||||||
|
return @intCast(@min(@max(value, 0), std.math.maxInt(i64)));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn statToJS(stat_: *const bun.Stat, globalObject: *JSC.JSGlobalObject) JSC.JSValue {
|
||||||
|
const aTime = stat_.atime();
|
||||||
|
const mTime = stat_.mtime();
|
||||||
|
const cTime = stat_.ctime();
|
||||||
|
const dev: i64 = clampedInt64(stat_.dev);
|
||||||
|
const ino: i64 = clampedInt64(stat_.ino);
|
||||||
|
const mode: i64 = clampedInt64(stat_.mode);
|
||||||
|
const nlink: i64 = clampedInt64(stat_.nlink);
|
||||||
|
const uid: i64 = clampedInt64(stat_.uid);
|
||||||
|
const gid: i64 = clampedInt64(stat_.gid);
|
||||||
|
const rdev: i64 = clampedInt64(stat_.rdev);
|
||||||
|
const size: i64 = clampedInt64(stat_.size);
|
||||||
|
const blksize: i64 = clampedInt64(stat_.blksize);
|
||||||
|
const blocks: i64 = clampedInt64(stat_.blocks);
|
||||||
|
const atime_ms: Float = toTimeMS(aTime);
|
||||||
|
const mtime_ms: Float = toTimeMS(mTime);
|
||||||
|
const ctime_ms: Float = toTimeMS(cTime);
|
||||||
|
const atime_ns: u64 = if (big) toNanoseconds(aTime) else 0;
|
||||||
|
const mtime_ns: u64 = if (big) toNanoseconds(mTime) else 0;
|
||||||
|
const ctime_ns: u64 = if (big) toNanoseconds(cTime) else 0;
|
||||||
|
const birthtime_ms: Float = if (Environment.isLinux) 0 else toTimeMS(stat_.birthtime());
|
||||||
|
const birthtime_ns: u64 = if (big and !Environment.isLinux) toNanoseconds(stat_.birthtime()) else 0;
|
||||||
|
|
||||||
|
if (big) {
|
||||||
|
return Bun__createJSBigIntStatsObject(
|
||||||
|
globalObject,
|
||||||
|
dev,
|
||||||
|
ino,
|
||||||
|
mode,
|
||||||
|
nlink,
|
||||||
|
uid,
|
||||||
|
gid,
|
||||||
|
rdev,
|
||||||
|
size,
|
||||||
|
blksize,
|
||||||
|
blocks,
|
||||||
|
atime_ms,
|
||||||
|
mtime_ms,
|
||||||
|
ctime_ms,
|
||||||
|
birthtime_ms,
|
||||||
|
atime_ns,
|
||||||
|
mtime_ns,
|
||||||
|
ctime_ns,
|
||||||
|
birthtime_ns,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Bun__createJSStatsObject(
|
||||||
|
globalObject,
|
||||||
|
dev,
|
||||||
|
ino,
|
||||||
|
mode,
|
||||||
|
nlink,
|
||||||
|
uid,
|
||||||
|
gid,
|
||||||
|
rdev,
|
||||||
|
size,
|
||||||
|
blksize,
|
||||||
|
blocks,
|
||||||
|
atime_ms,
|
||||||
|
mtime_ms,
|
||||||
|
ctime_ms,
|
||||||
|
birthtime_ms,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(stat_: *const bun.Stat) @This() {
|
||||||
|
return @This(){
|
||||||
|
.value = stat_.*,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
extern fn Bun__JSBigIntStatsObjectConstructor(*JSC.JSGlobalObject) JSC.JSValue;
|
||||||
|
extern fn Bun__JSStatsObjectConstructor(*JSC.JSGlobalObject) JSC.JSValue;
|
||||||
|
|
||||||
|
extern fn Bun__createJSStatsObject(
|
||||||
|
globalObject: *JSC.JSGlobalObject,
|
||||||
|
dev: i64,
|
||||||
|
ino: i64,
|
||||||
|
mode: i64,
|
||||||
|
nlink: i64,
|
||||||
|
uid: i64,
|
||||||
|
gid: i64,
|
||||||
|
rdev: i64,
|
||||||
|
size: i64,
|
||||||
|
blksize: i64,
|
||||||
|
blocks: i64,
|
||||||
|
atimeMs: f64,
|
||||||
|
mtimeMs: f64,
|
||||||
|
ctimeMs: f64,
|
||||||
|
birthtimeMs: f64,
|
||||||
|
) JSC.JSValue;
|
||||||
|
|
||||||
|
extern fn Bun__createJSBigIntStatsObject(
|
||||||
|
globalObject: *JSC.JSGlobalObject,
|
||||||
|
dev: i64,
|
||||||
|
ino: i64,
|
||||||
|
mode: i64,
|
||||||
|
nlink: i64,
|
||||||
|
uid: i64,
|
||||||
|
gid: i64,
|
||||||
|
rdev: i64,
|
||||||
|
size: i64,
|
||||||
|
blksize: i64,
|
||||||
|
blocks: i64,
|
||||||
|
atimeMs: i64,
|
||||||
|
mtimeMs: i64,
|
||||||
|
ctimeMs: i64,
|
||||||
|
birthtimeMs: i64,
|
||||||
|
atimeNs: u64,
|
||||||
|
mtimeNs: u64,
|
||||||
|
ctimeNs: u64,
|
||||||
|
birthtimeNs: u64,
|
||||||
|
) JSC.JSValue;
|
||||||
|
|
||||||
|
pub const StatsSmall = StatType(false);
|
||||||
|
pub const StatsBig = StatType(true);
|
||||||
|
|
||||||
|
/// Union between `Stats` and `BigIntStats` where the type can be decided at runtime
|
||||||
|
pub const Stats = union(enum) {
|
||||||
|
big: StatsBig,
|
||||||
|
small: StatsSmall,
|
||||||
|
|
||||||
|
pub inline fn init(stat_: *const bun.Stat, big: bool) Stats {
|
||||||
|
if (big) {
|
||||||
|
return .{ .big = StatsBig.init(stat_) };
|
||||||
|
} else {
|
||||||
|
return .{ .small = StatsSmall.init(stat_) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toJSNewlyCreated(this: *const Stats, globalObject: *JSC.JSGlobalObject) JSC.JSValue {
|
||||||
|
return switch (this.*) {
|
||||||
|
.big => this.big.toJS(globalObject),
|
||||||
|
.small => this.small.toJS(globalObject),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn toJS(this: *Stats, globalObject: *JSC.JSGlobalObject) JSC.JSValue {
|
||||||
|
_ = this;
|
||||||
|
_ = globalObject;
|
||||||
|
|
||||||
|
@compileError("Only use Stats.toJSNewlyCreated() or Stats.toJS() directly on a StatsBig or StatsSmall");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const bun = @import("root").bun;
|
||||||
|
const JSC = bun.JSC;
|
||||||
|
const Environment = bun.Environment;
|
||||||
|
const std = @import("std");
|
||||||
142
src/bun.js/node/StatFS.zig
Normal file
142
src/bun.js/node/StatFS.zig
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
/// StatFS and BigIntStatFS classes from node:fs
|
||||||
|
pub fn StatFSType(comptime big: bool) type {
|
||||||
|
const Int = if (big) i64 else i32;
|
||||||
|
|
||||||
|
return struct {
|
||||||
|
|
||||||
|
// Common fields between Linux and macOS
|
||||||
|
_fstype: Int,
|
||||||
|
_bsize: Int,
|
||||||
|
_blocks: Int,
|
||||||
|
_bfree: Int,
|
||||||
|
_bavail: Int,
|
||||||
|
_files: Int,
|
||||||
|
_ffree: Int,
|
||||||
|
|
||||||
|
const This = @This();
|
||||||
|
|
||||||
|
pub fn toJS(this: *const This, globalObject: *JSC.JSGlobalObject) JSC.JSValue {
|
||||||
|
return statfsToJS(this, globalObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn statfsToJS(this: *const This, globalObject: *JSC.JSGlobalObject) JSC.JSValue {
|
||||||
|
if (big) {
|
||||||
|
return Bun__createJSBigIntStatFSObject(
|
||||||
|
globalObject,
|
||||||
|
this._fstype,
|
||||||
|
this._bsize,
|
||||||
|
this._blocks,
|
||||||
|
this._bfree,
|
||||||
|
this._bavail,
|
||||||
|
this._files,
|
||||||
|
this._ffree,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Bun__createJSStatFSObject(
|
||||||
|
globalObject,
|
||||||
|
this._fstype,
|
||||||
|
this._bsize,
|
||||||
|
this._blocks,
|
||||||
|
this._bfree,
|
||||||
|
this._bavail,
|
||||||
|
this._files,
|
||||||
|
this._ffree,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(statfs_: *const bun.StatFS) This {
|
||||||
|
const fstype_, const bsize_, const blocks_, const bfree_, const bavail_, const files_, const ffree_ = switch (comptime Environment.os) {
|
||||||
|
.linux, .mac => .{
|
||||||
|
statfs_.f_type,
|
||||||
|
statfs_.f_bsize,
|
||||||
|
statfs_.f_blocks,
|
||||||
|
statfs_.f_bfree,
|
||||||
|
statfs_.f_bavail,
|
||||||
|
statfs_.f_files,
|
||||||
|
statfs_.f_ffree,
|
||||||
|
},
|
||||||
|
.windows => .{
|
||||||
|
statfs_.f_type,
|
||||||
|
statfs_.f_bsize,
|
||||||
|
statfs_.f_blocks,
|
||||||
|
statfs_.f_bfree,
|
||||||
|
statfs_.f_bavail,
|
||||||
|
statfs_.f_files,
|
||||||
|
statfs_.f_ffree,
|
||||||
|
},
|
||||||
|
else => @compileError("Unsupported OS"),
|
||||||
|
};
|
||||||
|
return .{
|
||||||
|
._fstype = @truncate(@as(i64, @intCast(fstype_))),
|
||||||
|
._bsize = @truncate(@as(i64, @intCast(bsize_))),
|
||||||
|
._blocks = @truncate(@as(i64, @intCast(blocks_))),
|
||||||
|
._bfree = @truncate(@as(i64, @intCast(bfree_))),
|
||||||
|
._bavail = @truncate(@as(i64, @intCast(bavail_))),
|
||||||
|
._files = @truncate(@as(i64, @intCast(files_))),
|
||||||
|
._ffree = @truncate(@as(i64, @intCast(ffree_))),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
extern fn Bun__JSBigIntStatFSObjectConstructor(*JSC.JSGlobalObject) JSC.JSValue;
|
||||||
|
extern fn Bun__JSStatFSObjectConstructor(*JSC.JSGlobalObject) JSC.JSValue;
|
||||||
|
|
||||||
|
extern fn Bun__createJSStatFSObject(
|
||||||
|
globalObject: *JSC.JSGlobalObject,
|
||||||
|
fstype: i64,
|
||||||
|
bsize: i64,
|
||||||
|
blocks: i64,
|
||||||
|
bfree: i64,
|
||||||
|
bavail: i64,
|
||||||
|
files: i64,
|
||||||
|
ffree: i64,
|
||||||
|
) JSC.JSValue;
|
||||||
|
|
||||||
|
extern fn Bun__createJSBigIntStatFSObject(
|
||||||
|
globalObject: *JSC.JSGlobalObject,
|
||||||
|
fstype: i64,
|
||||||
|
bsize: i64,
|
||||||
|
blocks: i64,
|
||||||
|
bfree: i64,
|
||||||
|
bavail: i64,
|
||||||
|
files: i64,
|
||||||
|
ffree: i64,
|
||||||
|
) JSC.JSValue;
|
||||||
|
|
||||||
|
pub const StatFSSmall = StatFSType(false);
|
||||||
|
pub const StatFSBig = StatFSType(true);
|
||||||
|
|
||||||
|
/// Union between `Stats` and `BigIntStats` where the type can be decided at runtime
|
||||||
|
pub const StatFS = union(enum) {
|
||||||
|
big: StatFSBig,
|
||||||
|
small: StatFSSmall,
|
||||||
|
|
||||||
|
pub inline fn init(stat_: *const bun.StatFS, big: bool) StatFS {
|
||||||
|
if (big) {
|
||||||
|
return .{ .big = StatFSBig.init(stat_) };
|
||||||
|
} else {
|
||||||
|
return .{ .small = StatFSSmall.init(stat_) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toJSNewlyCreated(this: *const StatFS, globalObject: *JSC.JSGlobalObject) JSC.JSValue {
|
||||||
|
return switch (this.*) {
|
||||||
|
.big => |*big| big.toJS(globalObject),
|
||||||
|
.small => |*small| small.toJS(globalObject),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn toJS(this: *StatFS, globalObject: *JSC.JSGlobalObject) JSC.JSValue {
|
||||||
|
_ = this;
|
||||||
|
_ = globalObject;
|
||||||
|
|
||||||
|
@compileError("Only use Stats.toJSNewlyCreated() or Stats.toJS() directly on a StatsBig or StatsSmall");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const bun = @import("root").bun;
|
||||||
|
const JSC = bun.JSC;
|
||||||
|
const Environment = bun.Environment;
|
||||||
|
const std = @import("std");
|
||||||
@@ -314,72 +314,4 @@ export default [
|
|||||||
Stats: { getter: "getStats" },
|
Stats: { getter: "getStats" },
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
define({
|
|
||||||
name: "StatFs",
|
|
||||||
construct: true,
|
|
||||||
finalize: true,
|
|
||||||
klass: {},
|
|
||||||
JSType: "0b11101110",
|
|
||||||
|
|
||||||
supportsObjectCreate: true,
|
|
||||||
|
|
||||||
// TODO: make these own properties to pass test-fs-statfs.js
|
|
||||||
proto: {
|
|
||||||
type: {
|
|
||||||
getter: "fstype",
|
|
||||||
},
|
|
||||||
bsize: {
|
|
||||||
getter: "bsize",
|
|
||||||
},
|
|
||||||
blocks: {
|
|
||||||
getter: "blocks",
|
|
||||||
},
|
|
||||||
bfree: {
|
|
||||||
getter: "bfree",
|
|
||||||
},
|
|
||||||
bavail: {
|
|
||||||
getter: "bavail",
|
|
||||||
},
|
|
||||||
files: {
|
|
||||||
getter: "files",
|
|
||||||
},
|
|
||||||
ffree: {
|
|
||||||
getter: "ffree",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
define({
|
|
||||||
name: "BigIntStatFs",
|
|
||||||
construct: true,
|
|
||||||
finalize: true,
|
|
||||||
klass: {},
|
|
||||||
JSType: "0b11101110",
|
|
||||||
|
|
||||||
supportsObjectCreate: true,
|
|
||||||
|
|
||||||
// TODO: make these own properties to pass test-fs-statfs.js
|
|
||||||
proto: {
|
|
||||||
type: {
|
|
||||||
getter: "fstype",
|
|
||||||
},
|
|
||||||
bsize: {
|
|
||||||
getter: "bsize",
|
|
||||||
},
|
|
||||||
blocks: {
|
|
||||||
getter: "blocks",
|
|
||||||
},
|
|
||||||
bfree: {
|
|
||||||
getter: "bfree",
|
|
||||||
},
|
|
||||||
bavail: {
|
|
||||||
getter: "bavail",
|
|
||||||
},
|
|
||||||
files: {
|
|
||||||
getter: "files",
|
|
||||||
},
|
|
||||||
ffree: {
|
|
||||||
getter: "ffree",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -3850,7 +3850,7 @@ pub const NodeFS = struct {
|
|||||||
|
|
||||||
pub fn fstat(_: *NodeFS, args: Arguments.Fstat, _: Flavor) Maybe(Return.Fstat) {
|
pub fn fstat(_: *NodeFS, args: Arguments.Fstat, _: Flavor) Maybe(Return.Fstat) {
|
||||||
return switch (Syscall.fstat(args.fd)) {
|
return switch (Syscall.fstat(args.fd)) {
|
||||||
.result => |result| .{ .result = .init(result, args.big_int) },
|
.result => |*result| .{ .result = .init(result, args.big_int) },
|
||||||
.err => |err| .{ .err = err },
|
.err => |err| .{ .err = err },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -3927,7 +3927,7 @@ pub const NodeFS = struct {
|
|||||||
|
|
||||||
pub fn lstat(this: *NodeFS, args: Arguments.Lstat, _: Flavor) Maybe(Return.Lstat) {
|
pub fn lstat(this: *NodeFS, args: Arguments.Lstat, _: Flavor) Maybe(Return.Lstat) {
|
||||||
return switch (Syscall.lstat(args.path.sliceZ(&this.sync_error_buf))) {
|
return switch (Syscall.lstat(args.path.sliceZ(&this.sync_error_buf))) {
|
||||||
.result => |result| Maybe(Return.Lstat){ .result = .{ .stats = .init(result, args.big_int) } },
|
.result => |*result| Maybe(Return.Lstat){ .result = .{ .stats = .init(result, args.big_int) } },
|
||||||
.err => |err| brk: {
|
.err => |err| brk: {
|
||||||
if (!args.throw_if_no_entry and err.getErrno() == .NOENT) {
|
if (!args.throw_if_no_entry and err.getErrno() == .NOENT) {
|
||||||
return Maybe(Return.Lstat){ .result = .{ .not_found = {} } };
|
return Maybe(Return.Lstat){ .result = .{ .not_found = {} } };
|
||||||
@@ -4234,7 +4234,8 @@ pub const NodeFS = struct {
|
|||||||
.from_libuv = true,
|
.from_libuv = true,
|
||||||
} };
|
} };
|
||||||
}
|
}
|
||||||
return Maybe(Return.StatFS).initResult(Return.StatFS.init(req.ptrAs(*align(1) bun.StatFS).*, args.big_int));
|
const statfs_ = req.ptrAs(*align(1) bun.StatFS).*;
|
||||||
|
return Maybe(Return.StatFS).initResult(Return.StatFS.init(&statfs_, args.big_int));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn openDir(_: *NodeFS, _: Arguments.OpenDir, _: Flavor) Maybe(Return.OpenDir) {
|
pub fn openDir(_: *NodeFS, _: Arguments.OpenDir, _: Flavor) Maybe(Return.OpenDir) {
|
||||||
@@ -5748,7 +5749,7 @@ pub const NodeFS = struct {
|
|||||||
|
|
||||||
pub fn statfs(this: *NodeFS, args: Arguments.StatFS, _: Flavor) Maybe(Return.StatFS) {
|
pub fn statfs(this: *NodeFS, args: Arguments.StatFS, _: Flavor) Maybe(Return.StatFS) {
|
||||||
return switch (Syscall.statfs(args.path.sliceZ(&this.sync_error_buf))) {
|
return switch (Syscall.statfs(args.path.sliceZ(&this.sync_error_buf))) {
|
||||||
.result => |result| Maybe(Return.StatFS){ .result = Return.StatFS.init(result, args.big_int) },
|
.result => |*result| Maybe(Return.StatFS){ .result = Return.StatFS.init(result, args.big_int) },
|
||||||
.err => |err| Maybe(Return.StatFS){ .err = err },
|
.err => |err| Maybe(Return.StatFS){ .err = err },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -5756,13 +5757,13 @@ pub const NodeFS = struct {
|
|||||||
pub fn stat(this: *NodeFS, args: Arguments.Stat, _: Flavor) Maybe(Return.Stat) {
|
pub fn stat(this: *NodeFS, args: Arguments.Stat, _: Flavor) Maybe(Return.Stat) {
|
||||||
const path = args.path.sliceZ(&this.sync_error_buf);
|
const path = args.path.sliceZ(&this.sync_error_buf);
|
||||||
if (bun.StandaloneModuleGraph.get()) |graph| {
|
if (bun.StandaloneModuleGraph.get()) |graph| {
|
||||||
if (graph.stat(path)) |result| {
|
if (graph.stat(path)) |*result| {
|
||||||
return .{ .result = .{ .stats = .init(result, args.big_int) } };
|
return .{ .result = .{ .stats = .init(result, args.big_int) } };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return switch (Syscall.stat(path)) {
|
return switch (Syscall.stat(path)) {
|
||||||
.result => |result| .{
|
.result => |*result| .{
|
||||||
.result = .{ .stats = .init(result, args.big_int) },
|
.result = .{ .stats = .init(result, args.big_int) },
|
||||||
},
|
},
|
||||||
.err => |err| brk: {
|
.err => |err| brk: {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ const StatsBig = bun.JSC.Node.StatsBig;
|
|||||||
|
|
||||||
const log = bun.Output.scoped(.StatWatcher, false);
|
const log = bun.Output.scoped(.StatWatcher, false);
|
||||||
|
|
||||||
fn statToJSStats(globalThis: *JSC.JSGlobalObject, stats: bun.Stat, bigint: bool) JSC.JSValue {
|
fn statToJSStats(globalThis: *JSC.JSGlobalObject, stats: *const bun.Stat, bigint: bool) JSC.JSValue {
|
||||||
if (bigint) {
|
if (bigint) {
|
||||||
return StatsBig.init(stats).toJS(globalThis);
|
return StatsBig.init(stats).toJS(globalThis);
|
||||||
} else {
|
} else {
|
||||||
@@ -376,7 +376,7 @@ pub const StatWatcher = struct {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const jsvalue = statToJSStats(this.globalThis, this.last_stat, this.bigint);
|
const jsvalue = statToJSStats(this.globalThis, &this.last_stat, this.bigint);
|
||||||
this.last_jsvalue = JSC.Strong.create(jsvalue, this.globalThis);
|
this.last_jsvalue = JSC.Strong.create(jsvalue, this.globalThis);
|
||||||
|
|
||||||
const vm = this.globalThis.bunVM();
|
const vm = this.globalThis.bunVM();
|
||||||
@@ -389,7 +389,7 @@ pub const StatWatcher = struct {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const jsvalue = statToJSStats(this.globalThis, this.last_stat, this.bigint);
|
const jsvalue = statToJSStats(this.globalThis, &this.last_stat, this.bigint);
|
||||||
this.last_jsvalue = JSC.Strong.create(jsvalue, this.globalThis);
|
this.last_jsvalue = JSC.Strong.create(jsvalue, this.globalThis);
|
||||||
|
|
||||||
const vm = this.globalThis.bunVM();
|
const vm = this.globalThis.bunVM();
|
||||||
@@ -428,7 +428,7 @@ pub const StatWatcher = struct {
|
|||||||
/// After a restat found the file changed, this calls the listener function.
|
/// After a restat found the file changed, this calls the listener function.
|
||||||
pub fn swapAndCallListenerOnMainThread(this: *StatWatcher) void {
|
pub fn swapAndCallListenerOnMainThread(this: *StatWatcher) void {
|
||||||
const prev_jsvalue = this.last_jsvalue.swap();
|
const prev_jsvalue = this.last_jsvalue.swap();
|
||||||
const current_jsvalue = statToJSStats(this.globalThis, this.last_stat, this.bigint);
|
const current_jsvalue = statToJSStats(this.globalThis, &this.last_stat, this.bigint);
|
||||||
this.last_jsvalue.set(this.globalThis, current_jsvalue);
|
this.last_jsvalue.set(this.globalThis, current_jsvalue);
|
||||||
|
|
||||||
_ = StatWatcher.listenerGetCached(this.js_this).?.call(
|
_ = StatWatcher.listenerGetCached(this.js_this).?.call(
|
||||||
|
|||||||
@@ -1604,209 +1604,6 @@ pub const FileSystemFlags = enum(c_int) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Stats and BigIntStats classes from node:fs
|
|
||||||
pub fn StatType(comptime big: bool) type {
|
|
||||||
return struct {
|
|
||||||
pub usingnamespace bun.New(@This());
|
|
||||||
value: bun.Stat,
|
|
||||||
|
|
||||||
const StatTimespec = if (Environment.isWindows) bun.windows.libuv.uv_timespec_t else std.posix.timespec;
|
|
||||||
const Float = if (big) i64 else f64;
|
|
||||||
|
|
||||||
inline fn toNanoseconds(ts: StatTimespec) u64 {
|
|
||||||
if (ts.sec < 0) {
|
|
||||||
return @intCast(@max(bun.timespec.nsSigned(&bun.timespec{
|
|
||||||
.sec = @intCast(ts.sec),
|
|
||||||
.nsec = @intCast(ts.nsec),
|
|
||||||
}), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
return bun.timespec.ns(&bun.timespec{
|
|
||||||
.sec = @intCast(ts.sec),
|
|
||||||
.nsec = @intCast(ts.nsec),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn toTimeMS(ts: StatTimespec) Float {
|
|
||||||
// On windows, Node.js purposefully mis-interprets time values
|
|
||||||
// > On win32, time is stored in uint64_t and starts from 1601-01-01.
|
|
||||||
// > libuv calculates tv_sec and tv_nsec from it and converts to signed long,
|
|
||||||
// > which causes Y2038 overflow. On the other platforms it is safe to treat
|
|
||||||
// > negative values as pre-epoch time.
|
|
||||||
const tv_sec = if (Environment.isWindows) @as(u32, @bitCast(ts.sec)) else ts.sec;
|
|
||||||
const tv_nsec = if (Environment.isWindows) @as(u32, @bitCast(ts.nsec)) else ts.nsec;
|
|
||||||
if (big) {
|
|
||||||
const sec: i64 = tv_sec;
|
|
||||||
const nsec: i64 = tv_nsec;
|
|
||||||
return @as(i64, sec * std.time.ms_per_s) +|
|
|
||||||
@as(i64, @divTrunc(nsec, std.time.ns_per_ms));
|
|
||||||
} else {
|
|
||||||
return @floatFromInt(bun.timespec.ms(&bun.timespec{
|
|
||||||
.sec = @intCast(tv_sec),
|
|
||||||
.nsec = @intCast(tv_nsec),
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn toJS(this: *const @This(), globalObject: *JSC.JSGlobalObject) JSC.JSValue {
|
|
||||||
return statToJS(&this.value, globalObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn getConstructor(globalObject: *JSC.JSGlobalObject) JSC.JSValue {
|
|
||||||
return if (big) Bun__JSBigIntStatsObjectConstructor(globalObject) else Bun__JSStatsObjectConstructor(globalObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clampedInt64(value: anytype) i64 {
|
|
||||||
return @intCast(@min(@max(value, 0), std.math.maxInt(i64)));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn statToJS(stat_: *const bun.Stat, globalObject: *JSC.JSGlobalObject) JSC.JSValue {
|
|
||||||
const aTime = stat_.atime();
|
|
||||||
const mTime = stat_.mtime();
|
|
||||||
const cTime = stat_.ctime();
|
|
||||||
const dev: i64 = clampedInt64(stat_.dev);
|
|
||||||
const ino: i64 = clampedInt64(stat_.ino);
|
|
||||||
const mode: i64 = clampedInt64(stat_.mode);
|
|
||||||
const nlink: i64 = clampedInt64(stat_.nlink);
|
|
||||||
const uid: i64 = clampedInt64(stat_.uid);
|
|
||||||
const gid: i64 = clampedInt64(stat_.gid);
|
|
||||||
const rdev: i64 = clampedInt64(stat_.rdev);
|
|
||||||
const size: i64 = clampedInt64(stat_.size);
|
|
||||||
const blksize: i64 = clampedInt64(stat_.blksize);
|
|
||||||
const blocks: i64 = clampedInt64(stat_.blocks);
|
|
||||||
const atime_ms: Float = toTimeMS(aTime);
|
|
||||||
const mtime_ms: Float = toTimeMS(mTime);
|
|
||||||
const ctime_ms: Float = toTimeMS(cTime);
|
|
||||||
const atime_ns: u64 = if (big) toNanoseconds(aTime) else 0;
|
|
||||||
const mtime_ns: u64 = if (big) toNanoseconds(mTime) else 0;
|
|
||||||
const ctime_ns: u64 = if (big) toNanoseconds(cTime) else 0;
|
|
||||||
const birthtime_ms: Float = if (Environment.isLinux) 0 else toTimeMS(stat_.birthtime());
|
|
||||||
const birthtime_ns: u64 = if (big and !Environment.isLinux) toNanoseconds(stat_.birthtime()) else 0;
|
|
||||||
|
|
||||||
if (big) {
|
|
||||||
return Bun__createJSBigIntStatsObject(
|
|
||||||
globalObject,
|
|
||||||
dev,
|
|
||||||
ino,
|
|
||||||
mode,
|
|
||||||
nlink,
|
|
||||||
uid,
|
|
||||||
gid,
|
|
||||||
rdev,
|
|
||||||
size,
|
|
||||||
blksize,
|
|
||||||
blocks,
|
|
||||||
atime_ms,
|
|
||||||
mtime_ms,
|
|
||||||
ctime_ms,
|
|
||||||
birthtime_ms,
|
|
||||||
atime_ns,
|
|
||||||
mtime_ns,
|
|
||||||
ctime_ns,
|
|
||||||
birthtime_ns,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Bun__createJSStatsObject(
|
|
||||||
globalObject,
|
|
||||||
dev,
|
|
||||||
ino,
|
|
||||||
mode,
|
|
||||||
nlink,
|
|
||||||
uid,
|
|
||||||
gid,
|
|
||||||
rdev,
|
|
||||||
size,
|
|
||||||
blksize,
|
|
||||||
blocks,
|
|
||||||
atime_ms,
|
|
||||||
mtime_ms,
|
|
||||||
ctime_ms,
|
|
||||||
birthtime_ms,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init(stat_: bun.Stat) @This() {
|
|
||||||
return @This(){
|
|
||||||
.value = stat_,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
extern fn Bun__JSBigIntStatsObjectConstructor(*JSC.JSGlobalObject) JSC.JSValue;
|
|
||||||
extern fn Bun__JSStatsObjectConstructor(*JSC.JSGlobalObject) JSC.JSValue;
|
|
||||||
|
|
||||||
extern fn Bun__createJSStatsObject(
|
|
||||||
globalObject: *JSC.JSGlobalObject,
|
|
||||||
dev: i64,
|
|
||||||
ino: i64,
|
|
||||||
mode: i64,
|
|
||||||
nlink: i64,
|
|
||||||
uid: i64,
|
|
||||||
gid: i64,
|
|
||||||
rdev: i64,
|
|
||||||
size: i64,
|
|
||||||
blksize: i64,
|
|
||||||
blocks: i64,
|
|
||||||
atimeMs: f64,
|
|
||||||
mtimeMs: f64,
|
|
||||||
ctimeMs: f64,
|
|
||||||
birthtimeMs: f64,
|
|
||||||
) JSC.JSValue;
|
|
||||||
|
|
||||||
extern fn Bun__createJSBigIntStatsObject(
|
|
||||||
globalObject: *JSC.JSGlobalObject,
|
|
||||||
dev: i64,
|
|
||||||
ino: i64,
|
|
||||||
mode: i64,
|
|
||||||
nlink: i64,
|
|
||||||
uid: i64,
|
|
||||||
gid: i64,
|
|
||||||
rdev: i64,
|
|
||||||
size: i64,
|
|
||||||
blksize: i64,
|
|
||||||
blocks: i64,
|
|
||||||
atimeMs: i64,
|
|
||||||
mtimeMs: i64,
|
|
||||||
ctimeMs: i64,
|
|
||||||
birthtimeMs: i64,
|
|
||||||
atimeNs: u64,
|
|
||||||
mtimeNs: u64,
|
|
||||||
ctimeNs: u64,
|
|
||||||
birthtimeNs: u64,
|
|
||||||
) JSC.JSValue;
|
|
||||||
|
|
||||||
pub const StatsSmall = StatType(false);
|
|
||||||
pub const StatsBig = StatType(true);
|
|
||||||
|
|
||||||
/// Union between `Stats` and `BigIntStats` where the type can be decided at runtime
|
|
||||||
pub const Stats = union(enum) {
|
|
||||||
big: StatsBig,
|
|
||||||
small: StatsSmall,
|
|
||||||
|
|
||||||
pub inline fn init(stat_: bun.Stat, big: bool) Stats {
|
|
||||||
if (big) {
|
|
||||||
return .{ .big = StatsBig.init(stat_) };
|
|
||||||
} else {
|
|
||||||
return .{ .small = StatsSmall.init(stat_) };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn toJSNewlyCreated(this: *const Stats, globalObject: *JSC.JSGlobalObject) JSC.JSValue {
|
|
||||||
return switch (this.*) {
|
|
||||||
.big => this.big.toJS(globalObject),
|
|
||||||
.small => this.small.toJS(globalObject),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub inline fn toJS(this: *Stats, globalObject: *JSC.JSGlobalObject) JSC.JSValue {
|
|
||||||
_ = this;
|
|
||||||
_ = globalObject;
|
|
||||||
|
|
||||||
@compileError("Only use Stats.toJSNewlyCreated() or Stats.toJS() directly on a StatsBig or StatsSmall");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A class representing a directory stream.
|
/// A class representing a directory stream.
|
||||||
///
|
///
|
||||||
/// Created by {@link opendir}, {@link opendirSync}, or `fsPromises.opendir()`.
|
/// Created by {@link opendir}, {@link opendirSync}, or `fsPromises.opendir()`.
|
||||||
@@ -2185,142 +1982,15 @@ comptime {
|
|||||||
std.testing.refAllDecls(Process);
|
std.testing.refAllDecls(Process);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// StatFS and BigIntStatFS classes from node:fs
|
|
||||||
pub fn StatFSType(comptime big: bool) type {
|
|
||||||
const Int = if (big) i64 else i32;
|
|
||||||
|
|
||||||
return extern struct {
|
|
||||||
pub usingnamespace if (big) JSC.Codegen.JSBigIntStatFs else JSC.Codegen.JSStatFs;
|
|
||||||
pub usingnamespace bun.New(@This());
|
|
||||||
|
|
||||||
// Common fields between Linux and macOS
|
|
||||||
_fstype: Int,
|
|
||||||
_bsize: Int,
|
|
||||||
_blocks: Int,
|
|
||||||
_bfree: Int,
|
|
||||||
_bavail: Int,
|
|
||||||
_files: Int,
|
|
||||||
_ffree: Int,
|
|
||||||
|
|
||||||
const This = @This();
|
|
||||||
|
|
||||||
const PropertyGetter = fn (this: *This, globalObject: *JSC.JSGlobalObject) JSC.JSValue;
|
|
||||||
|
|
||||||
fn getter(comptime field: std.meta.FieldEnum(This)) PropertyGetter {
|
|
||||||
return struct {
|
|
||||||
pub fn callback(this: *This, globalObject: *JSC.JSGlobalObject) JSC.JSValue {
|
|
||||||
const value = @field(this, @tagName(field));
|
|
||||||
const Type = @TypeOf(value);
|
|
||||||
if (comptime big and @typeInfo(Type) == .int) {
|
|
||||||
return JSC.JSValue.fromInt64NoTruncate(globalObject, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = JSC.JSValue.jsDoubleNumber(@as(f64, @floatFromInt(value)));
|
|
||||||
if (Environment.isDebug) {
|
|
||||||
bun.assert_eql(result.asNumber(), @as(f64, @floatFromInt(value)));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}.callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fstype = getter(._fstype);
|
|
||||||
pub const bsize = getter(._bsize);
|
|
||||||
pub const blocks = getter(._blocks);
|
|
||||||
pub const bfree = getter(._bfree);
|
|
||||||
pub const bavail = getter(._bavail);
|
|
||||||
pub const files = getter(._files);
|
|
||||||
pub const ffree = getter(._ffree);
|
|
||||||
|
|
||||||
pub fn finalize(this: *This) void {
|
|
||||||
this.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init(statfs_: bun.StatFS) This {
|
|
||||||
const fstype_, const bsize_, const blocks_, const bfree_, const bavail_, const files_, const ffree_ = switch (comptime Environment.os) {
|
|
||||||
.linux, .mac => .{
|
|
||||||
statfs_.f_type,
|
|
||||||
statfs_.f_bsize,
|
|
||||||
statfs_.f_blocks,
|
|
||||||
statfs_.f_bfree,
|
|
||||||
statfs_.f_bavail,
|
|
||||||
statfs_.f_files,
|
|
||||||
statfs_.f_ffree,
|
|
||||||
},
|
|
||||||
.windows => .{
|
|
||||||
statfs_.f_type,
|
|
||||||
statfs_.f_bsize,
|
|
||||||
statfs_.f_blocks,
|
|
||||||
statfs_.f_bfree,
|
|
||||||
statfs_.f_bavail,
|
|
||||||
statfs_.f_files,
|
|
||||||
statfs_.f_ffree,
|
|
||||||
},
|
|
||||||
else => @compileError("Unsupported OS"),
|
|
||||||
};
|
|
||||||
return .{
|
|
||||||
._fstype = @truncate(@as(i64, @intCast(fstype_))),
|
|
||||||
._bsize = @truncate(@as(i64, @intCast(bsize_))),
|
|
||||||
._blocks = @truncate(@as(i64, @intCast(blocks_))),
|
|
||||||
._bfree = @truncate(@as(i64, @intCast(bfree_))),
|
|
||||||
._bavail = @truncate(@as(i64, @intCast(bavail_))),
|
|
||||||
._files = @truncate(@as(i64, @intCast(files_))),
|
|
||||||
._ffree = @truncate(@as(i64, @intCast(ffree_))),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn constructor(globalObject: *JSC.JSGlobalObject, callFrame: *JSC.CallFrame) bun.JSError!*This {
|
|
||||||
if (big) {
|
|
||||||
return globalObject.throwInvalidArguments("BigIntStatFS is not a constructor", .{});
|
|
||||||
}
|
|
||||||
|
|
||||||
var args = callFrame.arguments();
|
|
||||||
|
|
||||||
const this = This.new(.{
|
|
||||||
._fstype = if (args.len > 0 and args[0].isNumber()) args[0].toInt32() else 0,
|
|
||||||
._bsize = if (args.len > 1 and args[1].isNumber()) args[1].toInt32() else 0,
|
|
||||||
._blocks = if (args.len > 2 and args[2].isNumber()) args[2].toInt32() else 0,
|
|
||||||
._bfree = if (args.len > 3 and args[3].isNumber()) args[3].toInt32() else 0,
|
|
||||||
._bavail = if (args.len > 4 and args[4].isNumber()) args[4].toInt32() else 0,
|
|
||||||
._files = if (args.len > 5 and args[5].isNumber()) args[5].toInt32() else 0,
|
|
||||||
._ffree = if (args.len > 6 and args[6].isNumber()) args[6].toInt32() else 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const StatFSSmall = StatFSType(false);
|
|
||||||
pub const StatFSBig = StatFSType(true);
|
|
||||||
|
|
||||||
/// Union between `Stats` and `BigIntStats` where the type can be decided at runtime
|
|
||||||
pub const StatFS = union(enum) {
|
|
||||||
big: StatFSBig,
|
|
||||||
small: StatFSSmall,
|
|
||||||
|
|
||||||
pub inline fn init(stat_: bun.StatFS, big: bool) StatFS {
|
|
||||||
if (big) {
|
|
||||||
return .{ .big = StatFSBig.init(stat_) };
|
|
||||||
} else {
|
|
||||||
return .{ .small = StatFSSmall.init(stat_) };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn toJSNewlyCreated(this: *const StatFS, globalObject: *JSC.JSGlobalObject) JSC.JSValue {
|
|
||||||
return switch (this.*) {
|
|
||||||
.big => StatFSBig.new(this.big).toJS(globalObject),
|
|
||||||
.small => StatFSSmall.new(this.small).toJS(globalObject),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub inline fn toJS(this: *StatFS, globalObject: *JSC.JSGlobalObject) JSC.JSValue {
|
|
||||||
_ = this;
|
|
||||||
_ = globalObject;
|
|
||||||
|
|
||||||
@compileError("Only use Stats.toJSNewlyCreated() or Stats.toJS() directly on a StatsBig or StatsSmall");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const uid_t = if (Environment.isPosix) std.posix.uid_t else bun.windows.libuv.uv_uid_t;
|
pub const uid_t = if (Environment.isPosix) std.posix.uid_t else bun.windows.libuv.uv_uid_t;
|
||||||
pub const gid_t = if (Environment.isPosix) std.posix.gid_t else bun.windows.libuv.uv_gid_t;
|
pub const gid_t = if (Environment.isPosix) std.posix.gid_t else bun.windows.libuv.uv_gid_t;
|
||||||
|
|
||||||
|
const stat = @import("./Stat.zig");
|
||||||
|
pub const Stats = stat.Stats;
|
||||||
|
pub const StatsBig = stat.StatsBig;
|
||||||
|
pub const StatsSmall = stat.StatsSmall;
|
||||||
|
|
||||||
|
const statfs = @import("./StatFS.zig");
|
||||||
|
pub const StatFSSmall = statfs.StatFSSmall;
|
||||||
|
pub const StatFSBig = statfs.StatFSBig;
|
||||||
|
pub const StatFS = statfs.StatFS;
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ const words: Record<string, { reason: string; limit?: number; regex?: boolean }>
|
|||||||
"alloc.ptr !=": { reason: "The std.mem.Allocator context pointer can be undefined, which makes this comparison undefined behavior" },
|
"alloc.ptr !=": { reason: "The std.mem.Allocator context pointer can be undefined, which makes this comparison undefined behavior" },
|
||||||
"== alloc.ptr": { reason: "The std.mem.Allocator context pointer can be undefined, which makes this comparison undefined behavior" },
|
"== alloc.ptr": { reason: "The std.mem.Allocator context pointer can be undefined, which makes this comparison undefined behavior" },
|
||||||
"!= alloc.ptr": { reason: "The std.mem.Allocator context pointer can be undefined, which makes this comparison undefined behavior" },
|
"!= alloc.ptr": { reason: "The std.mem.Allocator context pointer can be undefined, which makes this comparison undefined behavior" },
|
||||||
[String.raw`: [a-zA-Z0-9_\.\*\?\[\]\(\)]+ = undefined,`]: { reason: "Do not default a struct field to undefined", limit: 246, regex: true },
|
[String.raw`: [a-zA-Z0-9_\.\*\?\[\]\(\)]+ = undefined,`]: { reason: "Do not default a struct field to undefined", limit: 244, regex: true },
|
||||||
"usingnamespace": { reason: "This brings Bun away from incremental / faster compile times.", limit: 494 },
|
"usingnamespace": { reason: "This brings Bun away from incremental / faster compile times.", limit: 492 },
|
||||||
};
|
};
|
||||||
const words_keys = [...Object.keys(words)];
|
const words_keys = [...Object.keys(words)];
|
||||||
|
|
||||||
|
|||||||
59
test/js/node/test/parallel/test-fs-statfs.js
Normal file
59
test/js/node/test/parallel/test-fs-statfs.js
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
'use strict';
|
||||||
|
const common = require('../common');
|
||||||
|
const assert = require('node:assert');
|
||||||
|
const fs = require('node:fs');
|
||||||
|
|
||||||
|
function verifyStatFsObject(statfs, isBigint = false) {
|
||||||
|
const valueType = isBigint ? 'bigint' : 'number';
|
||||||
|
|
||||||
|
[
|
||||||
|
'type', 'bsize', 'blocks', 'bfree', 'bavail', 'files', 'ffree',
|
||||||
|
].forEach((k) => {
|
||||||
|
assert.ok(Object.hasOwn(statfs, k));
|
||||||
|
assert.strictEqual(typeof statfs[k], valueType,
|
||||||
|
`${k} should be a ${valueType}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.statfs(__filename, common.mustSucceed(function(stats) {
|
||||||
|
verifyStatFsObject(stats);
|
||||||
|
assert.strictEqual(this, undefined);
|
||||||
|
}));
|
||||||
|
|
||||||
|
fs.statfs(__filename, { bigint: true }, function(err, stats) {
|
||||||
|
assert.ifError(err);
|
||||||
|
verifyStatFsObject(stats, true);
|
||||||
|
assert.strictEqual(this, undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Synchronous
|
||||||
|
{
|
||||||
|
const statFsObj = fs.statfsSync(__filename);
|
||||||
|
verifyStatFsObject(statFsObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Synchronous Bigint
|
||||||
|
{
|
||||||
|
const statFsBigIntObj = fs.statfsSync(__filename, { bigint: true });
|
||||||
|
verifyStatFsObject(statFsBigIntObj, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[false, 1, {}, [], null, undefined].forEach((input) => {
|
||||||
|
assert.throws(
|
||||||
|
() => fs.statfs(input, common.mustNotCall()),
|
||||||
|
{
|
||||||
|
code: 'ERR_INVALID_ARG_TYPE',
|
||||||
|
name: 'TypeError'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert.throws(
|
||||||
|
() => fs.statfsSync(input),
|
||||||
|
{
|
||||||
|
code: 'ERR_INVALID_ARG_TYPE',
|
||||||
|
name: 'TypeError'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Should not throw an error
|
||||||
|
fs.statfs(__filename, undefined, common.mustCall());
|
||||||
Reference in New Issue
Block a user