Skip to content
Next Next commit
src: port initializeImportMeta to native
  • Loading branch information
aduh95 committed Apr 25, 2025
commit a1edf9c6821566330bb9ae5f5cd4e2bb6a242ddc
23 changes: 7 additions & 16 deletions lib/internal/modules/esm/initialize_import_meta.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ const {
} = primordials;

const { getOptionValue } = require('internal/options');
const { fileURLToPath } = require('internal/url');
const { dirname } = require('path');
const {
initializeImportMeta: _initializeImportMeta,
} = internalBinding('modules');
const experimentalImportMetaResolve = getOptionValue('--experimental-import-meta-resolve');

/**
Expand Down Expand Up @@ -56,20 +57,10 @@ function createImportMetaResolve(defaultParentURL, loader, allowParentURL) {
function initializeImportMeta(meta, context, loader) {
const { url } = context;

// Alphabetical
if (StringPrototypeStartsWith(url, 'file:') === true) {
// These only make sense for locally loaded modules,
// i.e. network modules are not supported.
const filePath = fileURLToPath(url);
meta.dirname = dirname(filePath);
meta.filename = filePath;
}

if (!loader || loader.allowImportMetaResolve) {
meta.resolve = createImportMetaResolve(url, loader, experimentalImportMetaResolve);
}

meta.url = url;
_initializeImportMeta(
meta, url, StringPrototypeStartsWith(url, 'file:'),
Comment thread
aduh95 marked this conversation as resolved.
Outdated
(!loader || loader.allowImportMetaResolve) && createImportMetaResolve(url, loader, experimentalImportMetaResolve),
);

return meta;
}
Expand Down
84 changes: 84 additions & 0 deletions src/node_modules.cc
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,88 @@ void GetCompileCacheEntry(const FunctionCallbackInfo<Value>& args) {
isolate, v8::Null(isolate), names.data(), values.data(), names.size()));
}

static void InitImportMetaLazyGetter(
Local<v8::Name> name, const v8::PropertyCallbackInfo<Value>& info) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: remove the v8:: qualifier and add v8::PropertyCallbackInfo to the using section at the top if it is not already there.

Isolate* isolate = info.GetIsolate();
// This getter has no JavaScript function representation and is not
// invoked in the creation context.
// When this getter is invoked in a vm context, the `Realm::GetCurrent(info)`
// returns a nullptr and. Retrieve the creation context via `this` object and
Comment thread
aduh95 marked this conversation as resolved.
Outdated
// get the creation Realm.
Local<Value> receiver_val = info.This();
if (!receiver_val->IsObject()) {
THROW_ERR_INVALID_INVOCATION(isolate);
return;
}
Local<Object> receiver = receiver_val.As<Object>();
Local<Context> context;
if (!receiver->GetCreationContext().ToLocal(&context)) {
THROW_ERR_INVALID_INVOCATION(isolate);
return;
}
Environment* env = Environment::GetCurrent(context);

node::Utf8Value url(isolate, info.Data());
auto file_url = ada::parse(url.ToStringView());
CHECK(file_url);
auto file_path = url::FileURLToPath(env, *file_url);
CHECK(file_path.has_value());
std::string_view ret_view = file_path.value();

node::Utf8Value utf8name(isolate, name);
auto plain_name = utf8name.ToStringView();
if (plain_name == "dirname") {
#ifdef _WIN32
#define PATH_SEPARATOR '\\'
#else
#define PATH_SEPARATOR '/'
#endif
auto index = ret_view.rfind(PATH_SEPARATOR);
#undef PATH_SEPARATOR
CHECK(index != std::string_view::npos);
ret_view.remove_suffix(ret_view.size() - index);
}
Local<Value> ret;
if (ToV8Value(context, ret_view, isolate).ToLocal(&ret)) {
info.GetReturnValue().Set(ret);
}
}
void InitImportMeta(const FunctionCallbackInfo<Value>& args) {
// target, url, shouldSetDirnameAndFilename, resolve
CHECK_GE(args.Length(), 4);
CHECK(args[0]->IsObject());
CHECK(args[1]->IsString());
CHECK(args[2]->IsBoolean());
CHECK(args[3]->IsFalse() || args[3]->IsFunction());

Isolate* isolate = args.GetIsolate();
Local<Context> context = isolate->GetCurrentContext();

auto>

// N.B.: Order is important to keep keys in alphabetical order.

if (args[2]->IsTrue()) {
target
->SetLazyDataProperty(context,
FIXED_ONE_BYTE_STRING(isolate, "dirname"),
InitImportMetaLazyGetter,
args[1])
.Check();
target
->SetLazyDataProperty(context,
FIXED_ONE_BYTE_STRING(isolate, "filename"),
InitImportMetaLazyGetter,
args[1])
.Check();
Comment thread
aduh95 marked this conversation as resolved.
Outdated
}

if (args[3]->IsFunction()) {
target->Set(context, FIXED_ONE_BYTE_STRING(isolate, "resolve"), args[3])
.Check();
}
target->Set(context, FIXED_ONE_BYTE_STRING(isolate, "url"), args[1]).Check();
Comment thread
aduh95 marked this conversation as resolved.
Outdated
}
void SaveCompileCacheEntry(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Context> context = isolate->GetCurrentContext();
Expand Down Expand Up @@ -627,6 +709,7 @@ void BindingData::CreatePerIsolateProperties(IsolateData* isolate_data,
SetMethod(isolate, target, "flushCompileCache", FlushCompileCache);
SetMethod(isolate, target, "getCompileCacheEntry", GetCompileCacheEntry);
SetMethod(isolate, target, "saveCompileCacheEntry", SaveCompileCacheEntry);
SetMethod(isolate, target, "initializeImportMeta", InitImportMeta);
}

void BindingData::CreatePerContextProperties(Local<Object> target,
Expand Down Expand Up @@ -682,6 +765,7 @@ void BindingData::RegisterExternalReferences(
registry->Register(FlushCompileCache);
registry->Register(GetCompileCacheEntry);
registry->Register(SaveCompileCacheEntry);
registry->Register(InitImportMeta);
}

} // namespace modules
Expand Down