-
- Notifications
You must be signed in to change notification settings - Fork 33.5k
module: implement logical conditional exports ordering #31008
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
dc40b4a
f1fd65c
9dbc816
e00b4b7
d760e46
9bfdebf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
#define V8_ENABLE_CHECKS 1 | ||
#include "module_wrap.h" | ||
| ||
#include "env.h" | ||
| @@ -12,7 +13,6 @@ | |
#include <sys/stat.h> // S_IFDIR | ||
| ||
#include <algorithm> | ||
#include <climits> // PATH_MAX | ||
| ||
namespace node { | ||
namespace loader { | ||
| @@ -908,6 +908,25 @@ Maybe<URL> ResolveExportsTargetString(Environment* env, | |
return Just(subpath_resolved); | ||
} | ||
| ||
bool IsArrayIndex(Environment* env, Local<Value> p) { | ||
Local<Context> context = env->context(); | ||
Local<String> p_str = p->ToString(context).ToLocalChecked(); | ||
double n_dbl = static_cast<double>(p_str->NumberValue(context).FromJust()); | ||
Local<Number> n = Number::New(env->isolate(), n_dbl); | ||
Local<String> cmp_str = n->ToString(context).ToLocalChecked(); | ||
if (!p_str->Equals(context, cmp_str).FromJust()) { | ||
return false; | ||
} | ||
if (n_dbl == 0 && std::signbit(n_dbl) == false) { | ||
return true; | ||
} | ||
Local<Integer> cmp_integer; | ||
if (!n->ToInteger(context).ToLocal(&cmp_integer)) { | ||
return false; | ||
} | ||
return n_dbl > 0 && n_dbl < (2 ^ 32) - 1; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was building node with clang-11, and saw this:
I think the warning as well as the suggestion of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for catching the JavaScript'ism here - PR welcome, otherwise I will include a fix in my upcoming PR in this file. | ||
} | ||
| ||
Maybe<URL> ResolveExportsTarget(Environment* env, | ||
const URL& pjson_url, | ||
Local<Value> target, | ||
| @@ -953,44 +972,50 @@ Maybe<URL> ResolveExportsTarget(Environment* env, | |
return Nothing<URL>(); | ||
} else if (target->IsObject()) { | ||
Local<Object> target_obj = target.As<Object>(); | ||
bool matched = false; | ||
Local<Array> target_obj_keys = | ||
target_obj->GetOwnPropertyNames(context).ToLocalChecked(); | ||
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()) { | ||
ProcessEmitExperimentalWarning(env, "Conditional exports"); | ||
return resolved; | ||
bool matched = false; | ||
for (uint32_t i = 0; i < target_obj_keys->Length(); ++i) { | ||
Local<Value> key = | ||
target_obj_keys->Get(context, i).ToLocalChecked(); | ||
if (IsArrayIndex(env, key)) { | ||
const std::string msg = "Invalid package config for " + | ||
pjson_url.ToFilePath() + ", \"exports\" cannot contain numeric " + | ||
"property keys."; | ||
node::THROW_ERR_INVALID_PACKAGE_CONFIG(env, msg.c_str()); | ||
return Nothing<URL>(); | ||
} | ||
} | ||
if (env->options()->experimental_conditional_exports && | ||
target_obj->HasOwnProperty(context, env->import_string()).FromJust()) { | ||
matched = true; | ||
conditionalTarget = | ||
target_obj->Get(context, env->import_string()).ToLocalChecked(); | ||
Maybe<URL> resolved = ResolveExportsTarget(env, pjson_url, | ||
for (uint32_t i = 0; i < target_obj_keys->Length(); ++i) { | ||
Local<Value> key = target_obj_keys->Get(context, i).ToLocalChecked(); | ||
Utf8Value key_utf8(env->isolate(), | ||
key->ToString(context).ToLocalChecked()); | ||
std::string key_str(*key_utf8, key_utf8.length()); | ||
if (key_str == "node" || key_str == "import") { | ||
if (!env->options()->experimental_conditional_exports) continue; | ||
matched = true; | ||
conditionalTarget = target_obj->Get(context, key).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, | ||
if (!resolved.IsNothing()) { | ||
ProcessEmitExperimentalWarning(env, "Conditional exports"); | ||
return resolved; | ||
} | ||
} else if (key_str == "default") { | ||
matched = true; | ||
conditionalTarget = target_obj->Get(context, key).ToLocalChecked(); | ||
Maybe<URL> resolved = ResolveExportsTarget(env, pjson_url, | ||
conditionalTarget, subpath, pkg_subpath, base, false); | ||
if (!resolved.IsNothing()) { | ||
return resolved; | ||
if (!resolved.IsNothing()) { | ||
ProcessEmitExperimentalWarning(env, "Conditional exports"); | ||
return resolved; | ||
} | ||
} | ||
} | ||
if (matched && throw_invalid) { | ||
Maybe<URL> resolved = ResolveExportsTarget(env, pjson_url, | ||
conditionalTarget, subpath, pkg_subpath, base, true); | ||
conditionalTarget, subpath, pkg_subpath, base, true); | ||
CHECK(resolved.IsNothing()); | ||
return Nothing<URL>(); | ||
} | ||
| @@ -1013,8 +1038,8 @@ Maybe<bool> IsConditionalExportsMainSugar(Environment* env, | |
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); | ||
Local<Value> key = keys->Get(context, i).ToLocalChecked(); | ||
Utf8Value key_utf8(env->isolate(), key->ToString(context).ToLocalChecked()); | ||
bool curIsConditionalSugar = key_utf8.length() == 0 || key_utf8[0] != '.'; | ||
if (i == 0) { | ||
isConditionalSugar = curIsConditionalSugar; | ||
| @@ -1122,13 +1147,13 @@ Maybe<URL> PackageExportsResolve(Environment* env, | |
Local<Array> keys = | ||
exports_obj->GetOwnPropertyNames(context).ToLocalChecked(); | ||
for (uint32_t i = 0; i < keys->Length(); ++i) { | ||
Local<String> key = keys->Get(context, i).ToLocalChecked().As<String>(); | ||
Utf8Value key_utf8(isolate, key); | ||
Local<Value> key = keys->Get(context, i).ToLocalChecked(); | ||
Utf8Value key_utf8(isolate, key->ToString(context).ToLocalChecked()); | ||
std::string key_str(*key_utf8, key_utf8.length()); | ||
if (key_str.back() != '/') continue; | ||
if (pkg_subpath.substr(0, key_str.length()) == key_str && | ||
key_str.length() > best_match_str.length()) { | ||
best_match = key; | ||
best_match = key->ToString(context).ToLocalChecked(); | ||
best_match_str = key_str; | ||
} | ||
} | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Uh oh!
There was an error while loading. Please reload this page.