@@ -467,104 +467,108 @@ std::string ReadFile(uv_file file) {
467467 return contents;
468468}
469469
470- enum CheckFileOptions {
471- LEAVE_OPEN_AFTER_CHECK,
472- CLOSE_AFTER_CHECK
470+ enum DescriptorType {
471+ NONE,
472+ FILE,
473+ DIRECTORY
473474};
474475
475- Maybe<uv_file> CheckFile (const std::string& path,
476- CheckFileOptions opt = CLOSE_AFTER_CHECK) {
476+ DescriptorType CheckDescriptor (const std::string& path) {
477477 uv_fs_t fs_req;
478- if (path.empty ()) {
479- return Nothing<uv_file>();
480- }
481-
482- uv_file fd = uv_fs_open (nullptr , &fs_req, path.c_str (), O_RDONLY, 0 , nullptr );
483- uv_fs_req_cleanup (&fs_req);
484-
485- if (fd < 0 ) {
486- return Nothing<uv_file>();
487- }
488-
489- uv_fs_fstat (nullptr , &fs_req, fd, nullptr );
490- uint64_t is_directory = fs_req.statbuf .st_mode & S_IFDIR;
491- uv_fs_req_cleanup (&fs_req);
492-
493- if (is_directory) {
494- CHECK_EQ (0 , uv_fs_close (nullptr , &fs_req, fd, nullptr ));
495- uv_fs_req_cleanup (&fs_req);
496- return Nothing<uv_file>();
497- }
498-
499- if (opt == CLOSE_AFTER_CHECK) {
500- CHECK_EQ (0 , uv_fs_close (nullptr , &fs_req, fd, nullptr ));
478+ int rc = uv_fs_stat (nullptr , &fs_req, path.c_str (), nullptr );
479+ if (rc == 0 ) {
480+ uint64_t is_directory = fs_req.statbuf .st_mode & S_IFDIR;
501481 uv_fs_req_cleanup (&fs_req);
482+ return is_directory ? DIRECTORY : FILE;
502483 }
503-
504- return Just (fd) ;
484+ uv_fs_req_cleanup (&fs_req);
485+ return NONE ;
505486}
506487
507- enum ResolveExtensionsOptions {
508- TRY_EXACT_NAME,
509- ONLY_VIA_EXTENSIONS
510- };
511-
512- inline bool ResolvesToFile (const URL& search) {
513- std::string filePath = search.ToFilePath ();
514- Maybe<uv_file> check = CheckFile (filePath);
515- return !check.IsNothing ();
488+ inline Maybe<URL> PackageMainResolve (const URL& search) {
489+ std::string path = search.path ();
490+ std::string last_segment = path.substr (path.find_last_of (' /' ) + 1 );
491+ URL main_url = URL (" ./" + last_segment + " /index.mjs" , search);
492+ if (CheckDescriptor (main_url.ToFilePath ()) == FILE)
493+ return Just (main_url);
494+ return Nothing<URL>();
516495}
517496
518- template <ResolveExtensionsOptions options>
519- Maybe<URL> ResolveExtensions (const URL& search) {
520- if (options == TRY_EXACT_NAME) {
521- std::string filePath = search.ToFilePath ();
522- Maybe<uv_file> check = CheckFile (filePath);
523- if (!check.IsNothing ()) {
524- return Just (search);
525- }
526- }
527-
528- for (const char * extension : EXTENSIONS) {
529- URL guess (search.path () + extension, &search);
530- Maybe<uv_file> check = CheckFile (guess.ToFilePath ());
531- if (!check.IsNothing ()) {
532- return Just (guess);
497+ Maybe<URL> PackageResolve (Environment* env,
498+ const std::string& specifier,
499+ const URL& base) {
500+ if (specifier.length () == 0 ) return Nothing<URL>();
501+ size_t sep_index = specifier.find (' /' );
502+ if (specifier[0 ] == ' @' ) {
503+ if (sep_index == std::string::npos) {
504+ std::string msg = " Invalid package name '" + specifier +
505+ " ' imported from " + base.ToFilePath ();
506+ node::THROW_ERR_INVALID_PACKAGE_NAME (env, msg.c_str ());
507+ return Nothing<URL>();
533508 }
509+ sep_index = specifier.find (' /' , sep_index + 1 );
510+ }
511+ std::string pkg_name = specifier.substr (0 ,
512+ sep_index == std::string::npos ? std::string::npos : sep_index);
513+ std::string pkg_path;
514+ if (sep_index == std::string::npos ||
515+ sep_index == specifier.length () - 1 ) {
516+ pkg_path = " " ;
517+ } else {
518+ pkg_path = specifier.substr (sep_index);
534519 }
535-
536- return Nothing<URL>();
537- }
538-
539- inline Maybe<URL> ResolveIndex (const URL& search) {
540- return ResolveExtensions<ONLY_VIA_EXTENSIONS>(URL (" index" , search));
541- }
542-
543- Maybe<URL> ResolveModule (Environment* env,
544- const std::string& specifier,
545- const URL& base) {
546520 URL parent (" ." , base);
547- URL dir ( " " ) ;
521+ std::string last_path ;
548522 do {
549- dir = parent;
550- Maybe<URL> check =
551- Resolve (env, " ./node_modules/" + specifier, dir);
552- if (!check.IsNothing ()) {
553- const size_t limit = specifier.find (' /' );
554- const size_t spec_len =
555- limit == std::string::npos ? specifier.length () :
556- limit + 1 ;
557- std::string chroot =
558- dir.path () + " node_modules/" + specifier.substr (0 , spec_len);
559- if (check.FromJust ().path ().substr (0 , chroot.length ()) != chroot) {
560- return Nothing<URL>();
523+ URL pkg_url (" ./node_modules/" + pkg_name, &parent);
524+ URL url;
525+ if (pkg_path.length ()) {
526+ url = URL (" ./node_modules/" + pkg_name + " /" + pkg_path, &parent);
527+ } else {
528+ url = pkg_url;
529+ }
530+ if (pkg_path.length ()) {
531+ DescriptorType check = CheckDescriptor (url.ToFilePath ());
532+ if (check == FILE) {
533+ return Just (url);
534+ } else if (check == DIRECTORY) {
535+ Maybe<URL> main_url = PackageMainResolve (url);
536+ if (!main_url.IsNothing ()) return main_url;
561537 }
562- return check;
563538 } else {
564- // TODO(bmeck) PREVENT FALLTHROUGH
539+ Maybe<URL> main_url = PackageMainResolve (url);
540+ if (!main_url.IsNothing ()) return main_url;
541+ }
542+ // throw not found if we did match a package directory
543+ DescriptorType check = CheckDescriptor (pkg_url.ToFilePath ());
544+ if (check == DIRECTORY) {
545+ std::string msg = " Cannot find module '" + url.ToFilePath () +
546+ " ' imported from " + base.ToFilePath ();
547+ node::THROW_ERR_MISSING_MODULE (env, msg.c_str ());
548+ return Nothing<URL>();
565549 }
566- parent = URL (" .." , &dir);
567- } while (parent.path () != dir.path ());
550+ last_path = parent.path ();
551+ parent = URL (" .." , &parent);
552+ // cross-platform root check
553+ } while (parent.path () != last_path);
554+ return Nothing<URL>();
555+ }
556+
557+ Maybe<URL> PathResolve (Environment* env,
558+ const URL& url,
559+ const URL& base) {
560+ std::string path = url.ToFilePath ();
561+ DescriptorType check = CheckDescriptor (path);
562+ if (check == FILE) return Just (url);
563+
564+ if (check == DIRECTORY) {
565+ Maybe<URL> url_main = PackageMainResolve (url);
566+ if (!url_main.IsNothing ()) return url_main;
567+ }
568+
569+ std::string msg = " Cannot find module '" + path +
570+ " ' imported from " + base.ToFilePath ();
571+ node::THROW_ERR_MISSING_MODULE (env, msg.c_str ());
568572 return Nothing<URL>();
569573}
570574
@@ -575,24 +579,13 @@ Maybe<URL> Resolve(Environment* env,
575579 const URL& base) {
576580 URL pure_url (specifier);
577581 if (!(pure_url.flags () & URL_FLAGS_FAILED)) {
578- // just check existence, without altering
579- Maybe<uv_file> check = CheckFile (pure_url.ToFilePath ());
580- if (check.IsNothing ()) {
581- return Nothing<URL>();
582- }
583- return Just (pure_url);
584- }
585- if (specifier.length () == 0 ) {
586- return Nothing<URL>();
582+ return PathResolve (env, pure_url, base);
587583 }
588584 if (ShouldBeTreatedAsRelativeOrAbsolutePath (specifier)) {
589585 URL resolved (specifier, base);
590- if (ResolvesToFile (resolved))
591- return Just (resolved);
592- return Nothing<URL>();
593- } else {
594- return ResolveModule (env, specifier, base);
586+ return PathResolve (env, resolved, base);
595587 }
588+ return PackageResolve (env, specifier, base);
596589}
597590
598591void ModuleWrap::Resolve (const FunctionCallbackInfo<Value>& args) {
@@ -613,11 +606,18 @@ void ModuleWrap::Resolve(const FunctionCallbackInfo<Value>& args) {
613606 return node::THROW_ERR_INVALID_ARG_TYPE (
614607 env, " second argument is not a URL string" );
615608 }
616-
609+
610+ TryCatch try_catch (env->isolate ());
617611 Maybe<URL> result = node::loader::Resolve (env, specifier_std, url);
618- if (result.IsNothing () || (result.FromJust ().flags () & URL_FLAGS_FAILED)) {
619- std::string msg = " Cannot find module " + specifier_std;
620- return node::THROW_ERR_MISSING_MODULE (env, msg.c_str ());
612+ if (try_catch.HasCaught ()) {
613+ try_catch.ReThrow ();
614+ return ;
615+ } else if (result.IsNothing () || (result.FromJust ().flags () & URL_FLAGS_FAILED)) {
616+ std::string msg = " Cannot find module '" + specifier_std +
617+ " ' imported from " + url.ToFilePath ();
618+ node::THROW_ERR_MISSING_MODULE (env, msg.c_str ());
619+ try_catch.ReThrow ();
620+ return ;
621621 }
622622
623623 args.GetReturnValue ().Set (result.FromJust ().ToObject (env));
0 commit comments