2024-01-01 14:58:21 -05:00
|
|
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
2023-02-10 10:26:39 -05:00
|
|
|
|
2023-03-13 13:50:23 -04:00
|
|
|
use deno_core::anyhow::Context;
|
2023-02-10 10:26:39 -05:00
|
|
|
use deno_core::error::generic_error;
|
|
|
|
use deno_core::error::AnyError;
|
|
|
|
use deno_core::normalize_path;
|
2023-09-07 12:56:02 -04:00
|
|
|
use deno_core::op2;
|
2023-02-10 10:26:39 -05:00
|
|
|
use deno_core::url::Url;
|
|
|
|
use deno_core::JsRuntimeInspector;
|
2023-04-21 21:02:46 -04:00
|
|
|
use deno_core::ModuleSpecifier;
|
2023-02-10 10:26:39 -05:00
|
|
|
use deno_core::OpState;
|
2023-05-08 11:02:02 -04:00
|
|
|
use deno_fs::FileSystemRc;
|
2024-08-26 11:13:39 -04:00
|
|
|
use deno_package_json::PackageJsonRc;
|
2024-07-25 19:08:14 -04:00
|
|
|
use node_resolver::NodeModuleKind;
|
|
|
|
use node_resolver::NodeResolutionMode;
|
|
|
|
use node_resolver::REQUIRE_CONDITIONS;
|
2023-02-10 10:26:39 -05:00
|
|
|
use std::cell::RefCell;
|
|
|
|
use std::path::Path;
|
|
|
|
use std::path::PathBuf;
|
|
|
|
use std::rc::Rc;
|
|
|
|
|
2023-04-24 06:22:21 -04:00
|
|
|
use crate::NodePermissions;
|
2024-07-25 19:08:14 -04:00
|
|
|
use crate::NodeRequireResolverRc;
|
|
|
|
use crate::NodeResolverRc;
|
2023-05-08 11:02:02 -04:00
|
|
|
use crate::NpmResolverRc;
|
2023-02-10 10:26:39 -05:00
|
|
|
|
|
|
|
fn ensure_read_permission<P>(
|
|
|
|
state: &mut OpState,
|
|
|
|
file_path: &Path,
|
|
|
|
) -> Result<(), AnyError>
|
|
|
|
where
|
|
|
|
P: NodePermissions + 'static,
|
|
|
|
{
|
2024-07-25 19:08:14 -04:00
|
|
|
let resolver = state.borrow::<NodeRequireResolverRc>().clone();
|
2024-06-06 23:37:53 -04:00
|
|
|
let permissions = state.borrow_mut::<P>();
|
2023-02-10 10:26:39 -05:00
|
|
|
resolver.ensure_read_permission(permissions, file_path)
|
|
|
|
}
|
|
|
|
|
2023-09-07 12:56:02 -04:00
|
|
|
#[op2]
|
|
|
|
#[serde]
|
2023-02-10 10:26:39 -05:00
|
|
|
pub fn op_require_init_paths() -> Vec<String> {
|
|
|
|
// todo(dsherret): this code is node compat mode specific and
|
|
|
|
// we probably don't want it for small mammal, so ignore it for now
|
|
|
|
|
|
|
|
// let (home_dir, node_path) = if cfg!(windows) {
|
|
|
|
// (
|
|
|
|
// std::env::var("USERPROFILE").unwrap_or_else(|_| "".into()),
|
|
|
|
// std::env::var("NODE_PATH").unwrap_or_else(|_| "".into()),
|
|
|
|
// )
|
|
|
|
// } else {
|
|
|
|
// (
|
|
|
|
// std::env::var("HOME").unwrap_or_else(|_| "".into()),
|
|
|
|
// std::env::var("NODE_PATH").unwrap_or_else(|_| "".into()),
|
|
|
|
// )
|
|
|
|
// };
|
|
|
|
|
|
|
|
// let mut prefix_dir = std::env::current_exe().unwrap();
|
|
|
|
// if cfg!(windows) {
|
|
|
|
// prefix_dir = prefix_dir.join("..").join("..")
|
|
|
|
// } else {
|
|
|
|
// prefix_dir = prefix_dir.join("..")
|
|
|
|
// }
|
|
|
|
|
|
|
|
// let mut paths = vec![prefix_dir.join("lib").join("node")];
|
|
|
|
|
|
|
|
// if !home_dir.is_empty() {
|
|
|
|
// paths.insert(0, PathBuf::from(&home_dir).join(".node_libraries"));
|
|
|
|
// paths.insert(0, PathBuf::from(&home_dir).join(".nod_modules"));
|
|
|
|
// }
|
|
|
|
|
|
|
|
// let mut paths = paths
|
|
|
|
// .into_iter()
|
2024-08-26 11:13:39 -04:00
|
|
|
// .map(|p| p.to_string_lossy().into_owned())
|
2023-02-10 10:26:39 -05:00
|
|
|
// .collect();
|
|
|
|
|
|
|
|
// if !node_path.is_empty() {
|
|
|
|
// let delimiter = if cfg!(windows) { ";" } else { ":" };
|
|
|
|
// let mut node_paths: Vec<String> = node_path
|
|
|
|
// .split(delimiter)
|
|
|
|
// .filter(|e| !e.is_empty())
|
|
|
|
// .map(|s| s.to_string())
|
|
|
|
// .collect();
|
|
|
|
// node_paths.append(&mut paths);
|
|
|
|
// paths = node_paths;
|
|
|
|
// }
|
|
|
|
|
|
|
|
vec![]
|
|
|
|
}
|
|
|
|
|
2023-09-07 12:56:02 -04:00
|
|
|
#[op2]
|
|
|
|
#[serde]
|
2023-05-04 08:36:38 -04:00
|
|
|
pub fn op_require_node_module_paths<P>(
|
2023-02-10 10:26:39 -05:00
|
|
|
state: &mut OpState,
|
2023-09-07 12:56:02 -04:00
|
|
|
#[string] from: String,
|
2023-02-10 10:26:39 -05:00
|
|
|
) -> Result<Vec<String>, AnyError>
|
|
|
|
where
|
2023-05-04 08:36:38 -04:00
|
|
|
P: NodePermissions + 'static,
|
2023-02-10 10:26:39 -05:00
|
|
|
{
|
2023-05-08 11:02:02 -04:00
|
|
|
let fs = state.borrow::<FileSystemRc>();
|
2023-02-10 10:26:39 -05:00
|
|
|
// Guarantee that "from" is absolute.
|
2024-08-26 11:13:39 -04:00
|
|
|
let from = if from.starts_with("file:///") {
|
|
|
|
url_to_file_path(&Url::parse(&from)?)?
|
2023-08-17 10:39:06 -04:00
|
|
|
} else {
|
2024-08-26 11:13:39 -04:00
|
|
|
let current_dir =
|
|
|
|
&(fs.cwd().map_err(AnyError::from)).context("Unable to get CWD")?;
|
|
|
|
deno_core::normalize_path(current_dir.join(from))
|
2023-08-17 10:39:06 -04:00
|
|
|
};
|
2023-02-10 10:26:39 -05:00
|
|
|
|
2023-05-04 08:36:38 -04:00
|
|
|
ensure_read_permission::<P>(state, &from)?;
|
2023-02-10 10:26:39 -05:00
|
|
|
|
|
|
|
if cfg!(windows) {
|
|
|
|
// return root node_modules when path is 'D:\\'.
|
|
|
|
let from_str = from.to_str().unwrap();
|
|
|
|
if from_str.len() >= 3 {
|
|
|
|
let bytes = from_str.as_bytes();
|
|
|
|
if bytes[from_str.len() - 1] == b'\\' && bytes[from_str.len() - 2] == b':'
|
|
|
|
{
|
2024-08-26 11:13:39 -04:00
|
|
|
let p = format!("{}node_modules", from_str);
|
2023-02-10 10:26:39 -05:00
|
|
|
return Ok(vec![p]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Return early not only to avoid unnecessary work, but to *avoid* returning
|
|
|
|
// an array of two items for a root: [ '//node_modules', '/node_modules' ]
|
|
|
|
if from.to_string_lossy() == "/" {
|
|
|
|
return Ok(vec!["/node_modules".to_string()]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-26 11:13:39 -04:00
|
|
|
let mut paths = Vec::with_capacity(from.components().count());
|
2023-02-10 10:26:39 -05:00
|
|
|
let mut current_path = from.as_path();
|
|
|
|
let mut maybe_parent = Some(current_path);
|
|
|
|
while let Some(parent) = maybe_parent {
|
fix(node): duplicate node_module suffixes (#19222)
Noticed that we're checking more module paths than necessary. In
particular the module path array contains a couple of entries with a
duplicated `node_modules/node_modules` suffix.
```js
[
// ... more entries before here, where some also contain duplicate suffixes
"/Users/marvinhagemeister/dev/preact-render-to-string/node_modules/.deno/node_modules",
"/Users/marvinhagemeister/dev/preact-render-to-string/node_modules/node_modules", // <-- duplicate suffix
"/Users/marvinhagemeister/dev/preact-render-to-string/node_modules",
"/Users/marvinhagemeister/dev/node_modules",
"/Users/marvinhagemeister/node_modules",
"/Users/node_modules",
"/node_modules",
"/node_modules" // <-- duplicate entry
]
```
This was caused by a misunderstanding in how Rust's
[`Path::ends_with()`](https://doc.rust-lang.org/std/path/struct.Path.html#method.ends_with)
works. It's designed to match on whole path segments and the suffix
`/node_modules` is not that, except for the root entry. This meant that
our check for if the path already ended with `node_module` always
returned `false`. Removing the leading slash fixes that.
While we're at it, we can remove the last condition where we explicitly
added the root `/node_modules` entry since the while loop prior to that
takes care of it already.
2023-05-23 06:46:14 -04:00
|
|
|
if !parent.ends_with("node_modules") {
|
2024-08-26 11:13:39 -04:00
|
|
|
paths.push(parent.join("node_modules").to_string_lossy().into_owned());
|
2023-02-10 10:26:39 -05:00
|
|
|
}
|
fix(node): duplicate node_module suffixes (#19222)
Noticed that we're checking more module paths than necessary. In
particular the module path array contains a couple of entries with a
duplicated `node_modules/node_modules` suffix.
```js
[
// ... more entries before here, where some also contain duplicate suffixes
"/Users/marvinhagemeister/dev/preact-render-to-string/node_modules/.deno/node_modules",
"/Users/marvinhagemeister/dev/preact-render-to-string/node_modules/node_modules", // <-- duplicate suffix
"/Users/marvinhagemeister/dev/preact-render-to-string/node_modules",
"/Users/marvinhagemeister/dev/node_modules",
"/Users/marvinhagemeister/node_modules",
"/Users/node_modules",
"/node_modules",
"/node_modules" // <-- duplicate entry
]
```
This was caused by a misunderstanding in how Rust's
[`Path::ends_with()`](https://doc.rust-lang.org/std/path/struct.Path.html#method.ends_with)
works. It's designed to match on whole path segments and the suffix
`/node_modules` is not that, except for the root entry. This meant that
our check for if the path already ended with `node_module` always
returned `false`. Removing the leading slash fixes that.
While we're at it, we can remove the last condition where we explicitly
added the root `/node_modules` entry since the while loop prior to that
takes care of it already.
2023-05-23 06:46:14 -04:00
|
|
|
current_path = parent;
|
|
|
|
maybe_parent = current_path.parent();
|
2023-02-10 10:26:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(paths)
|
|
|
|
}
|
|
|
|
|
2023-09-07 12:56:02 -04:00
|
|
|
#[op2]
|
|
|
|
#[string]
|
|
|
|
pub fn op_require_proxy_path(#[string] filename: String) -> String {
|
2023-02-10 10:26:39 -05:00
|
|
|
// Allow a directory to be passed as the filename
|
|
|
|
let trailing_slash = if cfg!(windows) {
|
|
|
|
// Node also counts a trailing forward slash as a
|
|
|
|
// directory for node on Windows, but not backslashes
|
|
|
|
// on non-Windows platforms
|
|
|
|
filename.ends_with('\\') || filename.ends_with('/')
|
|
|
|
} else {
|
|
|
|
filename.ends_with('/')
|
|
|
|
};
|
|
|
|
|
|
|
|
if trailing_slash {
|
|
|
|
let p = PathBuf::from(filename);
|
2024-08-26 11:13:39 -04:00
|
|
|
p.join("noop.js").to_string_lossy().into_owned()
|
2023-02-10 10:26:39 -05:00
|
|
|
} else {
|
|
|
|
filename
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-07 12:56:02 -04:00
|
|
|
#[op2(fast)]
|
|
|
|
pub fn op_require_is_request_relative(#[string] request: String) -> bool {
|
2023-02-10 10:26:39 -05:00
|
|
|
if request.starts_with("./") || request.starts_with("../") || request == ".."
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if cfg!(windows) {
|
|
|
|
if request.starts_with(".\\") {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if request.starts_with("..\\") {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
2023-09-07 12:56:02 -04:00
|
|
|
#[op2]
|
|
|
|
#[string]
|
|
|
|
pub fn op_require_resolve_deno_dir(
|
2023-02-10 10:26:39 -05:00
|
|
|
state: &mut OpState,
|
2023-09-07 12:56:02 -04:00
|
|
|
#[string] request: String,
|
|
|
|
#[string] parent_filename: String,
|
2023-02-10 10:26:39 -05:00
|
|
|
) -> Option<String> {
|
2023-05-08 11:02:02 -04:00
|
|
|
let resolver = state.borrow::<NpmResolverRc>();
|
2023-02-10 10:26:39 -05:00
|
|
|
resolver
|
|
|
|
.resolve_package_folder_from_package(
|
|
|
|
&request,
|
2024-03-19 23:42:22 -04:00
|
|
|
&ModuleSpecifier::from_file_path(&parent_filename).unwrap_or_else(|_| {
|
|
|
|
panic!("Url::from_file_path: [{:?}]", parent_filename)
|
|
|
|
}),
|
2023-02-10 10:26:39 -05:00
|
|
|
)
|
|
|
|
.ok()
|
2024-08-26 11:13:39 -04:00
|
|
|
.map(|p| p.to_string_lossy().into_owned())
|
2023-02-10 10:26:39 -05:00
|
|
|
}
|
|
|
|
|
2023-09-07 12:56:02 -04:00
|
|
|
#[op2(fast)]
|
|
|
|
pub fn op_require_is_deno_dir_package(
|
|
|
|
state: &mut OpState,
|
|
|
|
#[string] path: String,
|
|
|
|
) -> bool {
|
2023-05-08 11:02:02 -04:00
|
|
|
let resolver = state.borrow::<NpmResolverRc>();
|
2023-11-07 09:56:06 -05:00
|
|
|
resolver.in_npm_package_at_file_path(&PathBuf::from(path))
|
2023-02-10 10:26:39 -05:00
|
|
|
}
|
|
|
|
|
2023-09-07 12:56:02 -04:00
|
|
|
#[op2]
|
|
|
|
#[serde]
|
|
|
|
pub fn op_require_resolve_lookup_paths(
|
|
|
|
#[string] request: String,
|
|
|
|
#[serde] maybe_parent_paths: Option<Vec<String>>,
|
|
|
|
#[string] parent_filename: String,
|
2023-02-10 10:26:39 -05:00
|
|
|
) -> Option<Vec<String>> {
|
|
|
|
if !request.starts_with('.')
|
|
|
|
|| (request.len() > 1
|
|
|
|
&& !request.starts_with("..")
|
|
|
|
&& !request.starts_with("./")
|
|
|
|
&& (!cfg!(windows) || !request.starts_with(".\\")))
|
|
|
|
{
|
|
|
|
let module_paths = vec![];
|
|
|
|
let mut paths = module_paths;
|
|
|
|
if let Some(mut parent_paths) = maybe_parent_paths {
|
|
|
|
if !parent_paths.is_empty() {
|
|
|
|
paths.append(&mut parent_paths);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !paths.is_empty() {
|
|
|
|
return Some(paths);
|
|
|
|
} else {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// In REPL, parent.filename is null.
|
|
|
|
// if (!parent || !parent.id || !parent.filename) {
|
|
|
|
// // Make require('./path/to/foo') work - normally the path is taken
|
|
|
|
// // from realpath(__filename) but in REPL there is no filename
|
|
|
|
// const mainPaths = ['.'];
|
|
|
|
|
|
|
|
// debug('looking for %j in %j', request, mainPaths);
|
|
|
|
// return mainPaths;
|
|
|
|
// }
|
|
|
|
|
|
|
|
let p = PathBuf::from(parent_filename);
|
2024-08-26 11:13:39 -04:00
|
|
|
Some(vec![p.parent().unwrap().to_string_lossy().into_owned()])
|
2023-02-10 10:26:39 -05:00
|
|
|
}
|
|
|
|
|
2023-09-07 12:56:02 -04:00
|
|
|
#[op2(fast)]
|
|
|
|
pub fn op_require_path_is_absolute(#[string] p: String) -> bool {
|
2023-02-10 10:26:39 -05:00
|
|
|
PathBuf::from(p).is_absolute()
|
|
|
|
}
|
|
|
|
|
2023-09-07 12:56:02 -04:00
|
|
|
#[op2(fast)]
|
|
|
|
pub fn op_require_stat<P>(
|
2023-02-10 10:26:39 -05:00
|
|
|
state: &mut OpState,
|
2023-09-07 12:56:02 -04:00
|
|
|
#[string] path: String,
|
2023-02-10 10:26:39 -05:00
|
|
|
) -> Result<i32, AnyError>
|
|
|
|
where
|
2023-05-04 08:36:38 -04:00
|
|
|
P: NodePermissions + 'static,
|
2023-02-10 10:26:39 -05:00
|
|
|
{
|
|
|
|
let path = PathBuf::from(path);
|
2023-05-04 08:36:38 -04:00
|
|
|
ensure_read_permission::<P>(state, &path)?;
|
2023-05-08 11:02:02 -04:00
|
|
|
let fs = state.borrow::<FileSystemRc>();
|
2023-05-05 12:44:24 -04:00
|
|
|
if let Ok(metadata) = fs.stat_sync(&path) {
|
2023-04-06 12:53:53 -04:00
|
|
|
if metadata.is_file {
|
2023-02-10 10:26:39 -05:00
|
|
|
return Ok(0);
|
|
|
|
} else {
|
|
|
|
return Ok(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(-1)
|
|
|
|
}
|
|
|
|
|
2023-09-07 12:56:02 -04:00
|
|
|
#[op2]
|
|
|
|
#[string]
|
|
|
|
pub fn op_require_real_path<P>(
|
2023-02-10 10:26:39 -05:00
|
|
|
state: &mut OpState,
|
2023-09-07 12:56:02 -04:00
|
|
|
#[string] request: String,
|
2023-02-10 10:26:39 -05:00
|
|
|
) -> Result<String, AnyError>
|
|
|
|
where
|
2023-05-04 08:36:38 -04:00
|
|
|
P: NodePermissions + 'static,
|
2023-02-10 10:26:39 -05:00
|
|
|
{
|
|
|
|
let path = PathBuf::from(request);
|
2023-05-04 08:36:38 -04:00
|
|
|
ensure_read_permission::<P>(state, &path)?;
|
2023-05-08 11:02:02 -04:00
|
|
|
let fs = state.borrow::<FileSystemRc>();
|
2023-05-05 12:44:24 -04:00
|
|
|
let canonicalized_path =
|
|
|
|
deno_core::strip_unc_prefix(fs.realpath_sync(&path)?);
|
2024-08-26 11:13:39 -04:00
|
|
|
Ok(canonicalized_path.to_string_lossy().into_owned())
|
2023-02-10 10:26:39 -05:00
|
|
|
}
|
|
|
|
|
2024-08-26 11:13:39 -04:00
|
|
|
fn path_resolve<'a>(mut parts: impl Iterator<Item = &'a str>) -> PathBuf {
|
|
|
|
let mut p = PathBuf::from(parts.next().unwrap());
|
|
|
|
for part in parts {
|
|
|
|
p = p.join(part);
|
2023-02-10 10:26:39 -05:00
|
|
|
}
|
2024-08-26 11:13:39 -04:00
|
|
|
normalize_path(p)
|
2023-02-10 10:26:39 -05:00
|
|
|
}
|
|
|
|
|
2023-09-07 12:56:02 -04:00
|
|
|
#[op2]
|
|
|
|
#[string]
|
|
|
|
pub fn op_require_path_resolve(#[serde] parts: Vec<String>) -> String {
|
2024-08-26 11:13:39 -04:00
|
|
|
path_resolve(parts.iter().map(|s| s.as_str()))
|
|
|
|
.to_string_lossy()
|
|
|
|
.into_owned()
|
2023-02-10 10:26:39 -05:00
|
|
|
}
|
|
|
|
|
2023-09-07 12:56:02 -04:00
|
|
|
#[op2]
|
|
|
|
#[string]
|
|
|
|
pub fn op_require_path_dirname(
|
|
|
|
#[string] request: String,
|
|
|
|
) -> Result<String, AnyError> {
|
2023-02-10 10:26:39 -05:00
|
|
|
let p = PathBuf::from(request);
|
|
|
|
if let Some(parent) = p.parent() {
|
2024-08-26 11:13:39 -04:00
|
|
|
Ok(parent.to_string_lossy().into_owned())
|
2023-02-10 10:26:39 -05:00
|
|
|
} else {
|
|
|
|
Err(generic_error("Path doesn't have a parent"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-07 12:56:02 -04:00
|
|
|
#[op2]
|
|
|
|
#[string]
|
|
|
|
pub fn op_require_path_basename(
|
|
|
|
#[string] request: String,
|
|
|
|
) -> Result<String, AnyError> {
|
2023-02-10 10:26:39 -05:00
|
|
|
let p = PathBuf::from(request);
|
|
|
|
if let Some(path) = p.file_name() {
|
2024-08-26 11:13:39 -04:00
|
|
|
Ok(path.to_string_lossy().into_owned())
|
2023-02-10 10:26:39 -05:00
|
|
|
} else {
|
|
|
|
Err(generic_error("Path doesn't have a file name"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-07 12:56:02 -04:00
|
|
|
#[op2]
|
|
|
|
#[string]
|
|
|
|
pub fn op_require_try_self_parent_path<P>(
|
2023-02-10 10:26:39 -05:00
|
|
|
state: &mut OpState,
|
|
|
|
has_parent: bool,
|
2023-09-07 12:56:02 -04:00
|
|
|
#[string] maybe_parent_filename: Option<String>,
|
|
|
|
#[string] maybe_parent_id: Option<String>,
|
2023-02-10 10:26:39 -05:00
|
|
|
) -> Result<Option<String>, AnyError>
|
|
|
|
where
|
2023-05-04 08:36:38 -04:00
|
|
|
P: NodePermissions + 'static,
|
2023-02-10 10:26:39 -05:00
|
|
|
{
|
|
|
|
if !has_parent {
|
|
|
|
return Ok(None);
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(parent_filename) = maybe_parent_filename {
|
|
|
|
return Ok(Some(parent_filename));
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(parent_id) = maybe_parent_id {
|
|
|
|
if parent_id == "<repl>" || parent_id == "internal/preload" {
|
2023-05-08 11:02:02 -04:00
|
|
|
let fs = state.borrow::<FileSystemRc>();
|
2023-05-05 12:44:24 -04:00
|
|
|
if let Ok(cwd) = fs.cwd() {
|
2023-05-04 08:36:38 -04:00
|
|
|
ensure_read_permission::<P>(state, &cwd)?;
|
2024-08-26 11:13:39 -04:00
|
|
|
return Ok(Some(cwd.to_string_lossy().into_owned()));
|
2023-02-10 10:26:39 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(None)
|
|
|
|
}
|
|
|
|
|
2023-09-07 12:56:02 -04:00
|
|
|
#[op2]
|
|
|
|
#[string]
|
|
|
|
pub fn op_require_try_self<P>(
|
2023-02-10 10:26:39 -05:00
|
|
|
state: &mut OpState,
|
2023-09-07 12:56:02 -04:00
|
|
|
#[string] parent_path: Option<String>,
|
|
|
|
#[string] request: String,
|
2023-02-10 10:26:39 -05:00
|
|
|
) -> Result<Option<String>, AnyError>
|
|
|
|
where
|
2023-05-04 08:36:38 -04:00
|
|
|
P: NodePermissions + 'static,
|
2023-02-10 10:26:39 -05:00
|
|
|
{
|
|
|
|
if parent_path.is_none() {
|
|
|
|
return Ok(None);
|
|
|
|
}
|
|
|
|
|
2024-06-06 23:37:53 -04:00
|
|
|
let node_resolver = state.borrow::<NodeResolverRc>();
|
2023-04-24 19:44:35 -04:00
|
|
|
let pkg = node_resolver
|
2024-08-26 11:13:39 -04:00
|
|
|
.get_closest_package_json_from_path(&PathBuf::from(parent_path.unwrap()))
|
2023-07-17 14:00:44 -04:00
|
|
|
.ok()
|
|
|
|
.flatten();
|
2023-02-10 10:26:39 -05:00
|
|
|
if pkg.is_none() {
|
|
|
|
return Ok(None);
|
|
|
|
}
|
|
|
|
|
|
|
|
let pkg = pkg.unwrap();
|
|
|
|
if pkg.exports.is_none() {
|
|
|
|
return Ok(None);
|
|
|
|
}
|
|
|
|
if pkg.name.is_none() {
|
|
|
|
return Ok(None);
|
|
|
|
}
|
|
|
|
|
|
|
|
let pkg_name = pkg.name.as_ref().unwrap().to_string();
|
|
|
|
let mut expansion = ".".to_string();
|
|
|
|
|
|
|
|
if request == pkg_name {
|
|
|
|
// pass
|
|
|
|
} else if request.starts_with(&format!("{pkg_name}/")) {
|
|
|
|
expansion += &request[pkg_name.len()..];
|
|
|
|
} else {
|
|
|
|
return Ok(None);
|
|
|
|
}
|
|
|
|
|
|
|
|
let referrer = deno_core::url::Url::from_file_path(&pkg.path).unwrap();
|
|
|
|
if let Some(exports) = &pkg.exports {
|
2024-03-09 10:21:31 -05:00
|
|
|
let r = node_resolver.package_exports_resolve(
|
|
|
|
&pkg.path,
|
|
|
|
&expansion,
|
|
|
|
exports,
|
2024-07-09 12:15:03 -04:00
|
|
|
Some(&referrer),
|
2024-03-09 10:21:31 -05:00
|
|
|
NodeModuleKind::Cjs,
|
2024-07-25 19:08:14 -04:00
|
|
|
REQUIRE_CONDITIONS,
|
2024-03-09 10:21:31 -05:00
|
|
|
NodeResolutionMode::Execution,
|
|
|
|
)?;
|
|
|
|
Ok(Some(if r.scheme() == "file" {
|
|
|
|
url_to_file_path_string(&r)?
|
|
|
|
} else {
|
|
|
|
r.to_string()
|
|
|
|
}))
|
2023-02-10 10:26:39 -05:00
|
|
|
} else {
|
|
|
|
Ok(None)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-07 12:56:02 -04:00
|
|
|
#[op2]
|
|
|
|
#[string]
|
|
|
|
pub fn op_require_read_file<P>(
|
2023-02-10 10:26:39 -05:00
|
|
|
state: &mut OpState,
|
2023-09-07 12:56:02 -04:00
|
|
|
#[string] file_path: String,
|
2023-02-10 10:26:39 -05:00
|
|
|
) -> Result<String, AnyError>
|
|
|
|
where
|
2023-05-04 08:36:38 -04:00
|
|
|
P: NodePermissions + 'static,
|
2023-02-10 10:26:39 -05:00
|
|
|
{
|
|
|
|
let file_path = PathBuf::from(file_path);
|
2023-05-04 08:36:38 -04:00
|
|
|
ensure_read_permission::<P>(state, &file_path)?;
|
2023-05-08 11:02:02 -04:00
|
|
|
let fs = state.borrow::<FileSystemRc>();
|
2024-06-08 12:36:13 -04:00
|
|
|
Ok(fs.read_text_file_lossy_sync(&file_path, None)?)
|
2023-02-10 10:26:39 -05:00
|
|
|
}
|
|
|
|
|
2023-09-07 12:56:02 -04:00
|
|
|
#[op2]
|
|
|
|
#[string]
|
|
|
|
pub fn op_require_as_file_path(#[string] file_or_url: String) -> String {
|
2023-02-10 10:26:39 -05:00
|
|
|
if let Ok(url) = Url::parse(&file_or_url) {
|
|
|
|
if let Ok(p) = url.to_file_path() {
|
2024-08-26 11:13:39 -04:00
|
|
|
return p.to_string_lossy().into_owned();
|
2023-02-10 10:26:39 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
file_or_url
|
|
|
|
}
|
|
|
|
|
2023-09-07 12:56:02 -04:00
|
|
|
#[op2]
|
|
|
|
#[string]
|
|
|
|
pub fn op_require_resolve_exports<P>(
|
2023-02-10 10:26:39 -05:00
|
|
|
state: &mut OpState,
|
|
|
|
uses_local_node_modules_dir: bool,
|
2024-08-26 11:13:39 -04:00
|
|
|
#[string] modules_path_str: String,
|
2023-09-07 12:56:02 -04:00
|
|
|
#[string] _request: String,
|
|
|
|
#[string] name: String,
|
|
|
|
#[string] expansion: String,
|
|
|
|
#[string] parent_path: String,
|
2023-02-10 10:26:39 -05:00
|
|
|
) -> Result<Option<String>, AnyError>
|
|
|
|
where
|
2023-05-04 08:36:38 -04:00
|
|
|
P: NodePermissions + 'static,
|
2023-02-10 10:26:39 -05:00
|
|
|
{
|
2023-05-08 11:02:02 -04:00
|
|
|
let fs = state.borrow::<FileSystemRc>();
|
|
|
|
let npm_resolver = state.borrow::<NpmResolverRc>();
|
2024-06-06 23:37:53 -04:00
|
|
|
let node_resolver = state.borrow::<NodeResolverRc>();
|
2023-02-10 10:26:39 -05:00
|
|
|
|
2024-08-26 11:13:39 -04:00
|
|
|
let modules_path = PathBuf::from(&modules_path_str);
|
|
|
|
let pkg_path = if npm_resolver.in_npm_package_at_file_path(&modules_path)
|
2023-02-10 10:26:39 -05:00
|
|
|
&& !uses_local_node_modules_dir
|
|
|
|
{
|
|
|
|
modules_path
|
|
|
|
} else {
|
2024-08-26 11:13:39 -04:00
|
|
|
let mod_dir =
|
|
|
|
path_resolve([modules_path_str.as_str(), name.as_str()].into_iter());
|
|
|
|
if fs.is_dir_sync(&mod_dir) {
|
2023-04-06 10:12:50 -04:00
|
|
|
mod_dir
|
|
|
|
} else {
|
2024-08-26 11:13:39 -04:00
|
|
|
modules_path
|
2023-04-06 10:12:50 -04:00
|
|
|
}
|
2023-02-10 10:26:39 -05:00
|
|
|
};
|
2024-08-26 11:13:39 -04:00
|
|
|
let Some(pkg) =
|
|
|
|
node_resolver.load_package_json(&pkg_path.join("package.json"))?
|
2024-06-26 17:24:10 -04:00
|
|
|
else {
|
|
|
|
return Ok(None);
|
|
|
|
};
|
|
|
|
let Some(exports) = &pkg.exports else {
|
|
|
|
return Ok(None);
|
|
|
|
};
|
2023-02-10 10:26:39 -05:00
|
|
|
|
2024-06-26 17:24:10 -04:00
|
|
|
let referrer = Url::from_file_path(parent_path).unwrap();
|
|
|
|
let r = node_resolver.package_exports_resolve(
|
|
|
|
&pkg.path,
|
|
|
|
&format!(".{expansion}"),
|
|
|
|
exports,
|
2024-07-09 12:15:03 -04:00
|
|
|
Some(&referrer),
|
2024-06-26 17:24:10 -04:00
|
|
|
NodeModuleKind::Cjs,
|
2024-07-25 19:08:14 -04:00
|
|
|
REQUIRE_CONDITIONS,
|
2024-06-26 17:24:10 -04:00
|
|
|
NodeResolutionMode::Execution,
|
|
|
|
)?;
|
|
|
|
Ok(Some(if r.scheme() == "file" {
|
|
|
|
url_to_file_path_string(&r)?
|
2023-02-10 10:26:39 -05:00
|
|
|
} else {
|
2024-06-26 17:24:10 -04:00
|
|
|
r.to_string()
|
|
|
|
}))
|
2023-02-10 10:26:39 -05:00
|
|
|
}
|
|
|
|
|
2023-09-07 12:56:02 -04:00
|
|
|
#[op2]
|
|
|
|
#[serde]
|
|
|
|
pub fn op_require_read_closest_package_json<P>(
|
2023-02-10 10:26:39 -05:00
|
|
|
state: &mut OpState,
|
2023-09-07 12:56:02 -04:00
|
|
|
#[string] filename: String,
|
2024-08-26 11:13:39 -04:00
|
|
|
) -> Result<Option<PackageJsonRc>, AnyError>
|
2023-02-10 10:26:39 -05:00
|
|
|
where
|
2023-05-04 08:36:38 -04:00
|
|
|
P: NodePermissions + 'static,
|
2023-02-10 10:26:39 -05:00
|
|
|
{
|
2024-08-26 11:13:39 -04:00
|
|
|
let filename = PathBuf::from(filename);
|
|
|
|
ensure_read_permission::<P>(state, filename.parent().unwrap())?;
|
2024-06-06 23:37:53 -04:00
|
|
|
let node_resolver = state.borrow::<NodeResolverRc>().clone();
|
2024-04-01 09:10:04 -04:00
|
|
|
node_resolver
|
2024-08-26 11:13:39 -04:00
|
|
|
.get_closest_package_json_from_path(&filename)
|
2024-07-09 12:15:03 -04:00
|
|
|
.map_err(AnyError::from)
|
2023-02-10 10:26:39 -05:00
|
|
|
}
|
|
|
|
|
2023-09-07 12:56:02 -04:00
|
|
|
#[op2]
|
|
|
|
#[serde]
|
|
|
|
pub fn op_require_read_package_scope<P>(
|
2023-02-10 10:26:39 -05:00
|
|
|
state: &mut OpState,
|
2023-09-07 12:56:02 -04:00
|
|
|
#[string] package_json_path: String,
|
2024-08-26 11:13:39 -04:00
|
|
|
) -> Option<PackageJsonRc>
|
2023-02-10 10:26:39 -05:00
|
|
|
where
|
2023-05-04 08:36:38 -04:00
|
|
|
P: NodePermissions + 'static,
|
2023-02-10 10:26:39 -05:00
|
|
|
{
|
2024-06-06 23:37:53 -04:00
|
|
|
let node_resolver = state.borrow::<NodeResolverRc>().clone();
|
2023-02-10 10:26:39 -05:00
|
|
|
let package_json_path = PathBuf::from(package_json_path);
|
2024-06-26 17:24:10 -04:00
|
|
|
if package_json_path.file_name() != Some("package.json".as_ref()) {
|
|
|
|
// permissions: do not allow reading a non-package.json file
|
|
|
|
return None;
|
|
|
|
}
|
2023-04-24 19:44:35 -04:00
|
|
|
node_resolver
|
2024-06-26 17:24:10 -04:00
|
|
|
.load_package_json(&package_json_path)
|
2023-04-24 19:44:35 -04:00
|
|
|
.ok()
|
2024-06-26 17:24:10 -04:00
|
|
|
.flatten()
|
2023-02-10 10:26:39 -05:00
|
|
|
}
|
|
|
|
|
2023-09-07 12:56:02 -04:00
|
|
|
#[op2]
|
|
|
|
#[string]
|
|
|
|
pub fn op_require_package_imports_resolve<P>(
|
2023-02-10 10:26:39 -05:00
|
|
|
state: &mut OpState,
|
2024-03-09 10:21:31 -05:00
|
|
|
#[string] referrer_filename: String,
|
2023-09-07 12:56:02 -04:00
|
|
|
#[string] request: String,
|
2023-02-10 10:26:39 -05:00
|
|
|
) -> Result<Option<String>, AnyError>
|
|
|
|
where
|
2023-05-04 08:36:38 -04:00
|
|
|
P: NodePermissions + 'static,
|
2023-02-10 10:26:39 -05:00
|
|
|
{
|
2024-03-09 10:21:31 -05:00
|
|
|
let referrer_path = PathBuf::from(&referrer_filename);
|
|
|
|
ensure_read_permission::<P>(state, &referrer_path)?;
|
2024-06-06 23:37:53 -04:00
|
|
|
let node_resolver = state.borrow::<NodeResolverRc>();
|
2024-06-26 17:24:10 -04:00
|
|
|
let Some(pkg) =
|
|
|
|
node_resolver.get_closest_package_json_from_path(&referrer_path)?
|
2024-03-09 10:21:31 -05:00
|
|
|
else {
|
|
|
|
return Ok(None);
|
|
|
|
};
|
2023-02-10 10:26:39 -05:00
|
|
|
|
|
|
|
if pkg.imports.is_some() {
|
2024-03-09 10:21:31 -05:00
|
|
|
let referrer_url =
|
|
|
|
deno_core::url::Url::from_file_path(&referrer_filename).unwrap();
|
|
|
|
let url = node_resolver.package_imports_resolve(
|
|
|
|
&request,
|
2024-07-09 12:15:03 -04:00
|
|
|
Some(&referrer_url),
|
2024-03-09 10:21:31 -05:00
|
|
|
NodeModuleKind::Cjs,
|
|
|
|
Some(&pkg),
|
2024-07-25 19:08:14 -04:00
|
|
|
REQUIRE_CONDITIONS,
|
2024-03-09 10:21:31 -05:00
|
|
|
NodeResolutionMode::Execution,
|
|
|
|
)?;
|
|
|
|
Ok(Some(url_to_file_path_string(&url)?))
|
2023-02-10 10:26:39 -05:00
|
|
|
} else {
|
|
|
|
Ok(None)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-07 12:56:02 -04:00
|
|
|
#[op2(fast)]
|
|
|
|
pub fn op_require_break_on_next_statement(state: &mut OpState) {
|
2023-02-10 10:26:39 -05:00
|
|
|
let inspector = state.borrow::<Rc<RefCell<JsRuntimeInspector>>>();
|
|
|
|
inspector
|
|
|
|
.borrow_mut()
|
|
|
|
.wait_for_session_and_break_on_next_statement()
|
|
|
|
}
|
2024-03-09 10:21:31 -05:00
|
|
|
|
|
|
|
fn url_to_file_path_string(url: &Url) -> Result<String, AnyError> {
|
|
|
|
let file_path = url_to_file_path(url)?;
|
2024-08-26 11:13:39 -04:00
|
|
|
Ok(file_path.to_string_lossy().into_owned())
|
2024-03-09 10:21:31 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn url_to_file_path(url: &Url) -> Result<PathBuf, AnyError> {
|
|
|
|
match url.to_file_path() {
|
|
|
|
Ok(file_path) => Ok(file_path),
|
|
|
|
Err(()) => {
|
|
|
|
deno_core::anyhow::bail!("failed to convert '{}' to file path", url)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|