@@ -467,104 +467,108 @@ std::string ReadFile(uv_file file) {
467
467
return contents;
468
468
}
469
469
470
- enum CheckFileOptions {
471
- LEAVE_OPEN_AFTER_CHECK,
472
- CLOSE_AFTER_CHECK
470
+ enum DescriptorType {
471
+ NONE,
472
+ FILE,
473
+ DIRECTORY
473
474
};
474
475
475
- Maybe<uv_file> CheckFile (const std::string& path,
476
- CheckFileOptions opt = CLOSE_AFTER_CHECK) {
476
+ DescriptorType CheckDescriptor (const std::string& path) {
477
477
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;
501
481
uv_fs_req_cleanup (&fs_req);
482
+ return is_directory ? DIRECTORY : FILE;
502
483
}
503
-
504
- return Just (fd) ;
484
+ uv_fs_req_cleanup (&fs_req);
485
+ return NONE ;
505
486
}
506
487
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>();
516
495
}
517
496
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>();
533
508
}
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);
534
519
}
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) {
546
520
URL parent (" ." , base);
547
- URL dir ( " " ) ;
521
+ std::string last_path ;
548
522
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;
561
537
}
562
- return check;
563
538
} 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>();
565
549
}
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 ());
568
572
return Nothing<URL>();
569
573
}
570
574
@@ -575,24 +579,13 @@ Maybe<URL> Resolve(Environment* env,
575
579
const URL& base) {
576
580
URL pure_url (specifier);
577
581
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);
587
583
}
588
584
if (ShouldBeTreatedAsRelativeOrAbsolutePath (specifier)) {
589
585
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);
595
587
}
588
+ return PackageResolve (env, specifier, base);
596
589
}
597
590
598
591
void ModuleWrap::Resolve (const FunctionCallbackInfo<Value>& args) {
@@ -613,11 +606,18 @@ void ModuleWrap::Resolve(const FunctionCallbackInfo<Value>& args) {
613
606
return node::THROW_ERR_INVALID_ARG_TYPE (
614
607
env, " second argument is not a URL string" );
615
608
}
616
-
609
+
610
+ TryCatch try_catch (env->isolate ());
617
611
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 ;
621
621
}
622
622
623
623
args.GetReturnValue ().Set (result.FromJust ().ToObject (env));
0 commit comments