Skip to content

Commit 0fb446e

Browse files
aduh95targos
authored andcommitted
esm: do not interpret "main" as a URL
As documented, its value is a path. PR-URL: #55003 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
1 parent 0999b5e commit 0fb446e

File tree

3 files changed

+26
-46
lines changed

3 files changed

+26
-46
lines changed

lib/internal/modules/esm/resolve.js

+13-14
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const {
2222
StringPrototypeStartsWith,
2323
encodeURIComponent,
2424
} = primordials;
25+
const assert = require('internal/assert');
2526
const internalFS = require('internal/fs/utils');
2627
const { BuiltinModule } = require('internal/bootstrap/realm');
2728
const { realpathSync } = require('fs');
@@ -117,18 +118,17 @@ function emitInvalidSegmentDeprecation(target, request, match, pjsonUrl, interna
117118
* Emits a deprecation warning if the given URL is a module and
118119
* the package.json file does not define a "main" or "exports" field.
119120
* @param {URL} url - The URL of the module being resolved.
120-
* @param {URL} packageJSONUrl - The URL of the package.json file for the module.
121+
* @param {string} path - The path of the module being resolved.
122+
* @param {string} pkgPath - The path of the parent dir of the package.json file for the module.
121123
* @param {string | URL} [base] - The base URL for the module being resolved.
122124
* @param {string} [main] - The "main" field from the package.json file.
123125
*/
124-
function emitLegacyIndexDeprecation(url, packageJSONUrl, base, main) {
126+
function emitLegacyIndexDeprecation(url, path, pkgPath, base, main) {
125127
if (process.noDeprecation) {
126128
return;
127129
}
128130
const format = defaultGetFormatWithoutErrors(url);
129131
if (format !== 'module') { return; }
130-
const path = fileURLToPath(url);
131-
const pkgPath = fileURLToPath(new URL('.', packageJSONUrl));
132132
const basePath = fileURLToPath(base);
133133
if (!main) {
134134
process.emitWarning(
@@ -196,20 +196,19 @@ const legacyMainResolveExtensionsIndexes = {
196196
* @returns {URL}
197197
*/
198198
function legacyMainResolve(packageJSONUrl, packageConfig, base) {
199-
const packageJsonUrlString = packageJSONUrl.href;
200-
201-
if (typeof packageJsonUrlString !== 'string') {
202-
throw new ERR_INVALID_ARG_TYPE('packageJSONUrl', ['URL'], packageJSONUrl);
203-
}
199+
assert(isURL(packageJSONUrl));
200+
const pkgPath = fileURLToPath(new URL('.', packageJSONUrl));
204201

205202
const baseStringified = isURL(base) ? base.href : base;
206203

207-
const resolvedOption = FSLegacyMainResolve(packageJsonUrlString, packageConfig.main, baseStringified);
204+
const resolvedOption = FSLegacyMainResolve(pkgPath, packageConfig.main, baseStringified);
208205

209-
const baseUrl = resolvedOption <= legacyMainResolveExtensionsIndexes.kResolvedByMainIndexNode ? `./${packageConfig.main}` : '';
210-
const resolvedUrl = new URL(baseUrl + legacyMainResolveExtensions[resolvedOption], packageJSONUrl);
206+
const maybeMain = resolvedOption <= legacyMainResolveExtensionsIndexes.kResolvedByMainIndexNode ?
207+
packageConfig.main || './' : '';
208+
const resolvedPath = resolve(pkgPath, maybeMain + legacyMainResolveExtensions[resolvedOption]);
209+
const resolvedUrl = pathToFileURL(resolvedPath);
211210

212-
emitLegacyIndexDeprecation(resolvedUrl, packageJSONUrl, base, packageConfig.main);
211+
emitLegacyIndexDeprecation(resolvedUrl, resolvedPath, pkgPath, base, packageConfig.main);
213212

214213
return resolvedUrl;
215214
}
@@ -790,8 +789,8 @@ function packageResolve(specifier, base, conditions) {
790789
// ResolveSelf
791790
const packageConfig = packageJsonReader.getPackageScopeConfig(base);
792791
if (packageConfig.exists) {
793-
const packageJSONUrl = pathToFileURL(packageConfig.pjsonPath);
794792
if (packageConfig.exports != null && packageConfig.name === packageName) {
793+
const packageJSONUrl = pathToFileURL(packageConfig.pjsonPath);
795794
return packageExportsResolve(
796795
packageJSONUrl, packageSubpath, packageConfig, base, conditions);
797796
}

src/node_file.cc

+4-31
Original file line numberDiff line numberDiff line change
@@ -3236,37 +3236,18 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
32363236
Environment* env = Environment::GetCurrent(args);
32373237
auto isolate = env->isolate();
32383238

3239-
Utf8Value utf8_package_json_url(isolate, args[0]);
3240-
auto package_json_url =
3241-
ada::parse<ada::url_aggregator>(utf8_package_json_url.ToStringView());
3242-
3243-
if (!package_json_url) {
3244-
THROW_ERR_INVALID_URL(isolate, "Invalid URL");
3245-
return;
3246-
}
3239+
auto utf8_package_path = Utf8Value(isolate, args[0]).ToString();
32473240

32483241
std::string package_initial_file = "";
32493242

3250-
ada::result<ada::url_aggregator> file_path_url;
32513243
std::optional<std::string> initial_file_path;
32523244
std::string file_path;
32533245

32543246
if (args.Length() >= 2 && args[1]->IsString()) {
32553247
auto package_config_main = Utf8Value(isolate, args[1]).ToString();
32563248

3257-
file_path_url = ada::parse<ada::url_aggregator>(
3258-
std::string("./") + package_config_main, &package_json_url.value());
3259-
3260-
if (!file_path_url) {
3261-
THROW_ERR_INVALID_URL(isolate, "Invalid URL");
3262-
return;
3263-
}
3264-
3265-
initial_file_path = node::url::FileURLToPath(env, *file_path_url);
3266-
if (!initial_file_path.has_value()) {
3267-
return;
3268-
}
3269-
3249+
initial_file_path =
3250+
PathResolve(env, {utf8_package_path, package_config_main});
32703251
FromNamespacedPath(&initial_file_path.value());
32713252

32723253
package_initial_file = *initial_file_path;
@@ -3297,15 +3278,7 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
32973278
}
32983279
}
32993280

3300-
file_path_url =
3301-
ada::parse<ada::url_aggregator>("./index", &package_json_url.value());
3302-
3303-
if (!file_path_url) {
3304-
THROW_ERR_INVALID_URL(isolate, "Invalid URL");
3305-
return;
3306-
}
3307-
3308-
initial_file_path = node::url::FileURLToPath(env, *file_path_url);
3281+
initial_file_path = PathResolve(env, {utf8_package_path, "./index"});
33093282
if (!initial_file_path.has_value()) {
33103283
return;
33113284
}

test/es-module/test-cjs-legacyMainResolve.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ describe('legacyMainResolve', () => {
8282
{},
8383
''
8484
),
85-
{ message: /instance of URL/, code: 'ERR_INVALID_ARG_TYPE' },
85+
{ code: 'ERR_INTERNAL_ASSERTION' },
8686
);
8787
});
8888

@@ -166,4 +166,12 @@ describe('legacyMainResolve', () => {
166166
{ message: /"base" argument must be/, code: 'ERR_INVALID_ARG_TYPE' },
167167
);
168168
});
169+
170+
it('should interpret main as a path, not a URL', () => {
171+
const packageJsonUrl = fixtures.fileURL('/es-modules/legacy-main-resolver/package.json');
172+
assert.deepStrictEqual(
173+
legacyMainResolve(packageJsonUrl, { main: '../folder%25with percentage#/' }, packageJsonUrl),
174+
fixtures.fileURL('/es-modules/folder%25with percentage#/index.js'),
175+
);
176+
});
169177
});

0 commit comments

Comments
 (0)