@@ -35,6 +35,7 @@ using v8::Null;
3535using v8::Object;
3636using v8::ObjectTemplate;
3737using v8::Primitive;
38+ using v8::PropertyCallbackInfo;
3839using v8::String;
3940using v8::Undefined;
4041using v8::Value;
@@ -594,6 +595,76 @@ void GetCompileCacheEntry(const FunctionCallbackInfo<Value>& args) {
594595 isolate, v8::Null (isolate), names.data (), values.data (), names.size ()));
595596}
596597
598+ static void PathHelpersLazyGetter (Local<v8::Name> name,
599+ const PropertyCallbackInfo<Value>& info) {
600+ Isolate* isolate = info.GetIsolate ();
601+ // This getter has no JavaScript function representation and is not
602+ // invoked in the creation context.
603+ // When this getter is invoked in a vm context, the `Realm::GetCurrent(info)`
604+ // returns a nullptr and retrieve the creation context via `this` object and
605+ // get the creation Realm.
606+ Local<Value> receiver_val = info.This ();
607+ if (!receiver_val->IsObject ()) {
608+ THROW_ERR_INVALID_INVOCATION (isolate);
609+ return ;
610+ }
611+ Local<Object> receiver = receiver_val.As <Object>();
612+ Local<Context> context;
613+ if (!receiver->GetCreationContext ().ToLocal (&context)) {
614+ THROW_ERR_INVALID_INVOCATION (isolate);
615+ return ;
616+ }
617+ Environment* env = Environment::GetCurrent (context);
618+
619+ node::Utf8Value url (isolate, info.Data ());
620+ auto file_url = ada::parse (url.ToStringView ());
621+ CHECK (file_url);
622+ auto file_path = url::FileURLToPath (env, *file_url);
623+ CHECK (file_path.has_value ());
624+ std::string_view ret_view = file_path.value ();
625+
626+ node::Utf8Value utf8name (isolate, name);
627+ auto plain_name = utf8name.ToStringView ();
628+ if (plain_name == " dirname" ) {
629+ #ifdef _WIN32
630+ #define PATH_SEPARATOR ' \\ '
631+ #else
632+ #define PATH_SEPARATOR ' /'
633+ #endif
634+ auto index = ret_view.rfind (PATH_SEPARATOR);
635+ CHECK (index != std::string_view::npos);
636+ ret_view.remove_suffix (ret_view.size () - index);
637+ #undef PATH_SEPARATOR
638+ }
639+ Local<Value> ret;
640+ if (!ToV8Value (context, ret_view, isolate).ToLocal (&ret)) {
641+ return ;
642+ }
643+ info.GetReturnValue ().Set (ret);
644+ }
645+ void InitImportMetaPathHelpers (const FunctionCallbackInfo<Value>& args) {
646+ // target, url, shouldSetDirnameAndFilename, resolve
647+ CHECK_GE (args.Length (), 2 );
648+ CHECK (args[0 ]->IsObject ());
649+ CHECK (args[1 ]->IsString ());
650+
651+ Isolate* isolate = args.GetIsolate ();
652+ Local<Context> context = isolate->GetCurrentContext ();
653+ Environment* env = Environment::GetCurrent (context);
654+
655+ auto target = args[0 ].As <Object>();
656+
657+ // N.B.: Order is important to keep keys in alphabetical order.
658+ if (target
659+ ->SetLazyDataProperty (
660+ context, env->dirname_string (), PathHelpersLazyGetter, args[1 ])
661+ .IsNothing () ||
662+ target
663+ ->SetLazyDataProperty (
664+ context, env->filename_string (), PathHelpersLazyGetter, args[1 ])
665+ .IsNothing ())
666+ return ;
667+ }
597668void SaveCompileCacheEntry (const FunctionCallbackInfo<Value>& args) {
598669 Isolate* isolate = args.GetIsolate ();
599670 Local<Context> context = isolate->GetCurrentContext ();
@@ -627,6 +698,7 @@ void BindingData::CreatePerIsolateProperties(IsolateData* isolate_data,
627698 SetMethod (isolate, target, " flushCompileCache" , FlushCompileCache);
628699 SetMethod (isolate, target, " getCompileCacheEntry" , GetCompileCacheEntry);
629700 SetMethod (isolate, target, " saveCompileCacheEntry" , SaveCompileCacheEntry);
701+ SetMethod (isolate, target, " setLazyPathHelpers" , InitImportMetaPathHelpers);
630702}
631703
632704void BindingData::CreatePerContextProperties (Local<Object> target,
@@ -682,6 +754,7 @@ void BindingData::RegisterExternalReferences(
682754 registry->Register (FlushCompileCache);
683755 registry->Register (GetCompileCacheEntry);
684756 registry->Register (SaveCompileCacheEntry);
757+ registry->Register (InitImportMetaPathHelpers);
685758}
686759
687760} // namespace modules
0 commit comments