@@ -30,6 +30,7 @@ using v8::NewStringType;
3030using v8::Object;
3131using v8::ObjectTemplate;
3232using v8::Primitive;
33+ using v8::PropertyCallbackInfo;
3334using v8::String;
3435using v8::Undefined;
3536using v8::Value;
@@ -529,6 +530,77 @@ void GetCompileCacheDir(const FunctionCallbackInfo<Value>& args) {
529530 .ToLocalChecked ());
530531}
531532
533+ static void PathHelpersLazyGetter (Local<v8::Name> name,
534+ const PropertyCallbackInfo<Value>& info) {
535+ Isolate* isolate = info.GetIsolate ();
536+ // This getter has no JavaScript function representation and is not
537+ // invoked in the creation context.
538+ // When this getter is invoked in a vm context, the `Realm::GetCurrent(info)`
539+ // returns a nullptr and retrieve the creation context via `this` object and
540+ // get the creation Realm.
541+ Local<Value> receiver_val = info.This ();
542+ if (!receiver_val->IsObject ()) {
543+ THROW_ERR_INVALID_INVOCATION (isolate);
544+ return ;
545+ }
546+ Local<Object> receiver = receiver_val.As <Object>();
547+ Local<Context> context;
548+ if (!receiver->GetCreationContext ().ToLocal (&context)) {
549+ THROW_ERR_INVALID_INVOCATION (isolate);
550+ return ;
551+ }
552+ Environment* env = Environment::GetCurrent (context);
553+
554+ node::Utf8Value url (isolate, info.Data ());
555+ auto file_url = ada::parse (url.ToStringView ());
556+ CHECK (file_url);
557+ auto file_path = url::FileURLToPath (env, *file_url);
558+ CHECK (file_path.has_value ());
559+ std::string_view ret_view = file_path.value ();
560+
561+ node::Utf8Value utf8name (isolate, name);
562+ auto plain_name = utf8name.ToStringView ();
563+ if (plain_name == " dirname" ) {
564+ #ifdef _WIN32
565+ #define PATH_SEPARATOR ' \\ '
566+ #else
567+ #define PATH_SEPARATOR ' /'
568+ #endif
569+ auto index = ret_view.rfind (PATH_SEPARATOR);
570+ CHECK (index != std::string_view::npos);
571+ ret_view.remove_suffix (ret_view.size () - index);
572+ #undef PATH_SEPARATOR
573+ }
574+ Local<Value> ret;
575+ if (!ToV8Value (context, ret_view, isolate).ToLocal (&ret)) {
576+ return ;
577+ }
578+ info.GetReturnValue ().Set (ret);
579+ }
580+ void InitImportMetaPathHelpers (const FunctionCallbackInfo<Value>& args) {
581+ // target, url, shouldSetDirnameAndFilename, resolve
582+ CHECK_GE (args.Length (), 2 );
583+ CHECK (args[0 ]->IsObject ());
584+ CHECK (args[1 ]->IsString ());
585+
586+ Isolate* isolate = args.GetIsolate ();
587+ Local<Context> context = isolate->GetCurrentContext ();
588+ Environment* env = Environment::GetCurrent (context);
589+
590+ auto target = args[0 ].As <Object>();
591+
592+ // N.B.: Order is important to keep keys in alphabetical order.
593+ if (target
594+ ->SetLazyDataProperty (
595+ context, env->dirname_string (), PathHelpersLazyGetter, args[1 ])
596+ .IsNothing () ||
597+ target
598+ ->SetLazyDataProperty (
599+ context, env->filename_string (), PathHelpersLazyGetter, args[1 ])
600+ .IsNothing ())
601+ return ;
602+ }
603+
532604void BindingData::CreatePerIsolateProperties (IsolateData* isolate_data,
533605 Local<ObjectTemplate> target) {
534606 Isolate* isolate = isolate_data->isolate ();
@@ -547,6 +619,7 @@ void BindingData::CreatePerIsolateProperties(IsolateData* isolate_data,
547619 SetMethod (isolate, target, " enableCompileCache" , EnableCompileCache);
548620 SetMethod (isolate, target, " getCompileCacheDir" , GetCompileCacheDir);
549621 SetMethod (isolate, target, " flushCompileCache" , FlushCompileCache);
622+ SetMethod (isolate, target, " setLazyPathHelpers" , InitImportMetaPathHelpers);
550623}
551624
552625void BindingData::CreatePerContextProperties (Local<Object> target,
@@ -581,6 +654,7 @@ void BindingData::RegisterExternalReferences(
581654 registry->Register (EnableCompileCache);
582655 registry->Register (GetCompileCacheDir);
583656 registry->Register (FlushCompileCache);
657+ registry->Register (InitImportMetaPathHelpers);
584658}
585659
586660} // namespace modules
0 commit comments