module: fix `--preserve-symlinks-main`

Fixes resolving main module when the `argv[1]` was pointing to a symlink
without its file extension.

PR-URL: https://github.com/nodejs/node/pull/51312
Fixes: https://github.com/nodejs/node/issues/41000
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
pull/51432/head
per4uk 2024-01-10 22:26:07 +00:00 committed by GitHub
parent e0b159ee82
commit d0e455044e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 49 additions and 30 deletions

View File

@ -469,15 +469,15 @@ function tryPackage(requestPath, exts, isMain, originalPath) {
} }
/** /**
* Check if the file exists and is not a directory if using `--preserve-symlinks` and `isMain` is false, keep symlinks * Check if the file exists and is not a directory if using `--preserve-symlinks` and `isMain` is false or
* intact, otherwise resolve to the absolute realpath. * `--preserve-symlinks-main` and `isMain` is true , keep symlinks intact, otherwise resolve to the absolute realpath.
* @param {string} requestPath The path to the file to load. * @param {string} requestPath The path to the file to load.
* @param {boolean} isMain Whether the file is the main module. * @param {boolean} isMain Whether the file is the main module.
*/ */
function tryFile(requestPath, isMain) { function tryFile(requestPath, isMain) {
const rc = _stat(requestPath); const rc = _stat(requestPath);
if (rc !== 0) { return; } if (rc !== 0) { return; }
if (getOptionValue('--preserve-symlinks') && !isMain) { if (getOptionValue(isMain ? '--preserve-symlinks-main' : '--preserve-symlinks')) {
return path.resolve(requestPath); return path.resolve(requestPath);
} }
return toRealPath(requestPath); return toRealPath(requestPath);

View File

@ -1,12 +1,19 @@
'use strict'; 'use strict';
const common = require('../common'); const { spawnPromisified, skip } = require('../common');
const { spawn } = require('child_process');
const assert = require('assert');
const path = require('path');
const fs = require('fs');
const tmpdir = require('../common/tmpdir'); const tmpdir = require('../common/tmpdir');
// Invoke the main file via a symlink. In this case --preserve-symlinks-main
// dictates that it'll resolve relative imports in the main file relative to
// the symlink, and not relative to the symlink target; the file structure set
// up below requires this to not crash when loading ./submodule_link.js
const assert = require('node:assert');
const fs = require('node:fs');
const path = require('node:path');
const { execPath } = require('node:process');
const { describe, it } = require('node:test');
tmpdir.refresh(); tmpdir.refresh();
const tmpDir = tmpdir.path; const tmpDir = tmpdir.path;
@ -14,7 +21,7 @@ fs.mkdirSync(path.join(tmpDir, 'nested'));
fs.mkdirSync(path.join(tmpDir, 'nested2')); fs.mkdirSync(path.join(tmpDir, 'nested2'));
const entry = path.join(tmpDir, 'nested', 'entry.js'); const entry = path.join(tmpDir, 'nested', 'entry.js');
const entry_link_absolute_path = path.join(tmpDir, 'link.js'); const entry_link_absolute_path = path.join(tmpDir, 'index.js');
const submodule = path.join(tmpDir, 'nested2', 'submodule.js'); const submodule = path.join(tmpDir, 'nested2', 'submodule.js');
const submodule_link_absolute_path = path.join(tmpDir, 'submodule_link.js'); const submodule_link_absolute_path = path.join(tmpDir, 'submodule_link.js');
@ -31,27 +38,39 @@ try {
fs.symlinkSync(submodule, submodule_link_absolute_path); fs.symlinkSync(submodule, submodule_link_absolute_path);
} catch (err) { } catch (err) {
if (err.code !== 'EPERM') throw err; if (err.code !== 'EPERM') throw err;
common.skip('insufficient privileges for symlinks'); skip('insufficient privileges for symlinks');
} }
function doTest(flags, done) { describe('Invoke the main file via a symlink.', { concurrency: true }, () => {
// Invoke the main file via a symlink. In this case --preserve-symlinks-main it('should resolve relative imports in the main file', async () => {
// dictates that it'll resolve relative imports in the main file relative to const { code } = await spawnPromisified(execPath, [
// the symlink, and not relative to the symlink target; the file structure set '--preserve-symlinks',
// up above requires this to not crash when loading ./submodule_link.js '--preserve-symlinks-main',
spawn(process.execPath, [ entry_link_absolute_path,
'--preserve-symlinks', ]);
'--preserve-symlinks-main',
entry_link_absolute_path,
], { stdio: 'inherit' })
.on('exit', (code) => {
assert.strictEqual(code, 0);
done();
});
}
// First test the commonjs module loader assert.strictEqual(code, 0);
doTest([], () => { });
// Now test the new loader
doTest([], () => {}); it('should resolve relative imports in the main file when file extension is omitted', async () => {
const entry_link_absolute_path_without_ext = path.join(tmpDir, 'index');
const { code } = await spawnPromisified(execPath, [
'--preserve-symlinks',
'--preserve-symlinks-main',
entry_link_absolute_path_without_ext,
]);
assert.strictEqual(code, 0);
});
it('should resolve relative imports in the main file when filename(index.js) is omitted', async () => {
const { code } = await spawnPromisified(execPath, [
'--preserve-symlinks',
'--preserve-symlinks-main',
tmpDir,
]);
assert.strictEqual(code, 0);
});
}); });