1212#include < sys/stat.h> // S_IFDIR
1313
1414#include < algorithm>
15- #include < climits> // PATH_MAX
1615
1716namespace node {
1817namespace loader {
@@ -908,6 +907,25 @@ Maybe<URL> ResolveExportsTargetString(Environment* env,
908907 return Just (subpath_resolved);
909908}
910909
910+ bool IsArrayIndex (Environment* env, Local<Value> p) {
911+ Local<Context> context = env->context ();
912+ Local<String> p_str = p->ToString (context).ToLocalChecked ();
913+ double n_dbl = static_cast <double >(p_str->NumberValue (context).FromJust ());
914+ Local<Number> n = Number::New (env->isolate (), n_dbl);
915+ Local<String> cmp_str = n->ToString (context).ToLocalChecked ();
916+ if (!p_str->Equals (context, cmp_str).FromJust ()) {
917+ return false ;
918+ }
919+ if (n_dbl == 0 && std::signbit (n_dbl) == false ) {
920+ return true ;
921+ }
922+ Local<Integer> cmp_integer;
923+ if (!n->ToInteger (context).ToLocal (&cmp_integer)) {
924+ return false ;
925+ }
926+ return n_dbl > 0 && n_dbl < (2 ^ 32 ) - 1 ;
927+ }
928+
911929Maybe<URL> ResolveExportsTarget (Environment* env,
912930 const URL& pjson_url,
913931 Local<Value> target,
@@ -953,44 +971,50 @@ Maybe<URL> ResolveExportsTarget(Environment* env,
953971 return Nothing<URL>();
954972 } else if (target->IsObject ()) {
955973 Local<Object> target_obj = target.As <Object>();
956- bool matched = false ;
974+ Local<Array> target_obj_keys =
975+ target_obj->GetOwnPropertyNames (context).ToLocalChecked ();
957976 Local<Value> conditionalTarget;
958- if (env-> options ()-> experimental_conditional_exports &&
959- target_obj-> HasOwnProperty (context, env-> node_string ()). FromJust () ) {
960- matched = true ;
961- conditionalTarget =
962- target_obj-> Get (context, env-> node_string ()). ToLocalChecked ();
963- Maybe<URL> resolved = ResolveExportsTarget (env, pjson_url,
964- conditionalTarget, subpath, pkg_subpath, base, false );
965- if (!resolved. IsNothing ()) {
966- ProcessEmitExperimentalWarning (env, " Conditional exports " );
967- return resolved ;
977+ bool matched = false ;
978+ for ( uint32_t i = 0 ; i < target_obj_keys-> Length (); ++i ) {
979+ Local<Value> key =
980+ target_obj_keys-> Get (context, i). ToLocalChecked ();
981+ if ( IsArrayIndex (env, key)) {
982+ const std::string msg = " Invalid package config for " +
983+ pjson_url. ToFilePath () + " , \" exports \" cannot contain numeric " +
984+ " property keys. " ;
985+ node::THROW_ERR_INVALID_PACKAGE_CONFIG (env, msg. c_str () );
986+ return Nothing<URL>() ;
968987 }
969988 }
970- if (env->options ()->experimental_conditional_exports &&
971- target_obj->HasOwnProperty (context, env->import_string ()).FromJust ()) {
972- matched = true ;
973- conditionalTarget =
974- target_obj->Get (context, env->import_string ()).ToLocalChecked ();
975- Maybe<URL> resolved = ResolveExportsTarget (env, pjson_url,
989+ for (uint32_t i = 0 ; i < target_obj_keys->Length (); ++i) {
990+ Local<Value> key = target_obj_keys->Get (context, i).ToLocalChecked ();
991+ Utf8Value key_utf8 (env->isolate (),
992+ key->ToString (context).ToLocalChecked ());
993+ std::string key_str (*key_utf8, key_utf8.length ());
994+ if (key_str == " node" || key_str == " import" ) {
995+ if (!env->options ()->experimental_conditional_exports ) continue ;
996+ matched = true ;
997+ conditionalTarget = target_obj->Get (context, key).ToLocalChecked ();
998+ Maybe<URL> resolved = ResolveExportsTarget (env, pjson_url,
976999 conditionalTarget, subpath, pkg_subpath, base, false );
977- if (!resolved.IsNothing ()) {
978- return resolved;
979- }
980- }
981- if (target_obj->HasOwnProperty (context, env->default_string ()).FromJust ()) {
982- matched = true ;
983- conditionalTarget =
984- target_obj->Get (context, env->default_string ()).ToLocalChecked ();
985- Maybe<URL> resolved = ResolveExportsTarget (env, pjson_url,
1000+ if (!resolved.IsNothing ()) {
1001+ ProcessEmitExperimentalWarning (env, " Conditional exports" );
1002+ return resolved;
1003+ }
1004+ } else if (key_str == " default" ) {
1005+ matched = true ;
1006+ conditionalTarget = target_obj->Get (context, key).ToLocalChecked ();
1007+ Maybe<URL> resolved = ResolveExportsTarget (env, pjson_url,
9861008 conditionalTarget, subpath, pkg_subpath, base, false );
987- if (!resolved.IsNothing ()) {
988- return resolved;
1009+ if (!resolved.IsNothing ()) {
1010+ ProcessEmitExperimentalWarning (env, " Conditional exports" );
1011+ return resolved;
1012+ }
9891013 }
9901014 }
9911015 if (matched && throw_invalid) {
9921016 Maybe<URL> resolved = ResolveExportsTarget (env, pjson_url,
993- conditionalTarget, subpath, pkg_subpath, base, true );
1017+ conditionalTarget, subpath, pkg_subpath, base, true );
9941018 CHECK (resolved.IsNothing ());
9951019 return Nothing<URL>();
9961020 }
@@ -1013,8 +1037,8 @@ Maybe<bool> IsConditionalExportsMainSugar(Environment* env,
10131037 exports_obj->GetOwnPropertyNames (context).ToLocalChecked ();
10141038 bool isConditionalSugar = false ;
10151039 for (uint32_t i = 0 ; i < keys->Length (); ++i) {
1016- Local<String > key = keys->Get (context, i).ToLocalChecked (). As <String> ();
1017- Utf8Value key_utf8 (env->isolate (), key);
1040+ Local<Value > key = keys->Get (context, i).ToLocalChecked ();
1041+ Utf8Value key_utf8 (env->isolate (), key-> ToString (context). ToLocalChecked () );
10181042 bool curIsConditionalSugar = key_utf8.length () == 0 || key_utf8[0 ] != ' .' ;
10191043 if (i == 0 ) {
10201044 isConditionalSugar = curIsConditionalSugar;
@@ -1122,13 +1146,13 @@ Maybe<URL> PackageExportsResolve(Environment* env,
11221146 Local<Array> keys =
11231147 exports_obj->GetOwnPropertyNames (context).ToLocalChecked ();
11241148 for (uint32_t i = 0 ; i < keys->Length (); ++i) {
1125- Local<String > key = keys->Get (context, i).ToLocalChecked (). As <String> ();
1126- Utf8Value key_utf8 (isolate, key);
1149+ Local<Value > key = keys->Get (context, i).ToLocalChecked ();
1150+ Utf8Value key_utf8 (isolate, key-> ToString (context). ToLocalChecked () );
11271151 std::string key_str (*key_utf8, key_utf8.length ());
11281152 if (key_str.back () != ' /' ) continue ;
11291153 if (pkg_subpath.substr (0 , key_str.length ()) == key_str &&
11301154 key_str.length () > best_match_str.length ()) {
1131- best_match = key;
1155+ best_match = key-> ToString (context). ToLocalChecked () ;
11321156 best_match_str = key_str;
11331157 }
11341158 }
0 commit comments