diff options
author | Guy Bedford <guybedford@gmail.com> | 2019-12-17 22:00:21 +0300 |
---|---|---|
committer | Guy Bedford <guybedford@gmail.com> | 2020-01-07 07:14:19 +0300 |
commit | 405e7b45575ef39264067e68ee4ef5db466eebb2 (patch) | |
tree | eb2f9c07560b372ea24f6de78a49812c54d4d208 /src/module_wrap.cc | |
parent | 2551a21553d06e85790bdc96c6f1d528d0695d76 (diff) |
module: logical conditional exports ordering
PR-URL: https://github.com/nodejs/node/pull/31008
Reviewed-By: Bradley Farias <bradley.meck@gmail.com>
Reviewed-By: Jan Krems <jan.krems@gmail.com>
Diffstat (limited to 'src/module_wrap.cc')
-rw-r--r-- | src/module_wrap.cc | 94 |
1 files changed, 59 insertions, 35 deletions
diff --git a/src/module_wrap.cc b/src/module_wrap.cc index 74eacf198f7..ff6f0db651a 100644 --- a/src/module_wrap.cc +++ b/src/module_wrap.cc @@ -12,7 +12,6 @@ #include <sys/stat.h> // S_IFDIR #include <algorithm> -#include <climits> // PATH_MAX namespace node { namespace loader { @@ -908,6 +907,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; +} + Maybe<URL> ResolveExportsTarget(Environment* env, const URL& pjson_url, Local<Value> target, @@ -953,44 +971,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 +1037,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 +1146,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; } } |