Skip to content
This repository was archived by the owner on Apr 16, 2020. It is now read-only.

Commit 7da2197

Browse files
committed
implement spec
1 parent a951b37 commit 7da2197

File tree

4 files changed

+106
-114
lines changed

4 files changed

+106
-114
lines changed

lib/internal/errors.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -764,7 +764,7 @@ E('ERR_MISSING_DYNAMIC_INSTANTIATE_HOOK',
764764
'dynamicInstantiate function was provided', Error);
765765
E('ERR_MISSING_MODULE', 'Cannot find module %s', Error);
766766
E('ERR_MODULE_RESOLUTION_LEGACY',
767-
'%s not found by import in %s.' +
767+
'Cannot find module \'%s\' imported from %s.' +
768768
' Legacy behavior in require() would have found it at %s',
769769
Error);
770770
E('ERR_MULTIPLE_CALLBACK', 'Callback called multiple times', Error);

lib/internal/modules/esm/default_resolve.js

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ const {
1414
ERR_UNKNOWN_FILE_EXTENSION
1515
} = require('internal/errors').codes;
1616
const { resolve: moduleWrapResolve } = internalBinding('module_wrap');
17-
const StringStartsWith = Function.call.bind(String.prototype.startsWith);
1817
const { pathToFileURL, fileURLToPath } = require('internal/url');
1918

2019
const realpathCache = new Map();
@@ -35,8 +34,8 @@ function search(target, base) {
3534
tmpMod.paths = CJSmodule._nodeModulePaths(
3635
new URL('./', questionedBase).pathname);
3736
const found = CJSmodule._resolveFilename(target, tmpMod);
38-
error = new ERR_MODULE_RESOLUTION_LEGACY(target, base, found);
39-
} catch (problemChecking) {
37+
error = new ERR_MODULE_RESOLUTION_LEGACY(target, fileURLToPath(base), found);
38+
} catch {
4039
// ignore
4140
}
4241
throw error;
@@ -56,16 +55,8 @@ function resolve(specifier, parentURL) {
5655
};
5756
}
5857

59-
let url;
60-
try {
61-
url = search(specifier,
62-
parentURL || pathToFileURL(`${process.cwd()}/`).href);
63-
} catch (e) {
64-
if (typeof e.message === 'string' &&
65-
StringStartsWith(e.message, 'Cannot find module'))
66-
e.code = 'MODULE_NOT_FOUND';
67-
throw e;
68-
}
58+
let url = search(specifier,
59+
parentURL || pathToFileURL(`${process.cwd()}/`).href);
6960

7061
const isMain = parentURL === undefined;
7162

src/module_wrap.cc

Lines changed: 100 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -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

598591
void 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));

src/node_errors.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ namespace node {
2828
V(ERR_CONSTRUCT_CALL_REQUIRED, Error) \
2929
V(ERR_INVALID_ARG_VALUE, TypeError) \
3030
V(ERR_INVALID_ARG_TYPE, TypeError) \
31+
V(ERR_INVALID_PACKAGE_NAME, Error) \
3132
V(ERR_INVALID_TRANSFER_OBJECT, TypeError) \
3233
V(ERR_MEMORY_ALLOCATION_FAILED, Error) \
3334
V(ERR_MISSING_ARGS, TypeError) \

0 commit comments

Comments
 (0)