summaryrefslogtreecommitdiff
path: root/src/module_wrap.cc
diff options
context:
space:
mode:
authorGuy Bedford <guybedford@gmail.com>2019-10-13 19:27:39 -0400
committerGuy Bedford <guybedford@gmail.com>2019-11-08 17:26:26 -0500
commit2367474db46136aecb87b27d82bfa597a95aeedd (patch)
tree58fd8eb4ad143677a791b00f994965d9573e562b /src/module_wrap.cc
parentc73ef32d355aa58672c15e89534c375dd2246f3c (diff)
downloadandroid-node-v8-2367474db46136aecb87b27d82bfa597a95aeedd.tar.gz
android-node-v8-2367474db46136aecb87b27d82bfa597a95aeedd.tar.bz2
android-node-v8-2367474db46136aecb87b27d82bfa597a95aeedd.zip
module: conditional exports with flagged conditions
PR-URL: https://github.com/nodejs/node/pull/29978 Reviewed-By: Jan Krems <jan.krems@gmail.com> Reviewed-By: Myles Borins <myles.borins@gmail.com>
Diffstat (limited to 'src/module_wrap.cc')
-rw-r--r--src/module_wrap.cc307
1 files changed, 159 insertions, 148 deletions
diff --git a/src/module_wrap.cc b/src/module_wrap.cc
index 4c4a1ce863..5745cce9e0 100644
--- a/src/module_wrap.cc
+++ b/src/module_wrap.cc
@@ -835,10 +835,16 @@ void ThrowExportsInvalid(Environment* env,
const std::string& target,
const URL& pjson_url,
const URL& base) {
- const std::string msg = "Cannot resolve package exports target '" + target +
- "' matched for '" + subpath + "' in " + pjson_url.ToFilePath() +
- ", imported from " + base.ToFilePath();
- node::THROW_ERR_MODULE_NOT_FOUND(env, msg.c_str());
+ if (subpath.length()) {
+ const std::string msg = "Cannot resolve package exports target '" + target +
+ "' matched for '" + subpath + "' in " + pjson_url.ToFilePath() +
+ ", imported from " + base.ToFilePath();
+ node::THROW_ERR_MODULE_NOT_FOUND(env, msg.c_str());
+ } else {
+ const std::string msg = "Cannot resolve package main '" + target + "' in" +
+ pjson_url.ToFilePath() + ", imported from " + base.ToFilePath();
+ node::THROW_ERR_MODULE_NOT_FOUND(env, msg.c_str());
+ }
}
void ThrowExportsInvalid(Environment* env,
@@ -857,13 +863,13 @@ void ThrowExportsInvalid(Environment* env,
}
}
-Maybe<URL> ResolveExportsTarget(Environment* env,
- const std::string& target,
- const std::string& subpath,
- const std::string& match,
- const URL& pjson_url,
- const URL& base,
- bool throw_invalid = true) {
+Maybe<URL> ResolveExportsTargetString(Environment* env,
+ const std::string& target,
+ const std::string& subpath,
+ const std::string& match,
+ const URL& pjson_url,
+ const URL& base,
+ bool throw_invalid = true) {
if (target.substr(0, 2) != "./") {
if (throw_invalid) {
ThrowExportsInvalid(env, match, target, pjson_url, base);
@@ -901,68 +907,142 @@ Maybe<URL> ResolveExportsTarget(Environment* env,
return Just(subpath_resolved);
}
+Maybe<URL> ResolveExportsTarget(Environment* env,
+ const URL& pjson_url,
+ Local<Value> target,
+ const std::string& subpath,
+ const std::string& pkg_subpath,
+ const URL& base,
+ bool throw_invalid = true) {
+ Isolate* isolate = env->isolate();
+ Local<Context> context = env->context();
+ if (target->IsString()) {
+ Utf8Value target_utf8(isolate, target.As<v8::String>());
+ std::string target_str(*target_utf8, target_utf8.length());
+ Maybe<URL> resolved = ResolveExportsTargetString(env, target_str, subpath,
+ pkg_subpath, pjson_url, base, throw_invalid);
+ if (resolved.IsNothing()) {
+ return Nothing<URL>();
+ }
+ return FinalizeResolution(env, resolved.FromJust(), base);
+ } else if (target->IsArray()) {
+ Local<Array> target_arr = target.As<Array>();
+ const uint32_t length = target_arr->Length();
+ if (length == 0) {
+ if (throw_invalid) {
+ ThrowExportsInvalid(env, pkg_subpath, target, pjson_url, base);
+ }
+ return Nothing<URL>();
+ }
+ for (uint32_t i = 0; i < length; i++) {
+ auto target_item = target_arr->Get(context, i).ToLocalChecked();
+ if (!target_item->IsArray()) {
+ Maybe<URL> resolved = ResolveExportsTarget(env, pjson_url,
+ target_item, subpath, pkg_subpath, base, false);
+ if (resolved.IsNothing()) continue;
+ return FinalizeResolution(env, resolved.FromJust(), base);
+ }
+ }
+ if (throw_invalid) {
+ auto invalid = target_arr->Get(context, length - 1).ToLocalChecked();
+ Maybe<URL> resolved = ResolveExportsTarget(env, pjson_url, invalid,
+ subpath, pkg_subpath, base, true);
+ CHECK(resolved.IsNothing());
+ }
+ return Nothing<URL>();
+ } else if (target->IsObject()) {
+ Local<Object> target_obj = target.As<Object>();
+ bool matched = false;
+ Local<Value> conditionalTarget;
+ if (env->options()->experimental_conditional_exports &&
+ target_obj->HasOwnProperty(context, env->node_string()).FromJust()) {
+ matched = true;
+ conditionalTarget =
+ target_obj->Get(context, env->node_string()).ToLocalChecked();
+ Maybe<URL> resolved = ResolveExportsTarget(env, pjson_url,
+ conditionalTarget, subpath, pkg_subpath, base, false);
+ if (!resolved.IsNothing()) {
+ return resolved;
+ }
+ }
+ if (target_obj->HasOwnProperty(context, env->default_string()).FromJust()) {
+ matched = true;
+ conditionalTarget =
+ target_obj->Get(context, env->default_string()).ToLocalChecked();
+ Maybe<URL> resolved = ResolveExportsTarget(env, pjson_url,
+ conditionalTarget, subpath, pkg_subpath, base, false);
+ if (!resolved.IsNothing()) {
+ return resolved;
+ }
+ }
+ if (matched && throw_invalid) {
+ Maybe<URL> resolved = ResolveExportsTarget(env, pjson_url,
+ conditionalTarget, subpath, pkg_subpath, base, true);
+ CHECK(resolved.IsNothing());
+ return Nothing<URL>();
+ }
+ }
+ if (throw_invalid) {
+ ThrowExportsInvalid(env, pkg_subpath, target, pjson_url, base);
+ }
+ return Nothing<URL>();
+}
+
+Maybe<bool> IsConditionalExportsMainSugar(Environment* env,
+ Local<Value> exports,
+ const URL& pjson_url,
+ const URL& base) {
+ if (exports->IsString() || exports->IsArray()) return Just(true);
+ if (!exports->IsObject()) return Just(false);
+ Local<Context> context = env->context();
+ Local<Object> exports_obj = exports.As<Object>();
+ Local<Array> keys =
+ exports_obj->GetOwnPropertyNames(context).ToLocalChecked();
+ bool isConditionalSugar = false;
+ for (uint32_t i = 0; i < keys->Length(); ++i) {
+ Local<String> key = keys->Get(context, i).ToLocalChecked().As<String>();
+ Utf8Value key_utf8(env->isolate(), key);
+ bool curIsConditionalSugar = key_utf8.length() == 0 || key_utf8[0] != '.';
+ if (i == 0) {
+ isConditionalSugar = curIsConditionalSugar;
+ } else if (isConditionalSugar != curIsConditionalSugar) {
+ const std::string msg = "Cannot resolve package exports in " +
+ pjson_url.ToFilePath() + ", imported from " + base.ToFilePath() + ". " +
+ "\"exports\" cannot contain some keys starting with '.' and some not." +
+ " The exports object must either be an object of package subpath keys" +
+ " or an object of main entry condition name keys only.";
+ node::THROW_ERR_INVALID_PACKAGE_CONFIG(env, msg.c_str());
+ return Nothing<bool>();
+ }
+ }
+ return Just(isConditionalSugar);
+}
+
Maybe<URL> PackageMainResolve(Environment* env,
const URL& pjson_url,
const PackageConfig& pcfg,
const URL& base) {
if (pcfg.exists == Exists::Yes) {
Isolate* isolate = env->isolate();
- Local<Context> context = env->context();
+
if (!pcfg.exports.IsEmpty()) {
Local<Value> exports = pcfg.exports.Get(isolate);
- if (exports->IsString() || exports->IsObject() || exports->IsArray()) {
- Local<Value> target;
- if (!exports->IsObject()) {
- target = exports;
- } else {
- Local<Object> exports_obj = exports.As<Object>();
- Local<String> dot_string = String::NewFromUtf8(env->isolate(), ".",
- v8::NewStringType::kNormal).ToLocalChecked();
- target =
- exports_obj->Get(env->context(), dot_string).ToLocalChecked();
- }
- if (target->IsString()) {
- Utf8Value target_utf8(isolate, target.As<v8::String>());
- std::string target(*target_utf8, target_utf8.length());
- Maybe<URL> resolved = ResolveExportsTarget(env, target, "", ".",
- pjson_url, base);
- if (resolved.IsNothing()) {
- ThrowExportsInvalid(env, ".", target, pjson_url, base);
- return Nothing<URL>();
- }
- return FinalizeResolution(env, resolved.FromJust(), base);
- } else if (target->IsArray()) {
- Local<Array> target_arr = target.As<Array>();
- const uint32_t length = target_arr->Length();
- if (length == 0) {
- ThrowExportsInvalid(env, ".", target, pjson_url, base);
- return Nothing<URL>();
- }
- for (uint32_t i = 0; i < length; i++) {
- auto target_item = target_arr->Get(context, i).ToLocalChecked();
- if (target_item->IsString()) {
- Utf8Value target_utf8(isolate, target_item.As<v8::String>());
- std::string target_str(*target_utf8, target_utf8.length());
- Maybe<URL> resolved = ResolveExportsTarget(env, target_str, "",
- ".", pjson_url, base, false);
- if (resolved.IsNothing()) continue;
- return FinalizeResolution(env, resolved.FromJust(), base);
- }
- }
- auto invalid = target_arr->Get(context, length - 1).ToLocalChecked();
- if (!invalid->IsString()) {
- ThrowExportsInvalid(env, ".", invalid, pjson_url, base);
- return Nothing<URL>();
- }
- Utf8Value invalid_utf8(isolate, invalid.As<v8::String>());
- std::string invalid_str(*invalid_utf8, invalid_utf8.length());
- Maybe<URL> resolved = ResolveExportsTarget(env, invalid_str, "",
- ".", pjson_url, base);
- CHECK(resolved.IsNothing());
- return Nothing<URL>();
- } else {
- ThrowExportsInvalid(env, ".", target, pjson_url, base);
- return Nothing<URL>();
+ Maybe<bool> isConditionalExportsMainSugar =
+ IsConditionalExportsMainSugar(env, exports, pjson_url, base);
+ if (isConditionalExportsMainSugar.IsNothing())
+ return Nothing<URL>();
+ if (isConditionalExportsMainSugar.FromJust()) {
+ return ResolveExportsTarget(env, pjson_url, exports, "", "", base,
+ true);
+ } else if (exports->IsObject()) {
+ Local<Object> exports_obj = exports.As<Object>();
+ if (exports_obj->HasOwnProperty(env->context(), env->dot_string())
+ .FromJust()) {
+ Local<Value> target =
+ exports_obj->Get(env->context(), env->dot_string())
+ .ToLocalChecked();
+ return ResolveExportsTarget(env, pjson_url, target, "", "", base,
+ true);
}
}
}
@@ -1002,7 +1082,11 @@ Maybe<URL> PackageExportsResolve(Environment* env,
Isolate* isolate = env->isolate();
Local<Context> context = env->context();
Local<Value> exports = pcfg.exports.Get(isolate);
- if (!exports->IsObject()) {
+ Maybe<bool> isConditionalExportsMainSugar =
+ IsConditionalExportsMainSugar(env, exports, pjson_url, base);
+ if (isConditionalExportsMainSugar.IsNothing())
+ return Nothing<URL>();
+ if (!exports->IsObject() || isConditionalExportsMainSugar.FromJust()) {
ThrowExportsNotFound(env, pkg_subpath, pjson_url, base);
return Nothing<URL>();
}
@@ -1012,49 +1096,12 @@ Maybe<URL> PackageExportsResolve(Environment* env,
if (exports_obj->HasOwnProperty(context, subpath).FromJust()) {
Local<Value> target = exports_obj->Get(context, subpath).ToLocalChecked();
- if (target->IsString()) {
- Utf8Value target_utf8(isolate, target.As<v8::String>());
- std::string target_str(*target_utf8, target_utf8.length());
- Maybe<URL> resolved = ResolveExportsTarget(env, target_str, "",
- pkg_subpath, pjson_url, base);
- if (resolved.IsNothing()) {
- ThrowExportsInvalid(env, pkg_subpath, target, pjson_url, base);
- return Nothing<URL>();
- }
- return FinalizeResolution(env, resolved.FromJust(), base);
- } else if (target->IsArray()) {
- Local<Array> target_arr = target.As<Array>();
- const uint32_t length = target_arr->Length();
- if (length == 0) {
- ThrowExportsInvalid(env, pkg_subpath, target, pjson_url, base);
- return Nothing<URL>();
- }
- for (uint32_t i = 0; i < length; i++) {
- auto target_item = target_arr->Get(context, i).ToLocalChecked();
- if (target_item->IsString()) {
- Utf8Value target_utf8(isolate, target_item.As<v8::String>());
- std::string target(*target_utf8, target_utf8.length());
- Maybe<URL> resolved = ResolveExportsTarget(env, target, "",
- pkg_subpath, pjson_url, base, false);
- if (resolved.IsNothing()) continue;
- return FinalizeResolution(env, resolved.FromJust(), base);
- }
- }
- auto invalid = target_arr->Get(context, length - 1).ToLocalChecked();
- if (!invalid->IsString()) {
- ThrowExportsInvalid(env, pkg_subpath, invalid, pjson_url, base);
- return Nothing<URL>();
- }
- Utf8Value invalid_utf8(isolate, invalid.As<v8::String>());
- std::string invalid_str(*invalid_utf8, invalid_utf8.length());
- Maybe<URL> resolved = ResolveExportsTarget(env, invalid_str, "",
- pkg_subpath, pjson_url, base);
- CHECK(resolved.IsNothing());
- return Nothing<URL>();
- } else {
- ThrowExportsInvalid(env, pkg_subpath, target, pjson_url, base);
+ Maybe<URL> resolved = ResolveExportsTarget(env, pjson_url, target, "",
+ pkg_subpath, base);
+ if (resolved.IsNothing()) {
return Nothing<URL>();
}
+ return FinalizeResolution(env, resolved.FromJust(), base);
}
Local<String> best_match;
@@ -1076,49 +1123,13 @@ Maybe<URL> PackageExportsResolve(Environment* env,
if (best_match_str.length() > 0) {
auto target = exports_obj->Get(context, best_match).ToLocalChecked();
std::string subpath = pkg_subpath.substr(best_match_str.length());
- if (target->IsString()) {
- Utf8Value target_utf8(isolate, target.As<v8::String>());
- std::string target(*target_utf8, target_utf8.length());
- Maybe<URL> resolved = ResolveExportsTarget(env, target, subpath,
- pkg_subpath, pjson_url, base);
- if (resolved.IsNothing()) {
- ThrowExportsInvalid(env, pkg_subpath, target, pjson_url, base);
- return Nothing<URL>();
- }
- return FinalizeResolution(env, URL(subpath, resolved.FromJust()), base);
- } else if (target->IsArray()) {
- Local<Array> target_arr = target.As<Array>();
- const uint32_t length = target_arr->Length();
- if (length == 0) {
- ThrowExportsInvalid(env, pkg_subpath, target, pjson_url, base);
- return Nothing<URL>();
- }
- for (uint32_t i = 0; i < length; i++) {
- auto target_item = target_arr->Get(context, i).ToLocalChecked();
- if (target_item->IsString()) {
- Utf8Value target_utf8(isolate, target_item.As<v8::String>());
- std::string target_str(*target_utf8, target_utf8.length());
- Maybe<URL> resolved = ResolveExportsTarget(env, target_str, subpath,
- pkg_subpath, pjson_url, base, false);
- if (resolved.IsNothing()) continue;
- return FinalizeResolution(env, resolved.FromJust(), base);
- }
- }
- auto invalid = target_arr->Get(context, length - 1).ToLocalChecked();
- if (!invalid->IsString()) {
- ThrowExportsInvalid(env, pkg_subpath, invalid, pjson_url, base);
- return Nothing<URL>();
- }
- Utf8Value invalid_utf8(isolate, invalid.As<v8::String>());
- std::string invalid_str(*invalid_utf8, invalid_utf8.length());
- Maybe<URL> resolved = ResolveExportsTarget(env, invalid_str, subpath,
- pkg_subpath, pjson_url, base);
- CHECK(resolved.IsNothing());
- return Nothing<URL>();
- } else {
- ThrowExportsInvalid(env, pkg_subpath, target, pjson_url, base);
+
+ Maybe<URL> resolved = ResolveExportsTarget(env, pjson_url, target, subpath,
+ pkg_subpath, base);
+ if (resolved.IsNothing()) {
return Nothing<URL>();
}
+ return FinalizeResolution(env, resolved.FromJust(), base);
}
ThrowExportsNotFound(env, pkg_subpath, pjson_url, base);