mirror of
https://github.com/danbulant/oxc
synced 2026-05-20 20:58:48 +00:00
feat(resolver): check for node.js core modules (#794)
This commit is contained in:
parent
1bc1418ee6
commit
3d8ee2567f
7 changed files with 191 additions and 9 deletions
|
|
@ -31,7 +31,7 @@ fn data() -> Vec<(PathBuf, &'static str)> {
|
|||
(cwd.join("test/fixtures"), "m1/a.js?query#fragment"),
|
||||
// extensions
|
||||
(cwd.join("test/fixtures/extensions"), "./foo"),
|
||||
(cwd.join("test/fixtures/extensions/module"), "module"),
|
||||
(cwd.join("test/fixtures/extensions/module"), "module/"),
|
||||
// browserField
|
||||
(cwd.join("test/fixtures/browser-module"), "./lib/replaced"),
|
||||
(cwd.join("test/fixtures/browser-module/lib"), "./replaced"),
|
||||
|
|
|
|||
69
crates/oxc_resolver/src/builtins.rs
Normal file
69
crates/oxc_resolver/src/builtins.rs
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
// <https://nodejs.org/api/modules.html#core-modules>
|
||||
// node -p "[...require('module').builtinModules].map(b => JSON.stringify(b)).join(',\n')"
|
||||
pub const BUILTINS: &[&str] = &[
|
||||
"_http_agent",
|
||||
"_http_client",
|
||||
"_http_common",
|
||||
"_http_incoming",
|
||||
"_http_outgoing",
|
||||
"_http_server",
|
||||
"_stream_duplex",
|
||||
"_stream_passthrough",
|
||||
"_stream_readable",
|
||||
"_stream_transform",
|
||||
"_stream_wrap",
|
||||
"_stream_writable",
|
||||
"_tls_common",
|
||||
"_tls_wrap",
|
||||
"assert",
|
||||
"assert/strict",
|
||||
"async_hooks",
|
||||
"buffer",
|
||||
"child_process",
|
||||
"cluster",
|
||||
"console",
|
||||
"constants",
|
||||
"crypto",
|
||||
"dgram",
|
||||
"diagnostics_channel",
|
||||
"dns",
|
||||
"dns/promises",
|
||||
"domain",
|
||||
"events",
|
||||
"fs",
|
||||
"fs/promises",
|
||||
"http",
|
||||
"http2",
|
||||
"https",
|
||||
"inspector",
|
||||
"module",
|
||||
"net",
|
||||
"os",
|
||||
"path",
|
||||
"path/posix",
|
||||
"path/win32",
|
||||
"perf_hooks",
|
||||
"process",
|
||||
"punycode",
|
||||
"querystring",
|
||||
"readline",
|
||||
"repl",
|
||||
"stream",
|
||||
"stream/consumers",
|
||||
"stream/promises",
|
||||
"stream/web",
|
||||
"string_decoder",
|
||||
"sys",
|
||||
"timers",
|
||||
"timers/promises",
|
||||
"tls",
|
||||
"trace_events",
|
||||
"tty",
|
||||
"url",
|
||||
"util",
|
||||
"util/types",
|
||||
"v8",
|
||||
"vm",
|
||||
"worker_threads",
|
||||
"zlib",
|
||||
];
|
||||
|
|
@ -19,6 +19,12 @@ pub enum ResolveError {
|
|||
/// Path not found
|
||||
NotFound(PathBuf),
|
||||
|
||||
/// Node.js builtin modules
|
||||
///
|
||||
/// This is an error due to not being a Node.js runtime.
|
||||
/// The `alias` option can be used to resolve a builtin module to a polyfill.
|
||||
Builtin(String),
|
||||
|
||||
/// All of the aliased extension are not found
|
||||
ExtensionAlias,
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
//! [ECMAScript Module Resolution Algorithm]: https://nodejs.org/api/esm.html#resolution-algorithm-specification
|
||||
//! [parcel-resolver]: https://github.com/parcel-bundler/parcel/blob/v2/packages/utils/node-resolver-rs
|
||||
|
||||
mod builtins;
|
||||
mod cache;
|
||||
mod error;
|
||||
mod file_system;
|
||||
|
|
@ -41,6 +42,7 @@ use std::{
|
|||
};
|
||||
|
||||
use crate::{
|
||||
builtins::BUILTINS,
|
||||
cache::{Cache, CachedPath},
|
||||
file_system::FileSystemOs,
|
||||
package_json::{ExportsField, ExportsKey, MatchObject},
|
||||
|
|
@ -190,8 +192,11 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
|
|||
}
|
||||
|
||||
/// require(X) from module at path Y
|
||||
///
|
||||
/// X: specifier
|
||||
/// Y: path
|
||||
///
|
||||
/// <https://nodejs.org/api/modules.html#all-together>
|
||||
fn require(
|
||||
&self,
|
||||
cached_path: &CachedPath,
|
||||
|
|
@ -218,9 +223,6 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
|
|||
}
|
||||
|
||||
match specifier.as_bytes()[0] {
|
||||
// 1. If X is a core module,
|
||||
// a. return the core module
|
||||
// b. STOP
|
||||
// 2. If X begins with '/'
|
||||
// a. set Y to be the file system root
|
||||
b'/' => self.require_absolute(cached_path, specifier, ctx),
|
||||
|
|
@ -228,13 +230,28 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
|
|||
b'.' => self.require_relative(cached_path, specifier, ctx),
|
||||
// 4. If X begins with '#'
|
||||
b'#' => self.require_hash(cached_path, specifier, ctx),
|
||||
// (ESM) 5. Otherwise,
|
||||
// Note: specifier is now a bare specifier.
|
||||
// Set resolved the result of PACKAGE_RESOLVE(specifier, parentURL).
|
||||
_ => self.require_bare(cached_path, specifier, ctx),
|
||||
_ => {
|
||||
// 1. If X is a core module,
|
||||
// a. return the core module
|
||||
// b. STOP
|
||||
self.require_core(specifier)?;
|
||||
|
||||
// (ESM) 5. Otherwise,
|
||||
// Note: specifier is now a bare specifier.
|
||||
// Set resolved the result of PACKAGE_RESOLVE(specifier, parentURL).
|
||||
self.require_bare(cached_path, specifier, ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::unused_self)]
|
||||
fn require_core(&self, specifier: &str) -> Result<(), ResolveError> {
|
||||
if specifier.starts_with("node:") || BUILTINS.binary_search(&specifier).is_ok() {
|
||||
return Err(ResolveError::Builtin(specifier.to_string()));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn require_absolute(
|
||||
&self,
|
||||
cached_path: &CachedPath,
|
||||
|
|
|
|||
88
crates/oxc_resolver/src/tests/builtins.rs
Normal file
88
crates/oxc_resolver/src/tests/builtins.rs
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
use crate::{ResolveError, Resolver};
|
||||
use std::path::Path;
|
||||
|
||||
#[test]
|
||||
fn builtins() {
|
||||
let resolver = Resolver::default();
|
||||
let f = Path::new("/");
|
||||
|
||||
#[rustfmt::skip]
|
||||
let pass = [
|
||||
"_http_agent",
|
||||
"_http_client",
|
||||
"_http_common",
|
||||
"_http_incoming",
|
||||
"_http_outgoing",
|
||||
"_http_server",
|
||||
"_stream_duplex",
|
||||
"_stream_passthrough",
|
||||
"_stream_readable",
|
||||
"_stream_transform",
|
||||
"_stream_wrap",
|
||||
"_stream_writable",
|
||||
"_tls_common",
|
||||
"_tls_wrap",
|
||||
"assert",
|
||||
"assert/strict",
|
||||
"async_hooks",
|
||||
"buffer",
|
||||
"child_process",
|
||||
"cluster",
|
||||
"console",
|
||||
"constants",
|
||||
"crypto",
|
||||
"dgram",
|
||||
"diagnostics_channel",
|
||||
"dns",
|
||||
"dns/promises",
|
||||
"domain",
|
||||
"events",
|
||||
"fs",
|
||||
"fs/promises",
|
||||
"http",
|
||||
"http2",
|
||||
"https",
|
||||
"inspector",
|
||||
"module",
|
||||
"net",
|
||||
"os",
|
||||
"path",
|
||||
"path/posix",
|
||||
"path/win32",
|
||||
"perf_hooks",
|
||||
"process",
|
||||
"punycode",
|
||||
"querystring",
|
||||
"readline",
|
||||
"repl",
|
||||
"stream",
|
||||
"stream/consumers",
|
||||
"stream/promises",
|
||||
"stream/web",
|
||||
"string_decoder",
|
||||
"sys",
|
||||
"timers",
|
||||
"timers/promises",
|
||||
"tls",
|
||||
"trace_events",
|
||||
"tty",
|
||||
"url",
|
||||
"util",
|
||||
"util/types",
|
||||
"v8",
|
||||
"vm",
|
||||
"worker_threads",
|
||||
"zlib",
|
||||
];
|
||||
|
||||
for request in pass {
|
||||
let resolved_path = resolver.resolve(f, request).map(|r| r.full_path());
|
||||
assert_eq!(resolved_path, Err(ResolveError::Builtin(request.to_string())), "{request}");
|
||||
}
|
||||
|
||||
for request in pass {
|
||||
let request = format!("node:{request}");
|
||||
let resolved_path = resolver.resolve(f, &request).map(|r| r.full_path());
|
||||
assert_eq!(resolved_path, Err(ResolveError::Builtin(request.to_string())), "{request}");
|
||||
}
|
||||
}
|
||||
|
|
@ -16,7 +16,8 @@ fn extensions() {
|
|||
("should resolve according to order of provided extensions", "./foo", "foo.ts"),
|
||||
("should resolve according to order of provided extensions (dir index)", "./dir", "dir/index.ts"),
|
||||
("should resolve according to main field in module root", ".", "index.js"),
|
||||
("should resolve single file module before directory", "module", "node_modules/module.js"),
|
||||
// This is a core module
|
||||
// ("should resolve single file module before directory", "module", "node_modules/module.js"),
|
||||
("should resolve trailing slash directory before single file", "module/", "node_modules/module/index.ts"),
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
mod alias;
|
||||
mod browser_field;
|
||||
mod builtins;
|
||||
mod exports_field;
|
||||
mod extension_alias;
|
||||
mod extensions;
|
||||
|
|
|
|||
Loading…
Reference in a new issue