Skip to content

Commit 7f1c83e

Browse files
meixgsxa
authored andcommitted
loader: fix esm resolve for symlink file
Fix: #42195 PR-URL: #42197 Fixes: #42195 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Geoffrey Booth <[email protected]>
1 parent 05c3ff5 commit 7f1c83e

File tree

2 files changed

+55
-9
lines changed

2 files changed

+55
-9
lines changed

β€Žlib/internal/modules/esm/resolve.js

+15-9
Original file line numberDiff line numberDiff line change
@@ -374,18 +374,24 @@ function finalizeResolution(resolved, base, preserveSymlinks) {
374374
resolved.pathname, 'must not include encoded "/" or "\\" characters',
375375
fileURLToPath(base));
376376

377-
const path = fileURLToPath(resolved);
377+
let path = fileURLToPath(resolved);
378378
if (getOptionValue('--experimental-specifier-resolution') === 'node') {
379379
let file = resolveExtensionsWithTryExactName(resolved);
380-
if (file !== undefined) return file;
381-
if (!StringPrototypeEndsWith(path, '/')) {
382-
file = resolveDirectoryEntry(new URL(`${resolved}/`));
383-
if (file !== undefined) return file;
384-
} else {
385-
return resolveDirectoryEntry(resolved) || resolved;
380+
381+
// Directory
382+
if (file === undefined) {
383+
file = StringPrototypeEndsWith(path, '/') ?
384+
(resolveDirectoryEntry(resolved) || resolved) : resolveDirectoryEntry(new URL(`${resolved}/`));
385+
386+
if (file === resolved) return file;
387+
388+
if (file === undefined) {
389+
throw new ERR_MODULE_NOT_FOUND(
390+
resolved.pathname, fileURLToPath(base), 'module');
391+
}
386392
}
387-
throw new ERR_MODULE_NOT_FOUND(
388-
resolved.pathname, fileURLToPath(base), 'module');
393+
394+
path = file;
389395
}
390396

391397
const stats = tryStatSync(StringPrototypeEndsWith(path, '/') ?
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import * as common from '../common/index.mjs';
2+
import path from 'path';
3+
import fs from 'fs/promises';
4+
import tmpdir from '../common/tmpdir.js';
5+
import { spawn } from 'child_process';
6+
import assert from 'assert';
7+
8+
tmpdir.refresh();
9+
const tmpDir = tmpdir.path;
10+
11+
// Create the following file structure:
12+
// β”œβ”€β”€ index.mjs
13+
// β”œβ”€β”€ subfolder
14+
// β”‚ β”œβ”€β”€ index.mjs
15+
// β”‚ └── node_modules
16+
// β”‚ └── package-a
17+
// β”‚ └── index.mjs
18+
// └── symlink.mjs -> ./subfolder/index.mjs
19+
const entry = path.join(tmpDir, 'index.mjs');
20+
const symlink = path.join(tmpDir, 'symlink.mjs');
21+
const real = path.join(tmpDir, 'subfolder', 'index.mjs');
22+
const packageDir = path.join(tmpDir, 'subfolder', 'node_modules', 'package-a');
23+
const packageEntry = path.join(packageDir, 'index.mjs');
24+
try {
25+
await fs.symlink(real, symlink);
26+
} catch (err) {
27+
if (err.code !== 'EPERM') throw err;
28+
common.skip('insufficient privileges for symlinks');
29+
}
30+
await fs.mkdir(packageDir, { recursive: true });
31+
await Promise.all([
32+
fs.writeFile(entry, 'import "./symlink.mjs";'),
33+
fs.writeFile(real, 'export { a } from "package-a/index.mjs"'),
34+
fs.writeFile(packageEntry, 'export const a = 1;'),
35+
]);
36+
37+
spawn(process.execPath, ['--experimental-specifier-resolution=node', entry],
38+
{ stdio: 'inherit' }).on('exit', common.mustCall((code) => {
39+
assert.strictEqual(code, 0);
40+
}));

0 commit comments

Comments
Β (0)