diff options
Diffstat (limited to 'src/module_wrap.cc')
-rw-r--r-- | src/module_wrap.cc | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/src/module_wrap.cc b/src/module_wrap.cc index e7df8688cb..46210520fc 100644 --- a/src/module_wrap.cc +++ b/src/module_wrap.cc @@ -566,6 +566,7 @@ Maybe<std::string> ReadIfFile(const std::string& path) { using Exists = PackageConfig::Exists; using IsValid = PackageConfig::IsValid; using HasMain = PackageConfig::HasMain; +using HasName = PackageConfig::HasName; using PackageType = PackageConfig::PackageType; Maybe<const PackageConfig*> GetPackageConfig(Environment* env, @@ -588,6 +589,7 @@ Maybe<const PackageConfig*> GetPackageConfig(Environment* env, if (source.IsNothing()) { auto entry = env->package_json_cache.emplace(path, PackageConfig { Exists::No, IsValid::Yes, HasMain::No, "", + HasName::No, "", PackageType::None, Global<Value>() }); return Just(&entry.first->second); } @@ -608,6 +610,7 @@ Maybe<const PackageConfig*> GetPackageConfig(Environment* env, !pkg_json_v->ToObject(context).ToLocal(&pkg_json)) { env->package_json_cache.emplace(path, PackageConfig { Exists::Yes, IsValid::No, HasMain::No, "", + HasName::No, "", PackageType::None, Global<Value>() }); std::string msg = "Invalid JSON in " + path + " imported from " + base.ToFilePath(); @@ -627,6 +630,18 @@ Maybe<const PackageConfig*> GetPackageConfig(Environment* env, main_std.assign(std::string(*main_utf8, main_utf8.length())); } + Local<Value> pkg_name; + HasName has_name = HasName::No; + std::string name_std; + if (pkg_json->Get(env->context(), env->name_string()).ToLocal(&pkg_name)) { + if (pkg_name->IsString()) { + has_name = HasName::Yes; + + Utf8Value name_utf8(isolate, pkg_name); + name_std.assign(std::string(*name_utf8, name_utf8.length())); + } + } + PackageType pkg_type = PackageType::None; Local<Value> type_v; if (pkg_json->Get(env->context(), env->type_string()).ToLocal(&type_v)) { @@ -647,12 +662,14 @@ Maybe<const PackageConfig*> GetPackageConfig(Environment* env, auto entry = env->package_json_cache.emplace(path, PackageConfig { Exists::Yes, IsValid::Yes, has_main, main_std, + has_name, name_std, pkg_type, std::move(exports) }); return Just(&entry.first->second); } auto entry = env->package_json_cache.emplace(path, PackageConfig { Exists::Yes, IsValid::Yes, has_main, main_std, + has_name, name_std, pkg_type, Global<Value>() }); return Just(&entry.first->second); } @@ -682,6 +699,7 @@ Maybe<const PackageConfig*> GetPackageScopeConfig(Environment* env, } auto entry = env->package_json_cache.emplace(pjson_url.ToFilePath(), PackageConfig { Exists::No, IsValid::Yes, HasMain::No, "", + HasName::No, "", PackageType::None, Global<Value>() }); const PackageConfig* pcfg = &entry.first->second; return Just(pcfg); @@ -1107,6 +1125,62 @@ Maybe<URL> PackageExportsResolve(Environment* env, return Nothing<URL>(); } +Maybe<URL> ResolveSelf(Environment* env, + const std::string& specifier, + const URL& base) { + if (!env->options()->experimental_resolve_self) { + return Nothing<URL>(); + } + + const PackageConfig* pcfg; + if (GetPackageScopeConfig(env, base, base).To(&pcfg) && + pcfg->exists == Exists::Yes) { + // TODO(jkrems): Find a way to forward the pair/iterator already generated + // while executing GetPackageScopeConfig + URL pjson_url(""); + bool found_pjson = false; + for (auto it = env->package_json_cache.begin(); + it != env->package_json_cache.end(); + ++it) { + if (&it->second == pcfg) { + pjson_url = URL::FromFilePath(it->first); + found_pjson = true; + } + } + + if (!found_pjson) { + return Nothing<URL>(); + } + + // "If specifier starts with pcfg name" + std::string subpath; + if (specifier.rfind(pcfg->name, 0)) { + // We know now: specifier is either equal to name or longer. + if (specifier == subpath) { + subpath = ""; + } else if (specifier[pcfg->name.length()] == '/') { + // Return everything after the slash + subpath = "." + specifier.substr(pcfg->name.length() + 1); + } else { + // The specifier is neither the name of the package nor a subpath of it + return Nothing<URL>(); + } + } + + if (found_pjson && !subpath.length()) { + return PackageMainResolve(env, pjson_url, *pcfg, base); + } else if (found_pjson) { + if (!pcfg->exports.IsEmpty()) { + return PackageExportsResolve(env, pjson_url, subpath, *pcfg, base); + } else { + return FinalizeResolution(env, URL(subpath, pjson_url), base); + } + } + } + + return Nothing<URL>(); +} + Maybe<URL> PackageResolve(Environment* env, const std::string& specifier, const URL& base) { @@ -1180,6 +1254,11 @@ Maybe<URL> PackageResolve(Environment* env, // Cross-platform root check. } while (pjson_path.length() != last_path.length()); + Maybe<URL> self_url = ResolveSelf(env, specifier, base); + if (self_url.IsJust()) { + return self_url; + } + std::string msg = "Cannot find package '" + pkg_name + "' imported from " + base.ToFilePath(); node::THROW_ERR_MODULE_NOT_FOUND(env, msg.c_str()); |