diff --git a/napi/__test__/resolver.spec.mjs b/napi/__test__/resolver.spec.mjs index f17dd294..450324db 100644 --- a/napi/__test__/resolver.spec.mjs +++ b/napi/__test__/resolver.spec.mjs @@ -1,4 +1,4 @@ -import { join, sep } from 'node:path' +import path, { join } from 'node:path' import { fileURLToPath } from 'node:url' import test from 'ava' @@ -217,7 +217,7 @@ for (const [title, context, request, expected] of [ 'handle fragment escaping', enhancedResolveRoot, './no\0#fragment/\0#/\0##fragment', - join(enhancedResolveRoot, 'no#fragment','#', '#.js#fragment'), + join(enhancedResolveRoot, 'no#fragment', '#', '#.js#fragment'), ], ]) { test(title, (t) => { @@ -229,3 +229,31 @@ for (const [title, context, request, expected] of [ t.is(resolver.sync(context, request).path, expected) }) } + +test('resolve pnpm package', (t) => { + const pnpmProjectPath = join(currentDir, '..', '..', 'fixtures', 'pnpm8') + const resolver = new ResolverFactory({ + aliasFields: ['browser'], + }) + t.deepEqual(resolver.sync(pnpmProjectPath, 'styled-components'), { + path: join( + pnpmProjectPath, + 'node_modules/.pnpm/styled-components@6.1.1_react-dom@18.2.0_react@18.2.0/node_modules/styled-components/dist/styled-components.browser.cjs.js' + ), + }) + t.deepEqual( + resolver.sync( + join( + pnpmProjectPath, + 'node_modules/.pnpm/styled-components@6.1.1_react-dom@18.2.0_react@18.2.0/node_modules/styled-components' + ), + 'react' + ), + { + path: join( + pnpmProjectPath, + 'node_modules/.pnpm/react@18.2.0/node_modules/react/index.js' + ), + } + ) +}) diff --git a/src/file_system.rs b/src/file_system.rs index 95c504ef..f67fc7d0 100644 --- a/src/file_system.rs +++ b/src/file_system.rs @@ -91,6 +91,32 @@ impl FileSystem for FileSystemOs { } fn canonicalize(&self, path: &Path) -> io::Result { - dunce::canonicalize(path) + #[cfg(not(target_os = "wasi"))] + { + dunce::canonicalize(path) + } + #[cfg(target_os = "wasi")] + { + let meta = fs::symlink_metadata(path)?; + if meta.file_type().is_symlink() { + let link = fs::read_link(path)?; + let mut path_buf = path.to_path_buf(); + path_buf.pop(); + for segment in link.iter() { + match segment.to_str() { + Some("..") => { + path_buf.pop(); + } + Some(".") | None => {} + Some(seg) => { + path_buf.push(seg.trim_end_matches('\0')); + } + } + } + Ok(path_buf) + } else { + Ok(path.to_path_buf()) + } + } } }