fix_allow_passing_fileexists_fn_to_legacymainresolve.patch 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
  2. From: Shelley Vohr <[email protected]>
  3. Date: Sat, 17 Feb 2024 22:17:13 -0800
  4. Subject: fix: allow passing fileExists fn to legacyMainResolve
  5. This switch to native legacyMainResolve doesn't take asar into account, and can
  6. cause errors when a project using ESM and asar tries to load a dependency which
  7. uses commonJS.
  8. We can fix this by allowing the C++ implementation of legacyMainResolve to use
  9. a fileExists function that does take Asar into account.
  10. diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js
  11. index 2879e5cf541fb4d226cfd7cc0fe367ca448fb926..03082f0ec4f91382933eec48e77331cdf6f04943 100644
  12. --- a/lib/internal/modules/esm/resolve.js
  13. +++ b/lib/internal/modules/esm/resolve.js
  14. @@ -28,14 +28,13 @@ const { BuiltinModule } = require('internal/bootstrap/realm');
  15. const fs = require('fs');
  16. const { getOptionValue } = require('internal/options');
  17. // Do not eagerly grab .manifest, it may be in TDZ
  18. -const { sep, posix: { relative: relativePosixPath }, resolve } = require('path');
  19. +const { sep, posix: { relative: relativePosixPath }, toNamespacedPath, resolve } = require('path');
  20. const preserveSymlinks = getOptionValue('--preserve-symlinks');
  21. const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main');
  22. const inputTypeFlag = getOptionValue('--input-type');
  23. -const { URL, pathToFileURL, fileURLToPath, isURL, URLParse } = require('internal/url');
  24. +const { URL, pathToFileURL, fileURLToPath, isURL, URLParse, toPathIfFileURL } = require('internal/url');
  25. const { getCWDURL, setOwnProperty } = require('internal/util');
  26. const { canParse: URLCanParse } = internalBinding('url');
  27. -const { legacyMainResolve: FSLegacyMainResolve } = internalBinding('fs');
  28. const {
  29. ERR_INPUT_TYPE_NOT_ALLOWED,
  30. ERR_INVALID_ARG_TYPE,
  31. @@ -183,6 +182,11 @@ const legacyMainResolveExtensionsIndexes = {
  32. kResolvedByPackageAndNode: 9,
  33. };
  34. +function fileExists(url) {
  35. + const namespaced = toNamespacedPath(toPathIfFileURL(url));
  36. + return internalFsBinding.internalModuleStat(internalFsBinding, namespaced) === 0;
  37. +}
  38. +
  39. /**
  40. * Legacy CommonJS main resolution:
  41. * 1. let M = pkg_url + (json main field)
  42. @@ -201,7 +205,7 @@ function legacyMainResolve(packageJSONUrl, packageConfig, base) {
  43. const baseStringified = isURL(base) ? base.href : base;
  44. - const resolvedOption = FSLegacyMainResolve(pkgPath, packageConfig.main, baseStringified);
  45. + const resolvedOption = internalFsBinding.legacyMainResolve(pkgPath, packageConfig.main, baseStringified, fileExists);
  46. const maybeMain = resolvedOption <= legacyMainResolveExtensionsIndexes.kResolvedByMainIndexNode ?
  47. packageConfig.main || './' : '';
  48. diff --git a/src/node_file.cc b/src/node_file.cc
  49. index 1d22e19f16d5ad82466b0724971b2e4a685682f7..9619d10710ffbbdc73fa7d59d1b797c8d0b3a956 100644
  50. --- a/src/node_file.cc
  51. +++ b/src/node_file.cc
  52. @@ -3220,13 +3220,25 @@ static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) {
  53. }
  54. BindingData::FilePathIsFileReturnType BindingData::FilePathIsFile(
  55. - Environment* env, const std::string& file_path) {
  56. + Environment* env, const std::string& file_path, v8::Local<v8::Function> is_file_function) {
  57. THROW_IF_INSUFFICIENT_PERMISSIONS(
  58. env,
  59. permission::PermissionScope::kFileSystemRead,
  60. file_path,
  61. BindingData::FilePathIsFileReturnType::kThrowInsufficientPermissions);
  62. + if (!is_file_function.IsEmpty()) {
  63. + v8::Local<v8::Value> argv[] = {v8::String::NewFromUtf8(
  64. + env->isolate(), file_path.c_str(), v8::NewStringType::kNormal)
  65. + .ToLocalChecked()};
  66. + MaybeLocal<Value> maybe_is_file = is_file_function->Call(env->context(), v8::Undefined(env->isolate()), 1, argv);
  67. + if (maybe_is_file.IsEmpty()) {
  68. + bool is_file = maybe_is_file.ToLocalChecked()->BooleanValue(env->isolate());
  69. + return is_file ? BindingData::FilePathIsFileReturnType::kIsFile
  70. + : BindingData::FilePathIsFileReturnType::kIsNotFile;
  71. + }
  72. + }
  73. +
  74. uv_fs_t req;
  75. int rc = uv_fs_stat(env->event_loop(), &req, file_path.c_str(), nullptr);
  76. @@ -3284,6 +3296,11 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
  77. std::optional<std::string> initial_file_path;
  78. std::string file_path;
  79. + v8::Local<v8::Function> is_file_function;
  80. + if (args.Length() >= 3 && args[3]->IsFunction()) {
  81. + is_file_function = args[3].As<v8::Function>();
  82. + }
  83. +
  84. if (args.Length() >= 2 && args[1]->IsString()) {
  85. auto package_config_main = Utf8Value(isolate, args[1]).ToString();
  86. @@ -3304,7 +3321,7 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
  87. BufferValue buff_file_path(isolate, local_file_path);
  88. ToNamespacedPath(env, &buff_file_path);
  89. - switch (FilePathIsFile(env, buff_file_path.ToString())) {
  90. + switch (FilePathIsFile(env, buff_file_path.ToString(), is_file_function)) {
  91. case BindingData::FilePathIsFileReturnType::kIsFile:
  92. return args.GetReturnValue().Set(i);
  93. case BindingData::FilePathIsFileReturnType::kIsNotFile:
  94. @@ -3341,7 +3358,7 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
  95. BufferValue buff_file_path(isolate, local_file_path);
  96. ToNamespacedPath(env, &buff_file_path);
  97. - switch (FilePathIsFile(env, buff_file_path.ToString())) {
  98. + switch (FilePathIsFile(env, buff_file_path.ToString(), is_file_function)) {
  99. case BindingData::FilePathIsFileReturnType::kIsFile:
  100. return args.GetReturnValue().Set(i);
  101. case BindingData::FilePathIsFileReturnType::kIsNotFile:
  102. diff --git a/src/node_file.h b/src/node_file.h
  103. index bdad1ae25f4892cbbfd8cc30c4d8b4a6f600edbc..099488319f53bc7718313d6e30df2237cad6771d 100644
  104. --- a/src/node_file.h
  105. +++ b/src/node_file.h
  106. @@ -101,7 +101,8 @@ class BindingData : public SnapshotableObject {
  107. InternalFieldInfo* internal_field_info_ = nullptr;
  108. static FilePathIsFileReturnType FilePathIsFile(Environment* env,
  109. - const std::string& file_path);
  110. + const std::string& file_path,
  111. + v8::Local<v8::Function> is_file_function = v8::Local<v8::Function>());
  112. };
  113. // structure used to store state during a complex operation, e.g., mkdirp.