1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-24 15:19:26 -05:00

refactor: create util folder, move nap_sym to napi/sym, move http_cache to cache folder (#16857)

This commit is contained in:
David Sherret 2022-11-28 17:28:54 -05:00 committed by GitHub
parent f526513d74
commit 2d4c46c975
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
57 changed files with 940 additions and 920 deletions

View file

@ -5,7 +5,7 @@ resolver = "2"
members = [ members = [
"bench_util", "bench_util",
"cli", "cli",
"cli/napi_sym", "cli/napi/sym",
"core", "core",
"ops", "ops",
"runtime", "runtime",
@ -47,7 +47,7 @@ deno_core = { version = "0.161.0", path = "./core" }
deno_ops = { version = "0.39.0", path = "./ops" } deno_ops = { version = "0.39.0", path = "./ops" }
serde_v8 = { version = "0.72.0", path = "./serde_v8" } serde_v8 = { version = "0.72.0", path = "./serde_v8" }
deno_runtime = { version = "0.87.0", path = "./runtime" } deno_runtime = { version = "0.87.0", path = "./runtime" }
napi_sym = { version = "0.9.0", path = "./cli/napi_sym" } napi_sym = { version = "0.9.0", path = "./cli/napi/sym" }
deno_bench_util = { version = "0.73.0", path = "./bench_util" } deno_bench_util = { version = "0.73.0", path = "./bench_util" }
test_util = { path = "./test_util" } test_util = { path = "./test_util" }

View file

@ -3,10 +3,9 @@
use crate::args::ConfigFlag; use crate::args::ConfigFlag;
use crate::args::Flags; use crate::args::Flags;
use crate::args::TaskFlags; use crate::args::TaskFlags;
use crate::fs_util; use crate::util::fs::canonicalize_path;
use crate::fs_util::canonicalize_path; use crate::util::path::specifier_parent;
use crate::fs_util::specifier_parent; use crate::util::path::specifier_to_file_path;
use crate::fs_util::specifier_to_file_path;
use deno_core::anyhow::anyhow; use deno_core::anyhow::anyhow;
use deno_core::anyhow::bail; use deno_core::anyhow::bail;
@ -467,7 +466,7 @@ impl ConfigFile {
.. ..
}) = &flags.subcommand }) = &flags.subcommand
{ {
let task_cwd = fs_util::canonicalize_path(&PathBuf::from(path))?; let task_cwd = canonicalize_path(&PathBuf::from(path))?;
if let Some(path) = Self::discover_from(&task_cwd, &mut checked)? { if let Some(path) = Self::discover_from(&task_cwd, &mut checked)? {
return Ok(Some(path)); return Ok(Some(path));
} }

View file

@ -20,6 +20,7 @@ use crate::npm::NpmPackageId;
use crate::npm::NpmPackageReq; use crate::npm::NpmPackageReq;
use crate::npm::NpmResolutionPackage; use crate::npm::NpmResolutionPackage;
use crate::tools::fmt::format_json; use crate::tools::fmt::format_json;
use crate::util;
use crate::Flags; use crate::Flags;
#[derive(Debug)] #[derive(Debug)]
@ -260,7 +261,7 @@ impl Lockfile {
/// is not included, insert it. /// is not included, insert it.
fn check_or_insert(&mut self, specifier: &str, code: &str) -> bool { fn check_or_insert(&mut self, specifier: &str, code: &str) -> bool {
if let Some(lockfile_checksum) = self.content.remote.get(specifier) { if let Some(lockfile_checksum) = self.content.remote.get(specifier) {
let compiled_checksum = crate::checksum::gen(&[code.as_bytes()]); let compiled_checksum = util::checksum::gen(&[code.as_bytes()]);
lockfile_checksum == &compiled_checksum lockfile_checksum == &compiled_checksum
} else { } else {
self.insert(specifier, code); self.insert(specifier, code);
@ -269,7 +270,7 @@ impl Lockfile {
} }
fn insert(&mut self, specifier: &str, code: &str) { fn insert(&mut self, specifier: &str, code: &str) {
let checksum = crate::checksum::gen(&[code.as_bytes()]); let checksum = util::checksum::gen(&[code.as_bytes()]);
self.content.remote.insert(specifier.to_string(), checksum); self.content.remote.insert(specifier.to_string(), checksum);
self.has_content_changed = true; self.has_content_changed = true;
} }
@ -359,7 +360,7 @@ impl deno_graph::source::Locker for Locker {
} }
fn get_checksum(&self, content: &str) -> String { fn get_checksum(&self, content: &str) -> String {
crate::checksum::gen(&[content.as_bytes()]) util::checksum::gen(&[content.as_bytes()])
} }
fn get_filename(&self) -> Option<String> { fn get_filename(&self) -> Option<String> {

View file

@ -22,6 +22,10 @@ pub use config_file::TsConfig;
pub use config_file::TsConfigForEmit; pub use config_file::TsConfigForEmit;
pub use config_file::TsConfigType; pub use config_file::TsConfigType;
pub use config_file::TsTypeLib; pub use config_file::TsTypeLib;
use deno_runtime::deno_tls::rustls;
use deno_runtime::deno_tls::rustls_native_certs::load_native_certs;
use deno_runtime::deno_tls::rustls_pemfile;
use deno_runtime::deno_tls::webpki_roots;
pub use flags::*; pub use flags::*;
pub use lockfile::Lockfile; pub use lockfile::Lockfile;
pub use lockfile::LockfileError; pub use lockfile::LockfileError;
@ -40,16 +44,130 @@ use deno_runtime::inspector_server::InspectorServer;
use deno_runtime::permissions::PermissionsOptions; use deno_runtime::permissions::PermissionsOptions;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::env; use std::env;
use std::io::BufReader;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use crate::cache::DenoDir; use crate::cache::DenoDir;
use crate::file_fetcher::get_root_cert_store; use crate::util::fs::canonicalize_path_maybe_not_exists;
use crate::file_fetcher::CacheSetting;
use crate::fs_util;
use crate::version; use crate::version;
/// Indicates how cached source files should be handled.
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum CacheSetting {
/// Only the cached files should be used. Any files not in the cache will
/// error. This is the equivalent of `--cached-only` in the CLI.
Only,
/// No cached source files should be used, and all files should be reloaded.
/// This is the equivalent of `--reload` in the CLI.
ReloadAll,
/// Only some cached resources should be used. This is the equivalent of
/// `--reload=https://deno.land/std` or
/// `--reload=https://deno.land/std,https://deno.land/x/example`.
ReloadSome(Vec<String>),
/// The usability of a cached value is determined by analyzing the cached
/// headers and other metadata associated with a cached response, reloading
/// any cached "non-fresh" cached responses.
RespectHeaders,
/// The cached source files should be used for local modules. This is the
/// default behavior of the CLI.
Use,
}
impl CacheSetting {
pub fn should_use_for_npm_package(&self, package_name: &str) -> bool {
match self {
CacheSetting::ReloadAll => false,
CacheSetting::ReloadSome(list) => {
if list.iter().any(|i| i == "npm:") {
return false;
}
let specifier = format!("npm:{}", package_name);
if list.contains(&specifier) {
return false;
}
true
}
_ => true,
}
}
}
/// Create and populate a root cert store based on the passed options and
/// environment.
pub fn get_root_cert_store(
maybe_root_path: Option<PathBuf>,
maybe_ca_stores: Option<Vec<String>>,
maybe_ca_file: Option<String>,
) -> Result<RootCertStore, AnyError> {
let mut root_cert_store = RootCertStore::empty();
let ca_stores: Vec<String> = maybe_ca_stores
.or_else(|| {
let env_ca_store = env::var("DENO_TLS_CA_STORE").ok()?;
Some(
env_ca_store
.split(',')
.map(|s| s.trim().to_string())
.filter(|s| !s.is_empty())
.collect(),
)
})
.unwrap_or_else(|| vec!["mozilla".to_string()]);
for store in ca_stores.iter() {
match store.as_str() {
"mozilla" => {
root_cert_store.add_server_trust_anchors(
webpki_roots::TLS_SERVER_ROOTS.0.iter().map(|ta| {
rustls::OwnedTrustAnchor::from_subject_spki_name_constraints(
ta.subject,
ta.spki,
ta.name_constraints,
)
}),
);
}
"system" => {
let roots = load_native_certs().expect("could not load platform certs");
for root in roots {
root_cert_store
.add(&rustls::Certificate(root.0))
.expect("Failed to add platform cert to root cert store");
}
}
_ => {
return Err(anyhow!("Unknown certificate store \"{}\" specified (allowed: \"system,mozilla\")", store));
}
}
}
let ca_file = maybe_ca_file.or_else(|| env::var("DENO_CERT").ok());
if let Some(ca_file) = ca_file {
let ca_file = if let Some(root) = &maybe_root_path {
root.join(&ca_file)
} else {
PathBuf::from(ca_file)
};
let certfile = std::fs::File::open(&ca_file)?;
let mut reader = BufReader::new(certfile);
match rustls_pemfile::certs(&mut reader) {
Ok(certs) => {
root_cert_store.add_parsable_certificates(&certs);
}
Err(e) => {
return Err(anyhow!(
"Unable to add pem file to certificate store: {}",
e
));
}
}
}
Ok(root_cert_store)
}
/// Overrides for the options below that when set will /// Overrides for the options below that when set will
/// use these values over the values derived from the /// use these values over the values derived from the
/// CLI flags or config file. /// CLI flags or config file.
@ -176,7 +294,7 @@ impl CliOptions {
} else { } else {
std::env::current_dir()?.join("node_modules") std::env::current_dir()?.join("node_modules")
}; };
Ok(Some(fs_util::canonicalize_path_maybe_not_exists(&path)?)) Ok(Some(canonicalize_path_maybe_not_exists(&path)?))
} }
pub fn resolve_root_cert_store(&self) -> Result<RootCertStore, AnyError> { pub fn resolve_root_cert_store(&self) -> Result<RootCertStore, AnyError> {

View file

@ -1,7 +1,8 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use crate::fs_util; use super::http_cache::url_to_filename;
use crate::http_cache::url_to_filename; use super::CACHE_PERM;
use crate::util::fs::atomic_write_file;
use deno_core::url::Host; use deno_core::url::Host;
use deno_core::url::Url; use deno_core::url::Url;
@ -144,7 +145,7 @@ impl DiskCache {
Some(parent) => self.ensure_dir_exists(parent), Some(parent) => self.ensure_dir_exists(parent),
None => Ok(()), None => Ok(()),
}?; }?;
fs_util::atomic_write_file(&path, data, crate::http_cache::CACHE_PERM) atomic_write_file(&path, data, CACHE_PERM)
.map_err(|e| with_io_context(&e, format!("{:#?}", &path))) .map_err(|e| with_io_context(&e, format!("{:#?}", &path)))
} }
} }

View file

@ -3,8 +3,8 @@
//! as defined in RFC 7234 (<https://tools.ietf.org/html/rfc7234>). //! as defined in RFC 7234 (<https://tools.ietf.org/html/rfc7234>).
//! Currently it's a very simplified version to fulfill Deno needs //! Currently it's a very simplified version to fulfill Deno needs
//! at hand. //! at hand.
use crate::fs_util;
use crate::http_util::HeadersMap; use crate::http_util::HeadersMap;
use crate::util;
use deno_core::error::generic_error; use deno_core::error::generic_error;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::serde::Deserialize; use deno_core::serde::Deserialize;
@ -19,7 +19,7 @@ use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use std::time::SystemTime; use std::time::SystemTime;
pub const CACHE_PERM: u32 = 0o644; use super::CACHE_PERM;
/// Turn base of url (scheme, hostname, port) into a valid filename. /// Turn base of url (scheme, hostname, port) into a valid filename.
/// This method replaces port part with a special string token (because /// This method replaces port part with a special string token (because
@ -68,31 +68,32 @@ pub fn url_to_filename(url: &Url) -> Option<PathBuf> {
// NOTE: fragment is omitted on purpose - it's not taken into // NOTE: fragment is omitted on purpose - it's not taken into
// account when caching - it denotes parts of webpage, which // account when caching - it denotes parts of webpage, which
// in case of static resources doesn't make much sense // in case of static resources doesn't make much sense
let hashed_filename = crate::checksum::gen(&[rest_str.as_bytes()]); let hashed_filename = util::checksum::gen(&[rest_str.as_bytes()]);
cache_filename.push(hashed_filename); cache_filename.push(hashed_filename);
Some(cache_filename) Some(cache_filename)
} }
/// Cached metadata about a url.
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct Metadata { pub struct CachedUrlMetadata {
pub headers: HeadersMap, pub headers: HeadersMap,
pub url: String, pub url: String,
#[serde(default = "SystemTime::now")] #[serde(default = "SystemTime::now")]
pub now: SystemTime, pub now: SystemTime,
} }
impl Metadata { impl CachedUrlMetadata {
pub fn write(&self, cache_filename: &Path) -> Result<(), AnyError> { pub fn write(&self, cache_filename: &Path) -> Result<(), AnyError> {
let metadata_filename = Self::filename(cache_filename); let metadata_filename = Self::filename(cache_filename);
let json = serde_json::to_string_pretty(self)?; let json = serde_json::to_string_pretty(self)?;
fs_util::atomic_write_file(&metadata_filename, json, CACHE_PERM)?; util::fs::atomic_write_file(&metadata_filename, json, CACHE_PERM)?;
Ok(()) Ok(())
} }
pub fn read(cache_filename: &Path) -> Result<Metadata, AnyError> { pub fn read(cache_filename: &Path) -> Result<Self, AnyError> {
let metadata_filename = Metadata::filename(cache_filename); let metadata_filename = Self::filename(cache_filename);
let metadata = fs::read_to_string(metadata_filename)?; let metadata = fs::read_to_string(metadata_filename)?;
let metadata: Metadata = serde_json::from_str(&metadata)?; let metadata: Self = serde_json::from_str(&metadata)?;
Ok(metadata) Ok(metadata)
} }
@ -149,10 +150,10 @@ impl HttpCache {
url_to_filename(url) url_to_filename(url)
.ok_or_else(|| generic_error("Can't convert url to filename."))?, .ok_or_else(|| generic_error("Can't convert url to filename."))?,
); );
let metadata_filename = Metadata::filename(&cache_filename); let metadata_filename = CachedUrlMetadata::filename(&cache_filename);
let file = File::open(cache_filename)?; let file = File::open(cache_filename)?;
let metadata = fs::read_to_string(metadata_filename)?; let metadata = fs::read_to_string(metadata_filename)?;
let metadata: Metadata = serde_json::from_str(&metadata)?; let metadata: CachedUrlMetadata = serde_json::from_str(&metadata)?;
Ok((file, metadata.headers, metadata.now)) Ok((file, metadata.headers, metadata.now))
} }
@ -172,9 +173,9 @@ impl HttpCache {
.expect("Cache filename should have a parent dir"); .expect("Cache filename should have a parent dir");
self.ensure_dir_exists(parent_filename)?; self.ensure_dir_exists(parent_filename)?;
// Cache content // Cache content
fs_util::atomic_write_file(&cache_filename, content, CACHE_PERM)?; util::fs::atomic_write_file(&cache_filename, content, CACHE_PERM)?;
let metadata = Metadata { let metadata = CachedUrlMetadata {
now: SystemTime::now(), now: SystemTime::now(),
url: url.to_string(), url: url.to_string(),
headers: headers_map, headers: headers_map,

6
cli/cache/mod.rs vendored
View file

@ -19,6 +19,7 @@ mod common;
mod deno_dir; mod deno_dir;
mod disk_cache; mod disk_cache;
mod emit; mod emit;
mod http_cache;
mod incremental; mod incremental;
mod node; mod node;
mod parsed_source; mod parsed_source;
@ -28,10 +29,15 @@ pub use common::FastInsecureHasher;
pub use deno_dir::DenoDir; pub use deno_dir::DenoDir;
pub use disk_cache::DiskCache; pub use disk_cache::DiskCache;
pub use emit::EmitCache; pub use emit::EmitCache;
pub use http_cache::CachedUrlMetadata;
pub use http_cache::HttpCache;
pub use incremental::IncrementalCache; pub use incremental::IncrementalCache;
pub use node::NodeAnalysisCache; pub use node::NodeAnalysisCache;
pub use parsed_source::ParsedSourceCache; pub use parsed_source::ParsedSourceCache;
/// Permissions used to save a file in the disk caches.
pub const CACHE_PERM: u32 = 0o644;
/// A "wrapper" for the FileFetcher and DiskCache for the Deno CLI that provides /// A "wrapper" for the FileFetcher and DiskCache for the Deno CLI that provides
/// a concise interface to the DENO_DIR when building module graphs. /// a concise interface to the DENO_DIR when building module graphs.
pub struct FetchCacher { pub struct FetchCacher {

View file

@ -1,18 +1,18 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use crate::args::CacheSetting;
use crate::auth_tokens::AuthTokens; use crate::auth_tokens::AuthTokens;
use crate::cache::HttpCache;
use crate::colors; use crate::colors;
use crate::http_cache::HttpCache;
use crate::http_util::CacheSemantics; use crate::http_util::CacheSemantics;
use crate::http_util::FetchOnceArgs; use crate::http_util::FetchOnceArgs;
use crate::http_util::FetchOnceResult; use crate::http_util::FetchOnceResult;
use crate::http_util::HttpClient; use crate::http_util::HttpClient;
use crate::progress_bar::ProgressBar; use crate::util::progress_bar::ProgressBar;
use crate::text_encoding; use crate::util::text_encoding;
use data_url::DataUrl; use data_url::DataUrl;
use deno_ast::MediaType; use deno_ast::MediaType;
use deno_core::anyhow::anyhow;
use deno_core::error::custom_error; use deno_core::error::custom_error;
use deno_core::error::generic_error; use deno_core::error::generic_error;
use deno_core::error::uri_error; use deno_core::error::uri_error;
@ -21,11 +21,6 @@ use deno_core::futures;
use deno_core::futures::future::FutureExt; use deno_core::futures::future::FutureExt;
use deno_core::parking_lot::Mutex; use deno_core::parking_lot::Mutex;
use deno_core::ModuleSpecifier; use deno_core::ModuleSpecifier;
use deno_runtime::deno_tls::rustls;
use deno_runtime::deno_tls::rustls::RootCertStore;
use deno_runtime::deno_tls::rustls_native_certs::load_native_certs;
use deno_runtime::deno_tls::rustls_pemfile;
use deno_runtime::deno_tls::webpki_roots;
use deno_runtime::deno_web::BlobStore; use deno_runtime::deno_web::BlobStore;
use deno_runtime::permissions::Permissions; use deno_runtime::permissions::Permissions;
use log::debug; use log::debug;
@ -34,7 +29,6 @@ use std::collections::HashMap;
use std::env; use std::env;
use std::fs; use std::fs;
use std::future::Future; use std::future::Future;
use std::io::BufReader;
use std::io::Read; use std::io::Read;
use std::path::PathBuf; use std::path::PathBuf;
use std::pin::Pin; use std::pin::Pin;
@ -82,86 +76,6 @@ impl FileCache {
} }
} }
/// Indicates how cached source files should be handled.
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum CacheSetting {
/// Only the cached files should be used. Any files not in the cache will
/// error. This is the equivalent of `--cached-only` in the CLI.
Only,
/// No cached source files should be used, and all files should be reloaded.
/// This is the equivalent of `--reload` in the CLI.
ReloadAll,
/// Only some cached resources should be used. This is the equivalent of
/// `--reload=https://deno.land/std` or
/// `--reload=https://deno.land/std,https://deno.land/x/example`.
ReloadSome(Vec<String>),
/// The usability of a cached value is determined by analyzing the cached
/// headers and other metadata associated with a cached response, reloading
/// any cached "non-fresh" cached responses.
RespectHeaders,
/// The cached source files should be used for local modules. This is the
/// default behavior of the CLI.
Use,
}
impl CacheSetting {
/// Returns if the cache should be used for a given specifier.
pub fn should_use(
&self,
specifier: &ModuleSpecifier,
http_cache: &HttpCache,
) -> bool {
match self {
CacheSetting::ReloadAll => false,
CacheSetting::Use | CacheSetting::Only => true,
CacheSetting::RespectHeaders => {
if let Ok((_, headers, cache_time)) = http_cache.get(specifier) {
let cache_semantics =
CacheSemantics::new(headers, cache_time, SystemTime::now());
cache_semantics.should_use()
} else {
false
}
}
CacheSetting::ReloadSome(list) => {
let mut url = specifier.clone();
url.set_fragment(None);
if list.contains(&url.as_str().to_string()) {
return false;
}
url.set_query(None);
let mut path = PathBuf::from(url.as_str());
loop {
if list.contains(&path.to_str().unwrap().to_string()) {
return false;
}
if !path.pop() {
break;
}
}
true
}
}
}
pub fn should_use_for_npm_package(&self, package_name: &str) -> bool {
match self {
CacheSetting::ReloadAll => false,
CacheSetting::ReloadSome(list) => {
if list.contains(&"npm:".to_string()) {
return false;
}
let specifier = format!("npm:{}", package_name);
if list.contains(&specifier) {
return false;
}
true
}
_ => true,
}
}
}
/// Fetch a source file from the local file system. /// Fetch a source file from the local file system.
fn fetch_local(specifier: &ModuleSpecifier) -> Result<File, AnyError> { fn fetch_local(specifier: &ModuleSpecifier) -> Result<File, AnyError> {
let local = specifier.to_file_path().map_err(|_| { let local = specifier.to_file_path().map_err(|_| {
@ -182,80 +96,6 @@ fn fetch_local(specifier: &ModuleSpecifier) -> Result<File, AnyError> {
}) })
} }
/// Create and populate a root cert store based on the passed options and
/// environment.
pub fn get_root_cert_store(
maybe_root_path: Option<PathBuf>,
maybe_ca_stores: Option<Vec<String>>,
maybe_ca_file: Option<String>,
) -> Result<RootCertStore, AnyError> {
let mut root_cert_store = RootCertStore::empty();
let ca_stores: Vec<String> = maybe_ca_stores
.or_else(|| {
let env_ca_store = env::var("DENO_TLS_CA_STORE").ok()?;
Some(
env_ca_store
.split(',')
.map(|s| s.trim().to_string())
.filter(|s| !s.is_empty())
.collect(),
)
})
.unwrap_or_else(|| vec!["mozilla".to_string()]);
for store in ca_stores.iter() {
match store.as_str() {
"mozilla" => {
root_cert_store.add_server_trust_anchors(
webpki_roots::TLS_SERVER_ROOTS.0.iter().map(|ta| {
rustls::OwnedTrustAnchor::from_subject_spki_name_constraints(
ta.subject,
ta.spki,
ta.name_constraints,
)
}),
);
}
"system" => {
let roots = load_native_certs().expect("could not load platform certs");
for root in roots {
root_cert_store
.add(&rustls::Certificate(root.0))
.expect("Failed to add platform cert to root cert store");
}
}
_ => {
return Err(anyhow!("Unknown certificate store \"{}\" specified (allowed: \"system,mozilla\")", store));
}
}
}
let ca_file = maybe_ca_file.or_else(|| env::var("DENO_CERT").ok());
if let Some(ca_file) = ca_file {
let ca_file = if let Some(root) = &maybe_root_path {
root.join(&ca_file)
} else {
PathBuf::from(ca_file)
};
let certfile = fs::File::open(&ca_file)?;
let mut reader = BufReader::new(certfile);
match rustls_pemfile::certs(&mut reader) {
Ok(certs) => {
root_cert_store.add_parsable_certificates(&certs);
}
Err(e) => {
return Err(anyhow!(
"Unable to add pem file to certificate store: {}",
e
));
}
}
}
Ok(root_cert_store)
}
/// Returns the decoded body and content-type of a provided /// Returns the decoded body and content-type of a provided
/// data URL. /// data URL.
pub fn get_source_from_data_url( pub fn get_source_from_data_url(
@ -571,7 +411,7 @@ impl FileFetcher {
return futures::future::err(err).boxed(); return futures::future::err(err).boxed();
} }
if self.cache_setting.should_use(specifier, &self.http_cache) { if self.should_use_cache(specifier) {
match self.fetch_cached(specifier, redirect_limit) { match self.fetch_cached(specifier, redirect_limit) {
Ok(Some(file)) => { Ok(Some(file)) => {
return futures::future::ok(file).boxed(); return futures::future::ok(file).boxed();
@ -654,6 +494,41 @@ impl FileFetcher {
.boxed() .boxed()
} }
/// Returns if the cache should be used for a given specifier.
fn should_use_cache(&self, specifier: &ModuleSpecifier) -> bool {
match &self.cache_setting {
CacheSetting::ReloadAll => false,
CacheSetting::Use | CacheSetting::Only => true,
CacheSetting::RespectHeaders => {
if let Ok((_, headers, cache_time)) = self.http_cache.get(specifier) {
let cache_semantics =
CacheSemantics::new(headers, cache_time, SystemTime::now());
cache_semantics.should_use()
} else {
false
}
}
CacheSetting::ReloadSome(list) => {
let mut url = specifier.clone();
url.set_fragment(None);
if list.contains(&url.as_str().to_string()) {
return false;
}
url.set_query(None);
let mut path = PathBuf::from(url.as_str());
loop {
if list.contains(&path.to_str().unwrap().to_string()) {
return false;
}
if !path.pop() {
break;
}
}
true
}
}
}
/// Fetch a source file and asynchronously return it. /// Fetch a source file and asynchronously return it.
pub async fn fetch( pub async fn fetch(
&self, &self,
@ -754,6 +629,7 @@ impl FileFetcher {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::cache::CachedUrlMetadata;
use crate::http_util::HttpClient; use crate::http_util::HttpClient;
use super::*; use super::*;
@ -1175,8 +1051,7 @@ mod tests {
.http_cache .http_cache
.get_cache_filename(&specifier) .get_cache_filename(&specifier)
.unwrap(); .unwrap();
let mut metadata = let mut metadata = CachedUrlMetadata::read(&cache_filename).unwrap();
crate::http_cache::Metadata::read(&cache_filename).unwrap();
metadata.headers = HashMap::new(); metadata.headers = HashMap::new();
metadata metadata
.headers .headers
@ -1265,8 +1140,7 @@ mod tests {
.await; .await;
assert!(result.is_ok()); assert!(result.is_ok());
let metadata_filename = let metadata_filename = CachedUrlMetadata::filename(&cache_filename);
crate::http_cache::Metadata::filename(&cache_filename);
let metadata_file = fs::File::open(metadata_filename).unwrap(); let metadata_file = fs::File::open(metadata_filename).unwrap();
let metadata_file_metadata = metadata_file.metadata().unwrap(); let metadata_file_metadata = metadata_file.metadata().unwrap();
let metadata_file_modified_01 = metadata_file_metadata.modified().unwrap(); let metadata_file_modified_01 = metadata_file_metadata.modified().unwrap();
@ -1285,8 +1159,7 @@ mod tests {
.await; .await;
assert!(result.is_ok()); assert!(result.is_ok());
let metadata_filename = let metadata_filename = CachedUrlMetadata::filename(&cache_filename);
crate::http_cache::Metadata::filename(&cache_filename);
let metadata_file = fs::File::open(metadata_filename).unwrap(); let metadata_file = fs::File::open(metadata_filename).unwrap();
let metadata_file_metadata = metadata_file.metadata().unwrap(); let metadata_file_metadata = metadata_file.metadata().unwrap();
let metadata_file_modified_02 = metadata_file_metadata.modified().unwrap(); let metadata_file_modified_02 = metadata_file_metadata.modified().unwrap();
@ -1438,7 +1311,7 @@ mod tests {
assert!(result.is_ok()); assert!(result.is_ok());
let metadata_filename = let metadata_filename =
crate::http_cache::Metadata::filename(&redirected_cache_filename); CachedUrlMetadata::filename(&redirected_cache_filename);
let metadata_file = fs::File::open(metadata_filename).unwrap(); let metadata_file = fs::File::open(metadata_filename).unwrap();
let metadata_file_metadata = metadata_file.metadata().unwrap(); let metadata_file_metadata = metadata_file.metadata().unwrap();
let metadata_file_modified_01 = metadata_file_metadata.modified().unwrap(); let metadata_file_modified_01 = metadata_file_metadata.modified().unwrap();
@ -1458,7 +1331,7 @@ mod tests {
assert!(result.is_ok()); assert!(result.is_ok());
let metadata_filename = let metadata_filename =
crate::http_cache::Metadata::filename(&redirected_cache_filename); CachedUrlMetadata::filename(&redirected_cache_filename);
let metadata_file = fs::File::open(metadata_filename).unwrap(); let metadata_file = fs::File::open(metadata_filename).unwrap();
let metadata_file_metadata = metadata_file.metadata().unwrap(); let metadata_file_metadata = metadata_file.metadata().unwrap();
let metadata_file_modified_02 = metadata_file_metadata.modified().unwrap(); let metadata_file_modified_02 = metadata_file_metadata.modified().unwrap();

View file

@ -1,6 +1,7 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use crate::http_cache; use crate::cache::CachedUrlMetadata;
use crate::cache::HttpCache;
use deno_core::parking_lot::Mutex; use deno_core::parking_lot::Mutex;
use deno_core::ModuleSpecifier; use deno_core::ModuleSpecifier;
@ -49,14 +50,14 @@ struct Metadata {
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
pub struct CacheMetadata { pub struct CacheMetadata {
cache: http_cache::HttpCache, cache: HttpCache,
metadata: Arc<Mutex<HashMap<ModuleSpecifier, Metadata>>>, metadata: Arc<Mutex<HashMap<ModuleSpecifier, Metadata>>>,
} }
impl CacheMetadata { impl CacheMetadata {
pub fn new(location: &Path) -> Self { pub fn new(location: &Path) -> Self {
Self { Self {
cache: http_cache::HttpCache::new(location), cache: HttpCache::new(location),
metadata: Default::default(), metadata: Default::default(),
} }
} }
@ -87,8 +88,7 @@ impl CacheMetadata {
return None; return None;
} }
let cache_filename = self.cache.get_cache_filename(specifier)?; let cache_filename = self.cache.get_cache_filename(specifier)?;
let specifier_metadata = let specifier_metadata = CachedUrlMetadata::read(&cache_filename).ok()?;
http_cache::Metadata::read(&cache_filename).ok()?;
let values = Arc::new(parse_metadata(&specifier_metadata.headers)); let values = Arc::new(parse_metadata(&specifier_metadata.headers));
let version = calculate_fs_version(&cache_filename); let version = calculate_fs_version(&cache_filename);
let mut metadata_map = self.metadata.lock(); let mut metadata_map = self.metadata.lock();
@ -98,7 +98,7 @@ impl CacheMetadata {
} }
pub fn set_location(&mut self, location: &Path) { pub fn set_location(&mut self, location: &Path) {
self.cache = http_cache::HttpCache::new(location); self.cache = HttpCache::new(location);
self.metadata.lock().clear(); self.metadata.lock().clear();
} }
} }

View file

@ -7,9 +7,9 @@ use super::lsp_custom;
use super::registries::ModuleRegistry; use super::registries::ModuleRegistry;
use super::tsc; use super::tsc;
use crate::fs_util::is_supported_ext; use crate::util::path::is_supported_ext;
use crate::fs_util::relative_specifier; use crate::util::path::relative_specifier;
use crate::fs_util::specifier_to_file_path; use crate::util::path::specifier_to_file_path;
use deno_ast::LineAndColumnIndex; use deno_ast::LineAndColumnIndex;
use deno_ast::SourceTextInfo; use deno_ast::SourceTextInfo;
@ -505,7 +505,7 @@ fn get_workspace_completions(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::http_cache::HttpCache; use crate::cache::HttpCache;
use crate::lsp::documents::Documents; use crate::lsp::documents::Documents;
use crate::lsp::documents::LanguageId; use crate::lsp::documents::LanguageId;
use deno_core::resolve_url; use deno_core::resolve_url;

View file

@ -2,7 +2,8 @@
use super::client::Client; use super::client::Client;
use super::logging::lsp_log; use super::logging::lsp_log;
use crate::fs_util; use crate::util::path::ensure_directory_specifier;
use crate::util::path::specifier_to_file_path;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::serde::Deserialize; use deno_core::serde::Deserialize;
use deno_core::serde::Serialize; use deno_core::serde::Serialize;
@ -549,11 +550,11 @@ impl Config {
workspace: &ModuleSpecifier, workspace: &ModuleSpecifier,
enabled_paths: Vec<String>, enabled_paths: Vec<String>,
) -> bool { ) -> bool {
let workspace = fs_util::ensure_directory_specifier(workspace.clone()); let workspace = ensure_directory_specifier(workspace.clone());
let key = workspace.to_string(); let key = workspace.to_string();
let mut touched = false; let mut touched = false;
if !enabled_paths.is_empty() { if !enabled_paths.is_empty() {
if let Ok(workspace_path) = fs_util::specifier_to_file_path(&workspace) { if let Ok(workspace_path) = specifier_to_file_path(&workspace) {
let mut paths = Vec::new(); let mut paths = Vec::new();
for path in &enabled_paths { for path in &enabled_paths {
let fs_path = workspace_path.join(path); let fs_path = workspace_path.join(path);

View file

@ -6,12 +6,11 @@ use super::tsc;
use super::tsc::AssetDocument; use super::tsc::AssetDocument;
use crate::args::ConfigFile; use crate::args::ConfigFile;
use crate::cache::CachedUrlMetadata;
use crate::cache::HttpCache;
use crate::file_fetcher::get_source_from_bytes; use crate::file_fetcher::get_source_from_bytes;
use crate::file_fetcher::map_content_type; use crate::file_fetcher::map_content_type;
use crate::file_fetcher::SUPPORTED_SCHEMES; use crate::file_fetcher::SUPPORTED_SCHEMES;
use crate::fs_util::specifier_to_file_path;
use crate::http_cache;
use crate::http_cache::HttpCache;
use crate::node; use crate::node;
use crate::node::node_resolve_npm_reference; use crate::node::node_resolve_npm_reference;
use crate::node::NodeResolution; use crate::node::NodeResolution;
@ -20,7 +19,8 @@ use crate::npm::NpmPackageReference;
use crate::npm::NpmPackageReq; use crate::npm::NpmPackageReq;
use crate::npm::NpmPackageResolver; use crate::npm::NpmPackageResolver;
use crate::resolver::CliResolver; use crate::resolver::CliResolver;
use crate::text_encoding; use crate::util::path::specifier_to_file_path;
use crate::util::text_encoding;
use deno_ast::MediaType; use deno_ast::MediaType;
use deno_ast::ParsedSource; use deno_ast::ParsedSource;
@ -610,7 +610,7 @@ impl SpecifierResolver {
) -> Option<ModuleSpecifier> { ) -> Option<ModuleSpecifier> {
let cache_filename = self.cache.get_cache_filename(specifier)?; let cache_filename = self.cache.get_cache_filename(specifier)?;
if redirect_limit > 0 && cache_filename.is_file() { if redirect_limit > 0 && cache_filename.is_file() {
let headers = http_cache::Metadata::read(&cache_filename) let headers = CachedUrlMetadata::read(&cache_filename)
.ok() .ok()
.map(|m| m.headers)?; .map(|m| m.headers)?;
if let Some(location) = headers.get("location") { if let Some(location) = headers.get("location") {
@ -657,8 +657,7 @@ impl FileSystemDocuments {
) )
} else { } else {
let cache_filename = cache.get_cache_filename(specifier)?; let cache_filename = cache.get_cache_filename(specifier)?;
let specifier_metadata = let specifier_metadata = CachedUrlMetadata::read(&cache_filename).ok()?;
http_cache::Metadata::read(&cache_filename).ok()?;
let maybe_content_type = let maybe_content_type =
specifier_metadata.headers.get("content-type").cloned(); specifier_metadata.headers.get("content-type").cloned();
let maybe_headers = Some(&specifier_metadata.headers); let maybe_headers = Some(&specifier_metadata.headers);

View file

@ -57,6 +57,8 @@ use super::tsc::Assets;
use super::tsc::AssetsSnapshot; use super::tsc::AssetsSnapshot;
use super::tsc::TsServer; use super::tsc::TsServer;
use super::urls; use super::urls;
use crate::args::get_root_cert_store;
use crate::args::CacheSetting;
use crate::args::CliOptions; use crate::args::CliOptions;
use crate::args::ConfigFile; use crate::args::ConfigFile;
use crate::args::Flags; use crate::args::Flags;
@ -64,10 +66,7 @@ use crate::args::FmtConfig;
use crate::args::LintConfig; use crate::args::LintConfig;
use crate::args::TsConfig; use crate::args::TsConfig;
use crate::cache::DenoDir; use crate::cache::DenoDir;
use crate::file_fetcher::get_root_cert_store;
use crate::file_fetcher::get_source_from_data_url; use crate::file_fetcher::get_source_from_data_url;
use crate::file_fetcher::CacheSetting;
use crate::fs_util;
use crate::graph_util::graph_valid; use crate::graph_util::graph_valid;
use crate::http_util::HttpClient; use crate::http_util::HttpClient;
use crate::npm::NpmCache; use crate::npm::NpmCache;
@ -75,9 +74,12 @@ use crate::npm::NpmPackageResolver;
use crate::npm::RealNpmRegistryApi; use crate::npm::RealNpmRegistryApi;
use crate::proc_state::import_map_from_text; use crate::proc_state::import_map_from_text;
use crate::proc_state::ProcState; use crate::proc_state::ProcState;
use crate::progress_bar::ProgressBar;
use crate::tools::fmt::format_file; use crate::tools::fmt::format_file;
use crate::tools::fmt::format_parsed_source; use crate::tools::fmt::format_parsed_source;
use crate::util::fs::remove_dir_all_if_exists;
use crate::util::path::ensure_directory_specifier;
use crate::util::path::specifier_to_file_path;
use crate::util::progress_bar::ProgressBar;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct LanguageServer(Arc<tokio::sync::Mutex<Inner>>); pub struct LanguageServer(Arc<tokio::sync::Mutex<Inner>>);
@ -407,7 +409,7 @@ impl Inner {
// file open and not a workspace. In those situations we can't // file open and not a workspace. In those situations we can't
// automatically discover the configuration // automatically discover the configuration
if let Some(root_uri) = &self.config.root_uri { if let Some(root_uri) = &self.config.root_uri {
let root_path = fs_util::specifier_to_file_path(root_uri)?; let root_path = specifier_to_file_path(root_uri)?;
let mut checked = std::collections::HashSet::new(); let mut checked = std::collections::HashSet::new();
let maybe_config = ConfigFile::discover_from(&root_path, &mut checked)?; let maybe_config = ConfigFile::discover_from(&root_path, &mut checked)?;
Ok(maybe_config.map(|c| { Ok(maybe_config.map(|c| {
@ -481,7 +483,7 @@ impl Inner {
let cache_url = if let Ok(url) = Url::from_file_path(cache_str) { let cache_url = if let Ok(url) = Url::from_file_path(cache_str) {
Ok(url) Ok(url)
} else if let Some(root_uri) = &self.config.root_uri { } else if let Some(root_uri) = &self.config.root_uri {
let root_path = fs_util::specifier_to_file_path(root_uri)?; let root_path = specifier_to_file_path(root_uri)?;
let cache_path = root_path.join(cache_str); let cache_path = root_path.join(cache_str);
Url::from_file_path(cache_path).map_err(|_| { Url::from_file_path(cache_path).map_err(|_| {
anyhow!("Bad file path for import path: {:?}", cache_str) anyhow!("Bad file path for import path: {:?}", cache_str)
@ -492,7 +494,7 @@ impl Inner {
cache_str cache_str
)) ))
}?; }?;
let cache_path = fs_util::specifier_to_file_path(&cache_url)?; let cache_path = specifier_to_file_path(&cache_url)?;
lsp_log!( lsp_log!(
" Resolved cache path: \"{}\"", " Resolved cache path: \"{}\"",
cache_path.to_string_lossy() cache_path.to_string_lossy()
@ -521,7 +523,7 @@ impl Inner {
.config .config
.root_uri .root_uri
.as_ref() .as_ref()
.and_then(|uri| fs_util::specifier_to_file_path(uri).ok()); .and_then(|uri| specifier_to_file_path(uri).ok());
let root_cert_store = Some(get_root_cert_store( let root_cert_store = Some(get_root_cert_store(
maybe_root_path, maybe_root_path,
workspace_settings.certificate_stores.clone(), workspace_settings.certificate_stores.clone(),
@ -569,7 +571,7 @@ impl Inner {
anyhow!("Bad data url for import map: {}", import_map_str) anyhow!("Bad data url for import map: {}", import_map_str)
})?) })?)
} else if let Some(root_uri) = &self.config.root_uri { } else if let Some(root_uri) = &self.config.root_uri {
let root_path = fs_util::specifier_to_file_path(root_uri)?; let root_path = specifier_to_file_path(root_uri)?;
let import_map_path = root_path.join(&import_map_str); let import_map_path = root_path.join(&import_map_str);
Some(Url::from_file_path(import_map_path).map_err(|_| { Some(Url::from_file_path(import_map_path).map_err(|_| {
anyhow!("Bad file path for import map: {}", import_map_str) anyhow!("Bad file path for import map: {}", import_map_str)
@ -612,7 +614,7 @@ impl Inner {
let import_map_json = if import_map_url.scheme() == "data" { let import_map_json = if import_map_url.scheme() == "data" {
get_source_from_data_url(&import_map_url)?.0 get_source_from_data_url(&import_map_url)?.0
} else { } else {
let import_map_path = fs_util::specifier_to_file_path(&import_map_url)?; let import_map_path = specifier_to_file_path(&import_map_url)?;
lsp_log!( lsp_log!(
" Resolved import map: \"{}\"", " Resolved import map: \"{}\"",
import_map_path.to_string_lossy() import_map_path.to_string_lossy()
@ -768,7 +770,7 @@ impl Inner {
self.config.root_uri = params self.config.root_uri = params
.root_uri .root_uri
.map(|s| self.url_map.normalize_url(&s)) .map(|s| self.url_map.normalize_url(&s))
.map(fs_util::ensure_directory_specifier); .map(ensure_directory_specifier);
if let Some(value) = params.initialization_options { if let Some(value) = params.initialization_options {
self.config.set_workspace_settings(value).map_err(|err| { self.config.set_workspace_settings(value).map_err(|err| {
@ -1137,11 +1139,10 @@ impl Inner {
_ => return Ok(None), _ => return Ok(None),
}; };
let mark = self.performance.mark("formatting", Some(&params)); let mark = self.performance.mark("formatting", Some(&params));
let file_path = let file_path = specifier_to_file_path(&specifier).map_err(|err| {
fs_util::specifier_to_file_path(&specifier).map_err(|err| { error!("{}", err);
error!("{}", err); LspError::invalid_request()
LspError::invalid_request() })?;
})?;
let fmt_options = if let Some(fmt_config) = self.maybe_fmt_config.as_ref() { let fmt_options = if let Some(fmt_config) = self.maybe_fmt_config.as_ref() {
// skip formatting any files ignored by the config file // skip formatting any files ignored by the config file
@ -2063,7 +2064,7 @@ impl Inner {
.config .config
.root_uri .root_uri
.as_ref() .as_ref()
.and_then(|uri| fs_util::specifier_to_file_path(uri).ok()); .and_then(|uri| specifier_to_file_path(uri).ok());
let mut resolved_items = Vec::<CallHierarchyIncomingCall>::new(); let mut resolved_items = Vec::<CallHierarchyIncomingCall>::new();
for item in incoming_calls.iter() { for item in incoming_calls.iter() {
if let Some(resolved) = item.try_resolve_call_hierarchy_incoming_call( if let Some(resolved) = item.try_resolve_call_hierarchy_incoming_call(
@ -2109,7 +2110,7 @@ impl Inner {
.config .config
.root_uri .root_uri
.as_ref() .as_ref()
.and_then(|uri| fs_util::specifier_to_file_path(uri).ok()); .and_then(|uri| specifier_to_file_path(uri).ok());
let mut resolved_items = Vec::<CallHierarchyOutgoingCall>::new(); let mut resolved_items = Vec::<CallHierarchyOutgoingCall>::new();
for item in outgoing_calls.iter() { for item in outgoing_calls.iter() {
if let Some(resolved) = item.try_resolve_call_hierarchy_outgoing_call( if let Some(resolved) = item.try_resolve_call_hierarchy_outgoing_call(
@ -2162,7 +2163,7 @@ impl Inner {
.config .config
.root_uri .root_uri
.as_ref() .as_ref()
.and_then(|uri| fs_util::specifier_to_file_path(uri).ok()); .and_then(|uri| specifier_to_file_path(uri).ok());
let mut resolved_items = Vec::<CallHierarchyItem>::new(); let mut resolved_items = Vec::<CallHierarchyItem>::new();
match one_or_many { match one_or_many {
tsc::OneOrMany::One(item) => { tsc::OneOrMany::One(item) => {
@ -3010,7 +3011,7 @@ impl Inner {
} }
async fn reload_import_registries(&mut self) -> LspResult<Option<Value>> { async fn reload_import_registries(&mut self) -> LspResult<Option<Value>> {
fs_util::remove_dir_all_if_exists(&self.module_registries_location) remove_dir_all_if_exists(&self.module_registries_location)
.await .await
.map_err(|err| { .map_err(|err| {
error!("Unable to remove registries cache: {}", err); error!("Unable to remove registries cache: {}", err);

View file

@ -12,10 +12,10 @@ use super::path_to_regex::StringOrNumber;
use super::path_to_regex::StringOrVec; use super::path_to_regex::StringOrVec;
use super::path_to_regex::Token; use super::path_to_regex::Token;
use crate::args::CacheSetting;
use crate::cache::DenoDir; use crate::cache::DenoDir;
use crate::file_fetcher::CacheSetting; use crate::cache::HttpCache;
use crate::file_fetcher::FileFetcher; use crate::file_fetcher::FileFetcher;
use crate::http_cache::HttpCache;
use crate::http_util::HttpClient; use crate::http_util::HttpClient;
use deno_core::anyhow::anyhow; use deno_core::anyhow::anyhow;

View file

@ -2,9 +2,9 @@
use super::lsp_custom; use super::lsp_custom;
use crate::checksum;
use crate::lsp::analysis::source_range_to_lsp_range; use crate::lsp::analysis::source_range_to_lsp_range;
use crate::lsp::client::TestingNotification; use crate::lsp::client::TestingNotification;
use crate::util::checksum;
use deno_ast::SourceRange; use deno_ast::SourceRange;
use deno_ast::SourceTextInfo; use deno_ast::SourceTextInfo;

View file

@ -6,7 +6,6 @@ use super::lsp_custom;
use crate::args::flags_from_vec; use crate::args::flags_from_vec;
use crate::args::DenoSubcommand; use crate::args::DenoSubcommand;
use crate::checksum;
use crate::lsp::client::Client; use crate::lsp::client::Client;
use crate::lsp::client::TestingNotification; use crate::lsp::client::TestingNotification;
use crate::lsp::config; use crate::lsp::config;
@ -15,6 +14,7 @@ use crate::ops;
use crate::proc_state; use crate::proc_state;
use crate::tools::test; use crate::tools::test;
use crate::tools::test::TestEventSender; use crate::tools::test::TestEventSender;
use crate::util::checksum;
use crate::worker::create_main_worker_for_test_or_bench; use crate::worker::create_main_worker_for_test_or_bench;
use deno_core::anyhow::anyhow; use deno_core::anyhow::anyhow;

View file

@ -18,10 +18,10 @@ use super::urls::LspUrlMap;
use super::urls::INVALID_SPECIFIER; use super::urls::INVALID_SPECIFIER;
use crate::args::TsConfig; use crate::args::TsConfig;
use crate::fs_util::relative_specifier;
use crate::fs_util::specifier_to_file_path;
use crate::tsc; use crate::tsc;
use crate::tsc::ResolveArgs; use crate::tsc::ResolveArgs;
use crate::util::path::relative_specifier;
use crate::util::path::specifier_to_file_path;
use deno_core::anyhow::anyhow; use deno_core::anyhow::anyhow;
use deno_core::error::custom_error; use deno_core::error::custom_error;
@ -3445,7 +3445,7 @@ pub fn request(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::http_cache::HttpCache; use crate::cache::HttpCache;
use crate::http_util::HeadersMap; use crate::http_util::HeadersMap;
use crate::lsp::config::WorkspaceSettings; use crate::lsp::config::WorkspaceSettings;
use crate::lsp::documents::Documents; use crate::lsp::documents::Documents;

View file

@ -56,7 +56,7 @@ fn hash_data_specifier(specifier: &ModuleSpecifier) -> String {
file_name_str.push('?'); file_name_str.push('?');
file_name_str.push_str(query); file_name_str.push_str(query);
} }
crate::checksum::gen(&[file_name_str.as_bytes()]) crate::util::checksum::gen(&[file_name_str.as_bytes()])
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]

View file

@ -3,20 +3,13 @@
mod args; mod args;
mod auth_tokens; mod auth_tokens;
mod cache; mod cache;
mod checksum;
mod deno_std; mod deno_std;
mod diff;
mod display;
mod emit; mod emit;
mod errors; mod errors;
mod file_fetcher; mod file_fetcher;
mod file_watcher;
mod fs_util;
mod graph_util; mod graph_util;
mod http_cache;
mod http_util; mod http_util;
mod js; mod js;
mod logger;
mod lsp; mod lsp;
mod module_loader; mod module_loader;
mod napi; mod napi;
@ -24,15 +17,12 @@ mod node;
mod npm; mod npm;
mod ops; mod ops;
mod proc_state; mod proc_state;
mod progress_bar;
mod resolver; mod resolver;
mod standalone; mod standalone;
mod text_encoding;
mod tools; mod tools;
mod tsc; mod tsc;
mod unix_util; mod util;
mod version; mod version;
mod windows_util;
mod worker; mod worker;
use crate::args::flags_from_vec; use crate::args::flags_from_vec;
@ -63,11 +53,12 @@ use crate::args::UpgradeFlags;
use crate::args::VendorFlags; use crate::args::VendorFlags;
use crate::cache::TypeCheckCache; use crate::cache::TypeCheckCache;
use crate::file_fetcher::File; use crate::file_fetcher::File;
use crate::file_watcher::ResolutionResult;
use crate::graph_util::graph_lock_or_exit; use crate::graph_util::graph_lock_or_exit;
use crate::proc_state::ProcState; use crate::proc_state::ProcState;
use crate::resolver::CliResolver; use crate::resolver::CliResolver;
use crate::tools::check; use crate::tools::check;
use crate::util::display;
use crate::util::file_watcher::ResolutionResult;
use args::CliOptions; use args::CliOptions;
use args::Lockfile; use args::Lockfile;
@ -482,7 +473,7 @@ async fn bundle_command(
if let Some(out_file) = out_file.as_ref() { if let Some(out_file) = out_file.as_ref() {
let output_bytes = bundle_output.code.as_bytes(); let output_bytes = bundle_output.code.as_bytes();
let output_len = output_bytes.len(); let output_len = output_bytes.len();
fs_util::write_file(out_file, output_bytes, 0o644)?; util::fs::write_file(out_file, output_bytes, 0o644)?;
info!( info!(
"{} {:?} ({})", "{} {:?} ({})",
colors::green("Emit"), colors::green("Emit"),
@ -498,7 +489,7 @@ async fn bundle_command(
"map".to_string() "map".to_string()
}; };
let map_out_file = out_file.with_extension(ext); let map_out_file = out_file.with_extension(ext);
fs_util::write_file(&map_out_file, map_bytes, 0o644)?; util::fs::write_file(&map_out_file, map_bytes, 0o644)?;
info!( info!(
"{} {:?} ({})", "{} {:?} ({})",
colors::green("Emit"), colors::green("Emit"),
@ -515,10 +506,10 @@ async fn bundle_command(
}; };
if cli_options.watch_paths().is_some() { if cli_options.watch_paths().is_some() {
file_watcher::watch_func( util::file_watcher::watch_func(
resolver, resolver,
operation, operation,
file_watcher::PrintConfig { util::file_watcher::PrintConfig {
job_name: "Bundle".to_string(), job_name: "Bundle".to_string(),
clear_screen: !cli_options.no_clear_screen(), clear_screen: !cli_options.no_clear_screen(),
}, },
@ -660,11 +651,11 @@ async fn run_with_watch(flags: Flags, script: String) -> Result<i32, AnyError> {
}) })
}; };
file_watcher::watch_func2( util::file_watcher::watch_func2(
receiver, receiver,
operation, operation,
(sender, main_module), (sender, main_module),
file_watcher::PrintConfig { util::file_watcher::PrintConfig {
job_name: "Process".to_string(), job_name: "Process".to_string(),
clear_screen: !flags.no_clear_screen, clear_screen: !flags.no_clear_screen,
}, },
@ -952,8 +943,8 @@ fn unwrap_or_exit<T>(result: Result<T, AnyError>) -> T {
pub fn main() { pub fn main() {
setup_panic_hook(); setup_panic_hook();
unix_util::raise_fd_limit(); util::unix::raise_fd_limit();
windows_util::ensure_stdio_open(); util::windows::ensure_stdio_open();
#[cfg(windows)] #[cfg(windows)]
colors::enable_ansi(); // For Windows 10 colors::enable_ansi(); // For Windows 10
@ -984,7 +975,7 @@ pub fn main() {
init_v8_flags(&flags.v8_flags); init_v8_flags(&flags.v8_flags);
} }
logger::init(flags.log_level); util::logger::init(flags.log_level);
get_subcommand(flags).await get_subcommand(flags).await
}; };

View file

@ -5,8 +5,8 @@ use crate::emit::emit_parsed_source;
use crate::graph_util::ModuleEntry; use crate::graph_util::ModuleEntry;
use crate::node; use crate::node;
use crate::proc_state::ProcState; use crate::proc_state::ProcState;
use crate::text_encoding::code_without_source_map; use crate::util::text_encoding::code_without_source_map;
use crate::text_encoding::source_map_from_code; use crate::util::text_encoding::source_map_from_code;
use deno_ast::MediaType; use deno_ast::MediaType;
use deno_core::anyhow::anyhow; use deno_core::anyhow::anyhow;

View file

@ -20,7 +20,7 @@ pub fn napi_sym(_attr: TokenStream, item: TokenStream) -> TokenStream {
let name = &func.sig.ident; let name = &func.sig.ident;
assert!( assert!(
exports.symbols.contains(&name.to_string()), exports.symbols.contains(&name.to_string()),
"tools/napi/symbol_exports.json is out of sync!" "tools/napi/sym/symbol_exports.json is out of sync!"
); );
let block = &func.block; let block = &func.block;

View file

@ -14,11 +14,13 @@ use deno_core::error::AnyError;
use deno_core::parking_lot::Mutex; use deno_core::parking_lot::Mutex;
use deno_core::url::Url; use deno_core::url::Url;
use crate::args::CacheSetting;
use crate::cache::DenoDir; use crate::cache::DenoDir;
use crate::file_fetcher::CacheSetting;
use crate::fs_util;
use crate::http_util::HttpClient; use crate::http_util::HttpClient;
use crate::progress_bar::ProgressBar; use crate::util::fs::canonicalize_path;
use crate::util::fs::hard_link_dir_recursive;
use crate::util::path::root_url_to_safe_local_dirname;
use crate::util::progress_bar::ProgressBar;
use super::registry::NpmPackageVersionDistInfo; use super::registry::NpmPackageVersionDistInfo;
use super::semver::NpmVersion; use super::semver::NpmVersion;
@ -162,7 +164,7 @@ impl ReadonlyNpmCache {
std::fs::create_dir_all(root_dir) std::fs::create_dir_all(root_dir)
.with_context(|| format!("Error creating {}", root_dir.display()))?; .with_context(|| format!("Error creating {}", root_dir.display()))?;
} }
Ok(crate::fs_util::canonicalize_path(root_dir)?) Ok(canonicalize_path(root_dir)?)
} }
// this may fail on readonly file systems, so just ignore if so // this may fail on readonly file systems, so just ignore if so
@ -227,7 +229,7 @@ impl ReadonlyNpmCache {
pub fn registry_folder(&self, registry_url: &Url) -> PathBuf { pub fn registry_folder(&self, registry_url: &Url) -> PathBuf {
self self
.root_dir .root_dir
.join(fs_util::root_url_to_safe_local_dirname(registry_url)) .join(root_url_to_safe_local_dirname(registry_url))
} }
pub fn resolve_package_folder_id_from_specifier( pub fn resolve_package_folder_id_from_specifier(
@ -252,7 +254,7 @@ impl ReadonlyNpmCache {
.root_dir_url .root_dir_url
.join(&format!( .join(&format!(
"{}/", "{}/",
fs_util::root_url_to_safe_local_dirname(registry_url) root_url_to_safe_local_dirname(registry_url)
.to_string_lossy() .to_string_lossy()
.replace('\\', "/") .replace('\\', "/")
)) ))
@ -457,12 +459,7 @@ impl NpmCache {
with_folder_sync_lock( with_folder_sync_lock(
(id.name.as_str(), &id.version), (id.name.as_str(), &id.version),
&package_folder, &package_folder,
|| { || hard_link_dir_recursive(&original_package_folder, &package_folder),
fs_util::hard_link_dir_recursive(
&original_package_folder,
&package_folder,
)
},
)?; )?;
Ok(()) Ok(())
} }

View file

@ -21,11 +21,11 @@ use deno_core::url::Url;
use deno_runtime::colors; use deno_runtime::colors;
use serde::Serialize; use serde::Serialize;
use crate::file_fetcher::CacheSetting; use crate::args::CacheSetting;
use crate::fs_util; use crate::cache::CACHE_PERM;
use crate::http_cache::CACHE_PERM;
use crate::http_util::HttpClient; use crate::http_util::HttpClient;
use crate::progress_bar::ProgressBar; use crate::util::fs::atomic_write_file;
use crate::util::progress_bar::ProgressBar;
use super::cache::NpmCache; use super::cache::NpmCache;
use super::resolution::NpmVersionMatcher; use super::resolution::NpmVersionMatcher;
@ -405,7 +405,7 @@ impl RealNpmRegistryApiInner {
let file_cache_path = self.get_package_file_cache_path(name); let file_cache_path = self.get_package_file_cache_path(name);
let file_text = serde_json::to_string(&package_info)?; let file_text = serde_json::to_string(&package_info)?;
std::fs::create_dir_all(file_cache_path.parent().unwrap())?; std::fs::create_dir_all(file_cache_path.parent().unwrap())?;
fs_util::atomic_write_file(&file_cache_path, file_text, CACHE_PERM)?; atomic_write_file(&file_cache_path, file_text, CACHE_PERM)?;
Ok(()) Ok(())
} }

View file

@ -16,7 +16,6 @@ use deno_runtime::deno_node::PackageJson;
use deno_runtime::deno_node::TYPES_CONDITIONS; use deno_runtime::deno_node::TYPES_CONDITIONS;
use crate::args::Lockfile; use crate::args::Lockfile;
use crate::fs_util;
use crate::npm::resolution::NpmResolution; use crate::npm::resolution::NpmResolution;
use crate::npm::resolution::NpmResolutionSnapshot; use crate::npm::resolution::NpmResolutionSnapshot;
use crate::npm::resolvers::common::cache_packages; use crate::npm::resolvers::common::cache_packages;
@ -125,7 +124,7 @@ impl InnerNpmPackageResolver for GlobalNpmPackageResolver {
fn package_size(&self, package_id: &NpmPackageId) -> Result<u64, AnyError> { fn package_size(&self, package_id: &NpmPackageId) -> Result<u64, AnyError> {
let package_folder = self.package_folder(package_id); let package_folder = self.package_folder(package_id);
Ok(fs_util::dir_size(&package_folder)?) Ok(crate::util::fs::dir_size(&package_folder)?)
} }
fn has_packages(&self) -> bool { fn has_packages(&self) -> bool {

View file

@ -10,6 +10,7 @@ use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use crate::util::fs::symlink_dir;
use deno_ast::ModuleSpecifier; use deno_ast::ModuleSpecifier;
use deno_core::anyhow::bail; use deno_core::anyhow::bail;
use deno_core::anyhow::Context; use deno_core::anyhow::Context;
@ -23,7 +24,6 @@ use deno_runtime::deno_node::TYPES_CONDITIONS;
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
use crate::args::Lockfile; use crate::args::Lockfile;
use crate::fs_util;
use crate::npm::cache::mixed_case_package_name_encode; use crate::npm::cache::mixed_case_package_name_encode;
use crate::npm::cache::should_sync_download; use crate::npm::cache::should_sync_download;
use crate::npm::cache::NpmPackageCacheFolderId; use crate::npm::cache::NpmPackageCacheFolderId;
@ -34,6 +34,8 @@ use crate::npm::NpmPackageId;
use crate::npm::NpmPackageReq; use crate::npm::NpmPackageReq;
use crate::npm::NpmResolutionPackage; use crate::npm::NpmResolutionPackage;
use crate::npm::RealNpmRegistryApi; use crate::npm::RealNpmRegistryApi;
use crate::util::fs::copy_dir_recursive;
use crate::util::fs::hard_link_dir_recursive;
use super::common::ensure_registry_read_permission; use super::common::ensure_registry_read_permission;
use super::common::types_package_name; use super::common::types_package_name;
@ -203,7 +205,7 @@ impl InnerNpmPackageResolver for LocalNpmPackageResolver {
fn package_size(&self, package_id: &NpmPackageId) -> Result<u64, AnyError> { fn package_size(&self, package_id: &NpmPackageId) -> Result<u64, AnyError> {
let package_folder_path = self.get_package_id_folder(package_id)?; let package_folder_path = self.get_package_id_folder(package_id)?;
Ok(fs_util::dir_size(&package_folder_path)?) Ok(crate::util::fs::dir_size(&package_folder_path)?)
} }
fn has_packages(&self) -> bool { fn has_packages(&self) -> bool {
@ -318,7 +320,7 @@ async fn sync_resolution_with_fs(
&registry_url, &registry_url,
); );
// for now copy, but in the future consider hard linking // for now copy, but in the future consider hard linking
fs_util::copy_dir_recursive(&cache_folder, &package_path)?; copy_dir_recursive(&cache_folder, &package_path)?;
// write out a file that indicates this folder has been initialized // write out a file that indicates this folder has been initialized
fs::write(initialized_file, "")?; fs::write(initialized_file, "")?;
Ok(()) Ok(())
@ -356,7 +358,7 @@ async fn sync_resolution_with_fs(
.join("node_modules"), .join("node_modules"),
&package.id.name, &package.id.name,
); );
fs_util::hard_link_dir_recursive(&source_path, &package_path)?; hard_link_dir_recursive(&source_path, &package_path)?;
// write out a file that indicates this folder has been initialized // write out a file that indicates this folder has been initialized
fs::write(initialized_file, "")?; fs::write(initialized_file, "")?;
} }
@ -467,7 +469,7 @@ fn symlink_package_dir(
#[cfg(windows)] #[cfg(windows)]
return junction_or_symlink_dir(old_path, new_path); return junction_or_symlink_dir(old_path, new_path);
#[cfg(not(windows))] #[cfg(not(windows))]
fs_util::symlink_dir(old_path, new_path) symlink_dir(old_path, new_path)
} }
#[cfg(windows)] #[cfg(windows)]
@ -477,6 +479,7 @@ fn junction_or_symlink_dir(
) -> Result<(), AnyError> { ) -> Result<(), AnyError> {
// Use junctions because they're supported on ntfs file systems without // Use junctions because they're supported on ntfs file systems without
// needing to elevate privileges on Windows // needing to elevate privileges on Windows
match junction::create(old_path, new_path) { match junction::create(old_path, new_path) {
Ok(()) => Ok(()), Ok(()) => Ok(()),
Err(junction_err) => { Err(junction_err) => {
@ -486,7 +489,7 @@ fn junction_or_symlink_dir(
log::warn!("Error creating junction. {:#}", junction_err); log::warn!("Error creating junction. {:#}", junction_err);
} }
match fs_util::symlink_dir(old_path, new_path) { match symlink_dir(old_path, new_path) {
Ok(()) => Ok(()), Ok(()) => Ok(()),
Err(symlink_err) => bail!( Err(symlink_err) => bail!(
concat!( concat!(

View file

@ -23,7 +23,7 @@ use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use crate::args::Lockfile; use crate::args::Lockfile;
use crate::fs_util; use crate::util::fs::canonicalize_path_maybe_not_exists;
use self::common::InnerNpmPackageResolver; use self::common::InnerNpmPackageResolver;
use self::local::LocalNpmPackageResolver; use self::local::LocalNpmPackageResolver;
@ -187,7 +187,7 @@ impl NpmPackageResolver {
let path = self let path = self
.inner .inner
.resolve_package_folder_from_deno_module(pkg_req)?; .resolve_package_folder_from_deno_module(pkg_req)?;
let path = fs_util::canonicalize_path_maybe_not_exists(&path)?; let path = canonicalize_path_maybe_not_exists(&path)?;
log::debug!("Resolved {} to {}", pkg_req, path.display()); log::debug!("Resolved {} to {}", pkg_req, path.display());
Ok(path) Ok(path)
} }

View file

@ -11,6 +11,7 @@ use crate::cache;
use crate::cache::DenoDir; use crate::cache::DenoDir;
use crate::cache::EmitCache; use crate::cache::EmitCache;
use crate::cache::FastInsecureHasher; use crate::cache::FastInsecureHasher;
use crate::cache::HttpCache;
use crate::cache::NodeAnalysisCache; use crate::cache::NodeAnalysisCache;
use crate::cache::ParsedSourceCache; use crate::cache::ParsedSourceCache;
use crate::cache::TypeCheckCache; use crate::cache::TypeCheckCache;
@ -19,7 +20,6 @@ use crate::file_fetcher::FileFetcher;
use crate::graph_util::graph_lock_or_exit; use crate::graph_util::graph_lock_or_exit;
use crate::graph_util::GraphData; use crate::graph_util::GraphData;
use crate::graph_util::ModuleEntry; use crate::graph_util::ModuleEntry;
use crate::http_cache;
use crate::http_util::HttpClient; use crate::http_util::HttpClient;
use crate::node; use crate::node;
use crate::node::NodeResolution; use crate::node::NodeResolution;
@ -28,9 +28,9 @@ use crate::npm::NpmCache;
use crate::npm::NpmPackageReference; use crate::npm::NpmPackageReference;
use crate::npm::NpmPackageResolver; use crate::npm::NpmPackageResolver;
use crate::npm::RealNpmRegistryApi; use crate::npm::RealNpmRegistryApi;
use crate::progress_bar::ProgressBar;
use crate::resolver::CliResolver; use crate::resolver::CliResolver;
use crate::tools::check; use crate::tools::check;
use crate::util::progress_bar::ProgressBar;
use deno_ast::MediaType; use deno_ast::MediaType;
use deno_core::anyhow::anyhow; use deno_core::anyhow::anyhow;
@ -153,7 +153,7 @@ impl ProcState {
let compiled_wasm_module_store = CompiledWasmModuleStore::default(); let compiled_wasm_module_store = CompiledWasmModuleStore::default();
let dir = cli_options.resolve_deno_dir()?; let dir = cli_options.resolve_deno_dir()?;
let deps_cache_location = dir.deps_folder_path(); let deps_cache_location = dir.deps_folder_path();
let http_cache = http_cache::HttpCache::new(&deps_cache_location); let http_cache = HttpCache::new(&deps_cache_location);
let root_cert_store = cli_options.resolve_root_cert_store()?; let root_cert_store = cli_options.resolve_root_cert_store()?;
let cache_usage = cli_options.cache_setting(); let cache_usage = cli_options.cache_setting();
let progress_bar = ProgressBar::default(); let progress_bar = ProgressBar::default();

View file

@ -4,16 +4,16 @@ use crate::args::BenchFlags;
use crate::args::Flags; use crate::args::Flags;
use crate::args::TypeCheckMode; use crate::args::TypeCheckMode;
use crate::colors; use crate::colors;
use crate::file_watcher;
use crate::file_watcher::ResolutionResult;
use crate::fs_util::collect_specifiers;
use crate::fs_util::is_supported_bench_path;
use crate::graph_util::contains_specifier; use crate::graph_util::contains_specifier;
use crate::graph_util::graph_valid; use crate::graph_util::graph_valid;
use crate::ops; use crate::ops;
use crate::proc_state::ProcState; use crate::proc_state::ProcState;
use crate::tools::test::format_test_error; use crate::tools::test::format_test_error;
use crate::tools::test::TestFilter; use crate::tools::test::TestFilter;
use crate::util::file_watcher;
use crate::util::file_watcher::ResolutionResult;
use crate::util::fs::collect_specifiers;
use crate::util::path::is_supported_ext;
use crate::worker::create_main_worker_for_test_or_bench; use crate::worker::create_main_worker_for_test_or_bench;
use deno_core::error::generic_error; use deno_core::error::generic_error;
@ -32,6 +32,7 @@ use log::Level;
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
use std::collections::HashSet; use std::collections::HashSet;
use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use tokio::sync::mpsc::unbounded_channel; use tokio::sync::mpsc::unbounded_channel;
use tokio::sync::mpsc::UnboundedSender; use tokio::sync::mpsc::UnboundedSender;
@ -469,6 +470,19 @@ async fn bench_specifiers(
Ok(()) Ok(())
} }
/// Checks if the path has a basename and extension Deno supports for benches.
fn is_supported_bench_path(path: &Path) -> bool {
if let Some(name) = path.file_stem() {
let basename = name.to_string_lossy();
(basename.ends_with("_bench")
|| basename.ends_with(".bench")
|| basename == "bench")
&& is_supported_ext(path)
} else {
false
}
}
pub async fn run_benchmarks( pub async fn run_benchmarks(
flags: Flags, flags: Flags,
bench_flags: BenchFlags, bench_flags: BenchFlags,

View file

@ -3,10 +3,10 @@
use crate::args::CoverageFlags; use crate::args::CoverageFlags;
use crate::args::Flags; use crate::args::Flags;
use crate::colors; use crate::colors;
use crate::fs_util::collect_files;
use crate::proc_state::ProcState; use crate::proc_state::ProcState;
use crate::text_encoding::source_map_from_code;
use crate::tools::fmt::format_json; use crate::tools::fmt::format_json;
use crate::util::fs::collect_files;
use crate::util::text_encoding::source_map_from_code;
use deno_ast::MediaType; use deno_ast::MediaType;
use deno_ast::ModuleSpecifier; use deno_ast::ModuleSpecifier;

View file

@ -12,13 +12,13 @@ use crate::args::FmtFlags;
use crate::args::FmtOptionsConfig; use crate::args::FmtOptionsConfig;
use crate::args::ProseWrap; use crate::args::ProseWrap;
use crate::colors; use crate::colors;
use crate::diff::diff; use crate::util::diff::diff;
use crate::file_watcher; use crate::util::file_watcher;
use crate::file_watcher::ResolutionResult; use crate::util::file_watcher::ResolutionResult;
use crate::fs_util::collect_files; use crate::util::fs::collect_files;
use crate::fs_util::get_extension; use crate::util::path::get_extension;
use crate::fs_util::specifier_to_file_path; use crate::util::path::specifier_to_file_path;
use crate::text_encoding; use crate::util::text_encoding;
use deno_ast::ParsedSource; use deno_ast::ParsedSource;
use deno_core::anyhow::bail; use deno_core::anyhow::bail;
use deno_core::anyhow::Context; use deno_core::anyhow::Context;

View file

@ -20,7 +20,6 @@ use deno_runtime::colors;
use crate::args::Flags; use crate::args::Flags;
use crate::args::InfoFlags; use crate::args::InfoFlags;
use crate::checksum;
use crate::display; use crate::display;
use crate::npm::NpmPackageId; use crate::npm::NpmPackageId;
use crate::npm::NpmPackageReference; use crate::npm::NpmPackageReference;
@ -29,6 +28,7 @@ use crate::npm::NpmPackageResolver;
use crate::npm::NpmResolutionPackage; use crate::npm::NpmResolutionPackage;
use crate::npm::NpmResolutionSnapshot; use crate::npm::NpmResolutionSnapshot;
use crate::proc_state::ProcState; use crate::proc_state::ProcState;
use crate::util::checksum;
pub async fn info(flags: Flags, info_flags: InfoFlags) -> Result<(), AnyError> { pub async fn info(flags: Flags, info_flags: InfoFlags) -> Result<(), AnyError> {
let ps = ProcState::build(flags).await?; let ps = ProcState::build(flags).await?;

View file

@ -4,8 +4,8 @@ use crate::args::ConfigFlag;
use crate::args::Flags; use crate::args::Flags;
use crate::args::InstallFlags; use crate::args::InstallFlags;
use crate::args::TypeCheckMode; use crate::args::TypeCheckMode;
use crate::fs_util;
use crate::npm::NpmPackageReference; use crate::npm::NpmPackageReference;
use crate::util::fs::canonicalize_path_maybe_not_exists;
use deno_core::anyhow::Context; use deno_core::anyhow::Context;
use deno_core::error::generic_error; use deno_core::error::generic_error;
use deno_core::error::AnyError; use deno_core::error::AnyError;
@ -107,9 +107,7 @@ exec deno {} "$@"
fn get_installer_root() -> Result<PathBuf, io::Error> { fn get_installer_root() -> Result<PathBuf, io::Error> {
if let Ok(env_dir) = env::var("DENO_INSTALL_ROOT") { if let Ok(env_dir) = env::var("DENO_INSTALL_ROOT") {
if !env_dir.is_empty() { if !env_dir.is_empty() {
return fs_util::canonicalize_path_maybe_not_exists(&PathBuf::from( return canonicalize_path_maybe_not_exists(&PathBuf::from(env_dir));
env_dir,
));
} }
} }
// Note: on Windows, the $HOME environment variable may be set by users or by // Note: on Windows, the $HOME environment variable may be set by users or by
@ -167,7 +165,7 @@ pub fn infer_name_from_url(url: &Url) -> Option<String> {
pub fn uninstall(name: String, root: Option<PathBuf>) -> Result<(), AnyError> { pub fn uninstall(name: String, root: Option<PathBuf>) -> Result<(), AnyError> {
let root = if let Some(root) = root { let root = if let Some(root) = root {
fs_util::canonicalize_path_maybe_not_exists(&root)? canonicalize_path_maybe_not_exists(&root)?
} else { } else {
get_installer_root()? get_installer_root()?
}; };
@ -275,7 +273,7 @@ fn resolve_shim_data(
install_flags: &InstallFlags, install_flags: &InstallFlags,
) -> Result<ShimData, AnyError> { ) -> Result<ShimData, AnyError> {
let root = if let Some(root) = &install_flags.root { let root = if let Some(root) = &install_flags.root {
fs_util::canonicalize_path_maybe_not_exists(root)? canonicalize_path_maybe_not_exists(root)?
} else { } else {
get_installer_root()? get_installer_root()?
}; };
@ -450,6 +448,7 @@ mod tests {
use super::*; use super::*;
use crate::args::ConfigFlag; use crate::args::ConfigFlag;
use crate::util::fs::canonicalize_path;
use std::process::Command; use std::process::Command;
use test_util::testdata_path; use test_util::testdata_path;
use test_util::TempDir; use test_util::TempDir;
@ -746,7 +745,7 @@ mod tests {
#[test] #[test]
fn install_npm_lockfile_default() { fn install_npm_lockfile_default() {
let temp_dir = fs_util::canonicalize_path(&env::temp_dir()).unwrap(); let temp_dir = canonicalize_path(&env::temp_dir()).unwrap();
let shim_data = resolve_shim_data( let shim_data = resolve_shim_data(
&Flags { &Flags {
allow_all: true, allow_all: true,

View file

@ -10,13 +10,13 @@ use crate::args::Flags;
use crate::args::LintConfig; use crate::args::LintConfig;
use crate::args::LintFlags; use crate::args::LintFlags;
use crate::colors; use crate::colors;
use crate::file_watcher;
use crate::file_watcher::ResolutionResult;
use crate::fs_util::collect_files;
use crate::fs_util::is_supported_ext;
use crate::fs_util::specifier_to_file_path;
use crate::proc_state::ProcState; use crate::proc_state::ProcState;
use crate::tools::fmt::run_parallelized; use crate::tools::fmt::run_parallelized;
use crate::util::file_watcher;
use crate::util::file_watcher::ResolutionResult;
use crate::util::fs::collect_files;
use crate::util::path::is_supported_ext;
use crate::util::path::specifier_to_file_path;
use deno_ast::MediaType; use deno_ast::MediaType;
use deno_core::anyhow::anyhow; use deno_core::anyhow::anyhow;
use deno_core::error::generic_error; use deno_core::error::generic_error;

View file

@ -6,9 +6,9 @@ use crate::args::Flags;
use crate::args::RunFlags; use crate::args::RunFlags;
use crate::args::TypeCheckMode; use crate::args::TypeCheckMode;
use crate::cache::DenoDir; use crate::cache::DenoDir;
use crate::fs_util;
use crate::standalone::Metadata; use crate::standalone::Metadata;
use crate::standalone::MAGIC_TRAILER; use crate::standalone::MAGIC_TRAILER;
use crate::util::path::path_has_trailing_slash;
use crate::ProcState; use crate::ProcState;
use deno_core::anyhow::bail; use deno_core::anyhow::bail;
use deno_core::anyhow::Context; use deno_core::anyhow::Context;
@ -299,7 +299,7 @@ pub fn resolve_compile_executable_output_path(
) -> Result<PathBuf, AnyError> { ) -> Result<PathBuf, AnyError> {
let module_specifier = resolve_url_or_path(&compile_flags.source_file)?; let module_specifier = resolve_url_or_path(&compile_flags.source_file)?;
compile_flags.output.as_ref().and_then(|output| { compile_flags.output.as_ref().and_then(|output| {
if fs_util::path_has_trailing_slash(output) { if path_has_trailing_slash(output) {
let infer_file_name = infer_name_from_url(&module_specifier).map(PathBuf::from)?; let infer_file_name = infer_name_from_url(&module_specifier).map(PathBuf::from)?;
Some(output.join(infer_file_name)) Some(output.join(infer_file_name))
} else { } else {

View file

@ -3,8 +3,8 @@
use crate::args::Flags; use crate::args::Flags;
use crate::args::TaskFlags; use crate::args::TaskFlags;
use crate::colors; use crate::colors;
use crate::fs_util;
use crate::proc_state::ProcState; use crate::proc_state::ProcState;
use crate::util::fs::canonicalize_path;
use deno_core::anyhow::bail; use deno_core::anyhow::bail;
use deno_core::anyhow::Context; use deno_core::anyhow::Context;
use deno_core::error::AnyError; use deno_core::error::AnyError;
@ -40,7 +40,7 @@ pub async fn execute_script(
} }
let cwd = match task_flags.cwd { let cwd = match task_flags.cwd {
Some(path) => fs_util::canonicalize_path(&PathBuf::from(path))?, Some(path) => canonicalize_path(&PathBuf::from(path))?,
None => config_file_path.parent().unwrap().to_owned(), None => config_file_path.parent().unwrap().to_owned(),
}; };
let task_name = task_flags.task; let task_name = task_flags.task;

View file

@ -3,20 +3,20 @@
use crate::args::Flags; use crate::args::Flags;
use crate::args::TestFlags; use crate::args::TestFlags;
use crate::args::TypeCheckMode; use crate::args::TypeCheckMode;
use crate::checksum;
use crate::colors; use crate::colors;
use crate::display; use crate::display;
use crate::file_fetcher::File; use crate::file_fetcher::File;
use crate::file_watcher;
use crate::file_watcher::ResolutionResult;
use crate::fs_util::collect_specifiers;
use crate::fs_util::is_supported_test_ext;
use crate::fs_util::is_supported_test_path;
use crate::fs_util::specifier_to_file_path;
use crate::graph_util::contains_specifier; use crate::graph_util::contains_specifier;
use crate::graph_util::graph_valid; use crate::graph_util::graph_valid;
use crate::ops; use crate::ops;
use crate::proc_state::ProcState; use crate::proc_state::ProcState;
use crate::util::checksum;
use crate::util::file_watcher;
use crate::util::file_watcher::ResolutionResult;
use crate::util::fs::collect_specifiers;
use crate::util::path::get_extension;
use crate::util::path::is_supported_ext;
use crate::util::path::specifier_to_file_path;
use crate::worker::create_main_worker_for_test_or_bench; use crate::worker::create_main_worker_for_test_or_bench;
use deno_ast::swc::common::comments::CommentKind; use deno_ast::swc::common::comments::CommentKind;
@ -51,6 +51,7 @@ use std::fmt::Write as _;
use std::io::Read; use std::io::Read;
use std::io::Write; use std::io::Write;
use std::num::NonZeroUsize; use std::num::NonZeroUsize;
use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
@ -1184,6 +1185,44 @@ async fn test_specifiers(
Ok(()) Ok(())
} }
/// Checks if the path has a basename and extension Deno supports for tests.
fn is_supported_test_path(path: &Path) -> bool {
if let Some(name) = path.file_stem() {
let basename = name.to_string_lossy();
(basename.ends_with("_test")
|| basename.ends_with(".test")
|| basename == "test")
&& is_supported_ext(path)
} else {
false
}
}
/// Checks if the path has an extension Deno supports for tests.
fn is_supported_test_ext(path: &Path) -> bool {
if let Some(ext) = get_extension(path) {
matches!(
ext.as_str(),
"ts"
| "tsx"
| "js"
| "jsx"
| "mjs"
| "mts"
| "cjs"
| "cts"
| "md"
| "mkd"
| "mkdn"
| "mdwn"
| "mdown"
| "markdown"
)
} else {
false
}
}
/// Collects specifiers marking them with the appropriate test mode while maintaining the natural /// Collects specifiers marking them with the appropriate test mode while maintaining the natural
/// input order. /// input order.
/// ///
@ -1667,3 +1706,67 @@ fn start_output_redirect_thread(
} }
}); });
} }
#[cfg(test)]
mod inner_test {
use std::path::Path;
use super::*;
#[test]
fn test_is_supported_test_ext() {
assert!(!is_supported_test_ext(Path::new("tests/subdir/redirects")));
assert!(is_supported_test_ext(Path::new("README.md")));
assert!(is_supported_test_ext(Path::new("readme.MD")));
assert!(is_supported_test_ext(Path::new("lib/typescript.d.ts")));
assert!(is_supported_test_ext(Path::new(
"testdata/run/001_hello.js"
)));
assert!(is_supported_test_ext(Path::new(
"testdata/run/002_hello.ts"
)));
assert!(is_supported_test_ext(Path::new("foo.jsx")));
assert!(is_supported_test_ext(Path::new("foo.tsx")));
assert!(is_supported_test_ext(Path::new("foo.TS")));
assert!(is_supported_test_ext(Path::new("foo.TSX")));
assert!(is_supported_test_ext(Path::new("foo.JS")));
assert!(is_supported_test_ext(Path::new("foo.JSX")));
assert!(is_supported_test_ext(Path::new("foo.mjs")));
assert!(is_supported_test_ext(Path::new("foo.mts")));
assert!(is_supported_test_ext(Path::new("foo.cjs")));
assert!(is_supported_test_ext(Path::new("foo.cts")));
assert!(!is_supported_test_ext(Path::new("foo.mjsx")));
assert!(!is_supported_test_ext(Path::new("foo.jsonc")));
assert!(!is_supported_test_ext(Path::new("foo.JSONC")));
assert!(!is_supported_test_ext(Path::new("foo.json")));
assert!(!is_supported_test_ext(Path::new("foo.JsON")));
}
#[test]
fn test_is_supported_test_path() {
assert!(is_supported_test_path(Path::new(
"tests/subdir/foo_test.ts"
)));
assert!(is_supported_test_path(Path::new(
"tests/subdir/foo_test.tsx"
)));
assert!(is_supported_test_path(Path::new(
"tests/subdir/foo_test.js"
)));
assert!(is_supported_test_path(Path::new(
"tests/subdir/foo_test.jsx"
)));
assert!(is_supported_test_path(Path::new("bar/foo.test.ts")));
assert!(is_supported_test_path(Path::new("bar/foo.test.tsx")));
assert!(is_supported_test_path(Path::new("bar/foo.test.js")));
assert!(is_supported_test_path(Path::new("bar/foo.test.jsx")));
assert!(is_supported_test_path(Path::new("foo/bar/test.js")));
assert!(is_supported_test_path(Path::new("foo/bar/test.jsx")));
assert!(is_supported_test_path(Path::new("foo/bar/test.ts")));
assert!(is_supported_test_path(Path::new("foo/bar/test.tsx")));
assert!(!is_supported_test_path(Path::new("README.md")));
assert!(!is_supported_test_path(Path::new("lib/typescript.d.ts")));
assert!(!is_supported_test_path(Path::new("notatest.js")));
assert!(!is_supported_test_path(Path::new("NotAtest.ts")));
}
}

View file

@ -13,8 +13,8 @@ use deno_graph::ModuleGraph;
use deno_graph::Position; use deno_graph::Position;
use deno_graph::Resolved; use deno_graph::Resolved;
use crate::fs_util::path_with_stem_suffix; use crate::util::path::path_with_stem_suffix;
use crate::fs_util::relative_specifier; use crate::util::path::relative_specifier;
use super::specifiers::dir_name_for_root; use super::specifiers::dir_name_for_root;
use super::specifiers::get_unique_path; use super::specifiers::get_unique_path;

View file

@ -15,11 +15,12 @@ use crate::args::CliOptions;
use crate::args::Flags; use crate::args::Flags;
use crate::args::FmtOptionsConfig; use crate::args::FmtOptionsConfig;
use crate::args::VendorFlags; use crate::args::VendorFlags;
use crate::fs_util;
use crate::fs_util::relative_specifier;
use crate::fs_util::specifier_to_file_path;
use crate::proc_state::ProcState; use crate::proc_state::ProcState;
use crate::tools::fmt::format_json; use crate::tools::fmt::format_json;
use crate::util::fs::canonicalize_path;
use crate::util::fs::resolve_from_cwd;
use crate::util::path::relative_specifier;
use crate::util::path::specifier_to_file_path;
mod analyze; mod analyze;
mod build; mod build;
@ -38,7 +39,7 @@ pub async fn vendor(
Some(output_path) => output_path.to_owned(), Some(output_path) => output_path.to_owned(),
None => PathBuf::from("vendor/"), None => PathBuf::from("vendor/"),
}; };
let output_dir = fs_util::resolve_from_cwd(&raw_output_dir)?; let output_dir = resolve_from_cwd(&raw_output_dir)?;
validate_output_dir(&output_dir, &vendor_flags)?; validate_output_dir(&output_dir, &vendor_flags)?;
validate_options(&mut cli_options, &output_dir)?; validate_options(&mut cli_options, &output_dir)?;
let ps = ProcState::from_options(Arc::new(cli_options)).await?; let ps = ProcState::from_options(Arc::new(cli_options)).await?;
@ -110,18 +111,17 @@ fn validate_options(
if let Some(import_map_path) = options if let Some(import_map_path) = options
.resolve_import_map_specifier()? .resolve_import_map_specifier()?
.and_then(|p| specifier_to_file_path(&p).ok()) .and_then(|p| specifier_to_file_path(&p).ok())
.and_then(|p| fs_util::canonicalize_path(&p).ok()) .and_then(|p| canonicalize_path(&p).ok())
{ {
// make the output directory in order to canonicalize it for the check below // make the output directory in order to canonicalize it for the check below
std::fs::create_dir_all(output_dir)?; std::fs::create_dir_all(output_dir)?;
let output_dir = let output_dir = canonicalize_path(output_dir).with_context(|| {
fs_util::canonicalize_path(output_dir).with_context(|| { format!("Failed to canonicalize: {}", output_dir.display())
format!("Failed to canonicalize: {}", output_dir.display()) })?;
})?;
if import_map_path.starts_with(&output_dir) { if import_map_path.starts_with(&output_dir) {
// canonicalize to make the test for this pass on the CI // canonicalize to make the test for this pass on the CI
let cwd = fs_util::canonicalize_path(&std::env::current_dir()?)?; let cwd = canonicalize_path(&std::env::current_dir()?)?;
// We don't allow using the output directory to help generate the // We don't allow using the output directory to help generate the
// new state because this may lead to cryptic error messages. // new state because this may lead to cryptic error messages.
log::warn!( log::warn!(

View file

@ -8,8 +8,9 @@ use deno_ast::ModuleSpecifier;
use deno_core::anyhow::anyhow; use deno_core::anyhow::anyhow;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use crate::fs_util; use crate::util::path::is_banned_path_char;
use crate::fs_util::path_with_stem_suffix; use crate::util::path::path_with_stem_suffix;
use crate::util::path::root_url_to_safe_local_dirname;
/// Partitions the provided specifiers by the non-path and non-query parts of a specifier. /// Partitions the provided specifiers by the non-path and non-query parts of a specifier.
pub fn partition_by_root_specifiers<'a>( pub fn partition_by_root_specifiers<'a>(
@ -30,7 +31,7 @@ pub fn partition_by_root_specifiers<'a>(
/// Gets the directory name to use for the provided root. /// Gets the directory name to use for the provided root.
pub fn dir_name_for_root(root: &ModuleSpecifier) -> PathBuf { pub fn dir_name_for_root(root: &ModuleSpecifier) -> PathBuf {
fs_util::root_url_to_safe_local_dirname(root) root_url_to_safe_local_dirname(root)
} }
/// Gets a unique file path given the provided file path /// Gets a unique file path given the provided file path
@ -74,13 +75,7 @@ pub fn is_remote_specifier_text(text: &str) -> bool {
pub fn sanitize_filepath(text: &str) -> String { pub fn sanitize_filepath(text: &str) -> String {
text text
.chars() .chars()
.map(|c| { .map(|c| if is_banned_path_char(c) { '_' } else { c })
if fs_util::is_banned_path_char(c) {
'_'
} else {
c
}
})
.collect() .collect()
} }

View file

@ -9,6 +9,7 @@ use crate::node::NodeResolution;
use crate::node::NodeResolutionMode; use crate::node::NodeResolutionMode;
use crate::npm::NpmPackageReference; use crate::npm::NpmPackageReference;
use crate::npm::NpmPackageResolver; use crate::npm::NpmPackageResolver;
use crate::util::checksum;
use deno_ast::MediaType; use deno_ast::MediaType;
use deno_core::anyhow::anyhow; use deno_core::anyhow::anyhow;
@ -178,7 +179,7 @@ fn get_maybe_hash(
if let Some(source) = maybe_source { if let Some(source) = maybe_source {
let mut data = vec![source.as_bytes().to_owned()]; let mut data = vec![source.as_bytes().to_owned()];
data.extend_from_slice(hash_data); data.extend_from_slice(hash_data);
Some(crate::checksum::gen(&data)) Some(checksum::gen(&data))
} else { } else {
None None
} }
@ -186,7 +187,7 @@ fn get_maybe_hash(
/// Hash the URL so it can be sent to `tsc` in a supportable way /// Hash the URL so it can be sent to `tsc` in a supportable way
fn hash_url(specifier: &ModuleSpecifier, media_type: MediaType) -> String { fn hash_url(specifier: &ModuleSpecifier, media_type: MediaType) -> String {
let hash = crate::checksum::gen(&[specifier.path().as_bytes()]); let hash = checksum::gen(&[specifier.path().as_bytes()]);
format!( format!(
"{}:///{}{}", "{}:///{}{}",
specifier.scheme(), specifier.scheme(),
@ -365,7 +366,7 @@ fn op_create_hash(s: &mut OpState, args: Value) -> Result<Value, AnyError> {
.context("Invalid request from JavaScript for \"op_create_hash\".")?; .context("Invalid request from JavaScript for \"op_create_hash\".")?;
let mut data = vec![v.data.as_bytes().to_owned()]; let mut data = vec![v.data.as_bytes().to_owned()];
data.extend_from_slice(&state.hash_data); data.extend_from_slice(&state.hash_data);
let hash = crate::checksum::gen(&data); let hash = checksum::gen(&data);
Ok(json!({ "hash": hash })) Ok(json!({ "hash": hash }))
} }

View file

@ -1,7 +1,7 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use crate::colors; use crate::colors;
use crate::fs_util::canonicalize_path; use crate::util::fs::canonicalize_path;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::error::JsError; use deno_core::error::JsError;

View file

@ -1,13 +1,11 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use deno_core::anyhow::Context; use deno_core::anyhow::Context;
use deno_core::error::uri_error;
use deno_core::error::AnyError; use deno_core::error::AnyError;
pub use deno_core::normalize_path; pub use deno_core::normalize_path;
use deno_core::ModuleSpecifier; use deno_core::ModuleSpecifier;
use deno_runtime::deno_crypto::rand; use deno_runtime::deno_crypto::rand;
use deno_runtime::deno_node::PathClean; use deno_runtime::deno_node::PathClean;
use std::borrow::Cow;
use std::env::current_dir; use std::env::current_dir;
use std::fs::OpenOptions; use std::fs::OpenOptions;
use std::io::Error; use std::io::Error;
@ -18,6 +16,8 @@ use std::path::PathBuf;
use std::time::Duration; use std::time::Duration;
use walkdir::WalkDir; use walkdir::WalkDir;
use super::path::specifier_to_file_path;
pub fn atomic_write_file<T: AsRef<[u8]>>( pub fn atomic_write_file<T: AsRef<[u8]>>(
filename: &Path, filename: &Path,
data: T, data: T,
@ -163,77 +163,6 @@ pub fn resolve_from_cwd(path: &Path) -> Result<PathBuf, AnyError> {
Ok(normalize_path(&resolved_path)) Ok(normalize_path(&resolved_path))
} }
/// Checks if the path has extension Deno supports.
pub fn is_supported_ext(path: &Path) -> bool {
if let Some(ext) = get_extension(path) {
matches!(
ext.as_str(),
"ts" | "tsx" | "js" | "jsx" | "mjs" | "mts" | "cjs" | "cts"
)
} else {
false
}
}
/// Checks if the path has a basename and extension Deno supports for tests.
pub fn is_supported_test_path(path: &Path) -> bool {
if let Some(name) = path.file_stem() {
let basename = name.to_string_lossy();
(basename.ends_with("_test")
|| basename.ends_with(".test")
|| basename == "test")
&& is_supported_ext(path)
} else {
false
}
}
/// Checks if the path has a basename and extension Deno supports for benches.
pub fn is_supported_bench_path(path: &Path) -> bool {
if let Some(name) = path.file_stem() {
let basename = name.to_string_lossy();
(basename.ends_with("_bench")
|| basename.ends_with(".bench")
|| basename == "bench")
&& is_supported_ext(path)
} else {
false
}
}
/// Checks if the path has an extension Deno supports for tests.
pub fn is_supported_test_ext(path: &Path) -> bool {
if let Some(ext) = get_extension(path) {
matches!(
ext.as_str(),
"ts"
| "tsx"
| "js"
| "jsx"
| "mjs"
| "mts"
| "cjs"
| "cts"
| "md"
| "mkd"
| "mkdn"
| "mdwn"
| "mdown"
| "markdown"
)
} else {
false
}
}
/// Get the extension of a file in lowercase.
pub fn get_extension(file_path: &Path) -> Option<String> {
return file_path
.extension()
.and_then(|e| e.to_str())
.map(|e| e.to_lowercase());
}
/// Collects file paths that satisfy the given predicate, by recursively walking `files`. /// Collects file paths that satisfy the given predicate, by recursively walking `files`.
/// If the walker visits a path that is listed in `ignore`, it skips descending into the directory. /// If the walker visits a path that is listed in `ignore`, it skips descending into the directory.
pub fn collect_files<P>( pub fn collect_files<P>(
@ -461,201 +390,6 @@ pub fn symlink_dir(oldpath: &Path, newpath: &Path) -> Result<(), AnyError> {
Ok(()) Ok(())
} }
/// Attempts to convert a specifier to a file path. By default, uses the Url
/// crate's `to_file_path()` method, but falls back to try and resolve unix-style
/// paths on Windows.
pub fn specifier_to_file_path(
specifier: &ModuleSpecifier,
) -> Result<PathBuf, AnyError> {
let result = if cfg!(windows) {
match specifier.to_file_path() {
Ok(path) => Ok(path),
Err(()) => {
// This might be a unix-style path which is used in the tests even on Windows.
// Attempt to see if we can convert it to a `PathBuf`. This code should be removed
// once/if https://github.com/servo/rust-url/issues/730 is implemented.
if specifier.scheme() == "file"
&& specifier.host().is_none()
&& specifier.port().is_none()
&& specifier.path_segments().is_some()
{
let path_str = specifier.path();
match String::from_utf8(
percent_encoding::percent_decode(path_str.as_bytes()).collect(),
) {
Ok(path_str) => Ok(PathBuf::from(path_str)),
Err(_) => Err(()),
}
} else {
Err(())
}
}
}
} else {
specifier.to_file_path()
};
match result {
Ok(path) => Ok(path),
Err(()) => Err(uri_error(format!(
"Invalid file path.\n Specifier: {}",
specifier
))),
}
}
/// Ensures a specifier that will definitely be a directory has a trailing slash.
pub fn ensure_directory_specifier(
mut specifier: ModuleSpecifier,
) -> ModuleSpecifier {
let path = specifier.path();
if !path.ends_with('/') {
let new_path = format!("{}/", path);
specifier.set_path(&new_path);
}
specifier
}
/// Gets the parent of this module specifier.
pub fn specifier_parent(specifier: &ModuleSpecifier) -> ModuleSpecifier {
let mut specifier = specifier.clone();
// don't use specifier.segments() because it will strip the leading slash
let mut segments = specifier.path().split('/').collect::<Vec<_>>();
if segments.iter().all(|s| s.is_empty()) {
return specifier;
}
if let Some(last) = segments.last() {
if last.is_empty() {
segments.pop();
}
segments.pop();
let new_path = format!("{}/", segments.join("/"));
specifier.set_path(&new_path);
}
specifier
}
/// `from.make_relative(to)` but with fixes.
pub fn relative_specifier(
from: &ModuleSpecifier,
to: &ModuleSpecifier,
) -> Option<String> {
let is_dir = to.path().ends_with('/');
if is_dir && from == to {
return Some("./".to_string());
}
// workaround using parent directory until https://github.com/servo/rust-url/pull/754 is merged
let from = if !from.path().ends_with('/') {
if let Some(end_slash) = from.path().rfind('/') {
let mut new_from = from.clone();
new_from.set_path(&from.path()[..end_slash + 1]);
Cow::Owned(new_from)
} else {
Cow::Borrowed(from)
}
} else {
Cow::Borrowed(from)
};
// workaround for url crate not adding a trailing slash for a directory
// it seems to be fixed once a version greater than 2.2.2 is released
let mut text = from.make_relative(to)?;
if is_dir && !text.ends_with('/') && to.query().is_none() {
text.push('/');
}
Some(if text.starts_with("../") || text.starts_with("./") {
text
} else {
format!("./{}", text)
})
}
/// This function checks if input path has trailing slash or not. If input path
/// has trailing slash it will return true else it will return false.
pub fn path_has_trailing_slash(path: &Path) -> bool {
if let Some(path_str) = path.to_str() {
if cfg!(windows) {
path_str.ends_with('\\')
} else {
path_str.ends_with('/')
}
} else {
false
}
}
/// Gets a path with the specified file stem suffix.
///
/// Ex. `file.ts` with suffix `_2` returns `file_2.ts`
pub fn path_with_stem_suffix(path: &Path, suffix: &str) -> PathBuf {
if let Some(file_name) = path.file_name().map(|f| f.to_string_lossy()) {
if let Some(file_stem) = path.file_stem().map(|f| f.to_string_lossy()) {
if let Some(ext) = path.extension().map(|f| f.to_string_lossy()) {
return if file_stem.to_lowercase().ends_with(".d") {
path.with_file_name(format!(
"{}{}.{}.{}",
&file_stem[..file_stem.len() - ".d".len()],
suffix,
// maintain casing
&file_stem[file_stem.len() - "d".len()..],
ext
))
} else {
path.with_file_name(format!("{}{}.{}", file_stem, suffix, ext))
};
}
}
path.with_file_name(format!("{}{}", file_name, suffix))
} else {
path.with_file_name(suffix)
}
}
/// Gets if the provided character is not supported on all
/// kinds of file systems.
pub fn is_banned_path_char(c: char) -> bool {
matches!(c, '<' | '>' | ':' | '"' | '|' | '?' | '*')
}
/// Gets a safe local directory name for the provided url.
///
/// For example:
/// https://deno.land:8080/path -> deno.land_8080/path
pub fn root_url_to_safe_local_dirname(root: &ModuleSpecifier) -> PathBuf {
fn sanitize_segment(text: &str) -> String {
text
.chars()
.map(|c| if is_banned_segment_char(c) { '_' } else { c })
.collect()
}
fn is_banned_segment_char(c: char) -> bool {
matches!(c, '/' | '\\') || is_banned_path_char(c)
}
let mut result = String::new();
if let Some(domain) = root.domain() {
result.push_str(&sanitize_segment(domain));
}
if let Some(port) = root.port() {
if !result.is_empty() {
result.push('_');
}
result.push_str(&port.to_string());
}
let mut result = PathBuf::from(result);
if let Some(segments) = root.path_segments() {
for segment in segments.filter(|s| !s.is_empty()) {
result = result.join(sanitize_segment(segment));
}
}
result
}
/// Gets the total size (in bytes) of a directory. /// Gets the total size (in bytes) of a directory.
pub fn dir_size(path: &Path) -> std::io::Result<u64> { pub fn dir_size(path: &Path) -> std::io::Result<u64> {
let entries = std::fs::read_dir(path)?; let entries = std::fs::read_dir(path)?;
@ -718,83 +452,6 @@ mod tests {
assert_eq!(resolve_from_cwd(expected).unwrap(), expected); assert_eq!(resolve_from_cwd(expected).unwrap(), expected);
} }
#[test]
fn test_is_supported_ext() {
assert!(!is_supported_ext(Path::new("tests/subdir/redirects")));
assert!(!is_supported_ext(Path::new("README.md")));
assert!(is_supported_ext(Path::new("lib/typescript.d.ts")));
assert!(is_supported_ext(Path::new("testdata/run/001_hello.js")));
assert!(is_supported_ext(Path::new("testdata/run/002_hello.ts")));
assert!(is_supported_ext(Path::new("foo.jsx")));
assert!(is_supported_ext(Path::new("foo.tsx")));
assert!(is_supported_ext(Path::new("foo.TS")));
assert!(is_supported_ext(Path::new("foo.TSX")));
assert!(is_supported_ext(Path::new("foo.JS")));
assert!(is_supported_ext(Path::new("foo.JSX")));
assert!(is_supported_ext(Path::new("foo.mjs")));
assert!(is_supported_ext(Path::new("foo.mts")));
assert!(is_supported_ext(Path::new("foo.cjs")));
assert!(is_supported_ext(Path::new("foo.cts")));
assert!(!is_supported_ext(Path::new("foo.mjsx")));
}
#[test]
fn test_is_supported_test_ext() {
assert!(!is_supported_test_ext(Path::new("tests/subdir/redirects")));
assert!(is_supported_test_ext(Path::new("README.md")));
assert!(is_supported_test_ext(Path::new("readme.MD")));
assert!(is_supported_test_ext(Path::new("lib/typescript.d.ts")));
assert!(is_supported_test_ext(Path::new(
"testdata/run/001_hello.js"
)));
assert!(is_supported_test_ext(Path::new(
"testdata/run/002_hello.ts"
)));
assert!(is_supported_test_ext(Path::new("foo.jsx")));
assert!(is_supported_test_ext(Path::new("foo.tsx")));
assert!(is_supported_test_ext(Path::new("foo.TS")));
assert!(is_supported_test_ext(Path::new("foo.TSX")));
assert!(is_supported_test_ext(Path::new("foo.JS")));
assert!(is_supported_test_ext(Path::new("foo.JSX")));
assert!(is_supported_test_ext(Path::new("foo.mjs")));
assert!(is_supported_test_ext(Path::new("foo.mts")));
assert!(is_supported_test_ext(Path::new("foo.cjs")));
assert!(is_supported_test_ext(Path::new("foo.cts")));
assert!(!is_supported_test_ext(Path::new("foo.mjsx")));
assert!(!is_supported_test_ext(Path::new("foo.jsonc")));
assert!(!is_supported_test_ext(Path::new("foo.JSONC")));
assert!(!is_supported_test_ext(Path::new("foo.json")));
assert!(!is_supported_test_ext(Path::new("foo.JsON")));
}
#[test]
fn test_is_supported_test_path() {
assert!(is_supported_test_path(Path::new(
"tests/subdir/foo_test.ts"
)));
assert!(is_supported_test_path(Path::new(
"tests/subdir/foo_test.tsx"
)));
assert!(is_supported_test_path(Path::new(
"tests/subdir/foo_test.js"
)));
assert!(is_supported_test_path(Path::new(
"tests/subdir/foo_test.jsx"
)));
assert!(is_supported_test_path(Path::new("bar/foo.test.ts")));
assert!(is_supported_test_path(Path::new("bar/foo.test.tsx")));
assert!(is_supported_test_path(Path::new("bar/foo.test.js")));
assert!(is_supported_test_path(Path::new("bar/foo.test.jsx")));
assert!(is_supported_test_path(Path::new("foo/bar/test.js")));
assert!(is_supported_test_path(Path::new("foo/bar/test.jsx")));
assert!(is_supported_test_path(Path::new("foo/bar/test.ts")));
assert!(is_supported_test_path(Path::new("foo/bar/test.tsx")));
assert!(!is_supported_test_path(Path::new("README.md")));
assert!(!is_supported_test_path(Path::new("lib/typescript.d.ts")));
assert!(!is_supported_test_path(Path::new("notatest.js")));
assert!(!is_supported_test_path(Path::new("NotAtest.ts")));
}
#[test] #[test]
fn test_collect_files() { fn test_collect_files() {
fn create_files(dir_path: &Path, files: &[&str]) { fn create_files(dir_path: &Path, files: &[&str]) {
@ -1001,209 +658,4 @@ mod tests {
); );
} }
} }
#[test]
fn test_specifier_to_file_path() {
run_success_test("file:///", "/");
run_success_test("file:///test", "/test");
run_success_test("file:///dir/test/test.txt", "/dir/test/test.txt");
run_success_test(
"file:///dir/test%20test/test.txt",
"/dir/test test/test.txt",
);
fn run_success_test(specifier: &str, expected_path: &str) {
let result =
specifier_to_file_path(&ModuleSpecifier::parse(specifier).unwrap())
.unwrap();
assert_eq!(result, PathBuf::from(expected_path));
}
}
#[test]
fn test_ensure_directory_specifier() {
run_test("file:///", "file:///");
run_test("file:///test", "file:///test/");
run_test("file:///test/", "file:///test/");
run_test("file:///test/other", "file:///test/other/");
run_test("file:///test/other/", "file:///test/other/");
fn run_test(specifier: &str, expected: &str) {
let result =
ensure_directory_specifier(ModuleSpecifier::parse(specifier).unwrap());
assert_eq!(result.to_string(), expected);
}
}
#[test]
fn test_specifier_parent() {
run_test("file:///", "file:///");
run_test("file:///test", "file:///");
run_test("file:///test/", "file:///");
run_test("file:///test/other", "file:///test/");
run_test("file:///test/other.txt", "file:///test/");
run_test("file:///test/other/", "file:///test/");
fn run_test(specifier: &str, expected: &str) {
let result =
specifier_parent(&ModuleSpecifier::parse(specifier).unwrap());
assert_eq!(result.to_string(), expected);
}
}
#[test]
fn test_relative_specifier() {
let fixtures: Vec<(&str, &str, Option<&str>)> = vec![
("file:///from", "file:///to", Some("./to")),
("file:///from", "file:///from/other", Some("./from/other")),
("file:///from", "file:///from/other/", Some("./from/other/")),
("file:///from", "file:///other/from", Some("./other/from")),
("file:///from/", "file:///other/from", Some("../other/from")),
("file:///from", "file:///other/from/", Some("./other/from/")),
(
"file:///from",
"file:///to/other.txt",
Some("./to/other.txt"),
),
(
"file:///from/test",
"file:///to/other.txt",
Some("../to/other.txt"),
),
(
"file:///from/other.txt",
"file:///to/other.txt",
Some("../to/other.txt"),
),
(
"https://deno.land/x/a/b/d.ts",
"https://deno.land/x/a/b/c.ts",
Some("./c.ts"),
),
(
"https://deno.land/x/a/b/d.ts",
"https://deno.land/x/a/c.ts",
Some("../c.ts"),
),
(
"https://deno.land/x/a/b/d.ts",
"https://deno.land/x/a/b/c/d.ts",
Some("./c/d.ts"),
),
(
"https://deno.land/x/a/b/c/",
"https://deno.land/x/a/b/c/d.ts",
Some("./d.ts"),
),
(
"https://deno.land/x/a/b/c/",
"https://deno.land/x/a/b/c/d/e.ts",
Some("./d/e.ts"),
),
(
"https://deno.land/x/a/b/c/f.ts",
"https://deno.land/x/a/b/c/d/e.ts",
Some("./d/e.ts"),
),
(
"https://deno.land/x/a/b/d.ts",
"https://deno.land/x/a/c.ts?foo=bar",
Some("../c.ts?foo=bar"),
),
(
"https://deno.land/x/a/b/d.ts?foo=bar",
"https://deno.land/x/a/b/c.ts",
Some("./c.ts"),
),
("file:///a/b/d.ts", "file:///a/b/c.ts", Some("./c.ts")),
("https://deno.land/x/a/b/c.ts", "file:///a/b/c.ts", None),
(
"https://deno.land/",
"https://deno.land/x/a/b/c.ts",
Some("./x/a/b/c.ts"),
),
(
"https://deno.land/x/d/e/f.ts",
"https://deno.land/x/a/b/c.ts",
Some("../../a/b/c.ts"),
),
];
for (from_str, to_str, expected) in fixtures {
let from = ModuleSpecifier::parse(from_str).unwrap();
let to = ModuleSpecifier::parse(to_str).unwrap();
let actual = relative_specifier(&from, &to);
assert_eq!(
actual.as_deref(),
expected,
"from: \"{}\" to: \"{}\"",
from_str,
to_str
);
}
}
#[test]
fn test_path_has_trailing_slash() {
#[cfg(not(windows))]
{
run_test("/Users/johndoe/Desktop/deno-project/target/", true);
run_test(r"/Users/johndoe/deno-project/target//", true);
run_test("/Users/johndoe/Desktop/deno-project", false);
run_test(r"/Users/johndoe/deno-project\", false);
}
#[cfg(windows)]
{
run_test(r"C:\test\deno-project\", true);
run_test(r"C:\test\deno-project\\", true);
run_test(r"C:\test\file.txt", false);
run_test(r"C:\test\file.txt/", false);
}
fn run_test(path_str: &str, expected: bool) {
let path = Path::new(path_str);
let result = path_has_trailing_slash(path);
assert_eq!(result, expected);
}
}
#[test]
fn test_path_with_stem_suffix() {
assert_eq!(
path_with_stem_suffix(&PathBuf::from("/"), "_2"),
PathBuf::from("/_2")
);
assert_eq!(
path_with_stem_suffix(&PathBuf::from("/test"), "_2"),
PathBuf::from("/test_2")
);
assert_eq!(
path_with_stem_suffix(&PathBuf::from("/test.txt"), "_2"),
PathBuf::from("/test_2.txt")
);
assert_eq!(
path_with_stem_suffix(&PathBuf::from("/test/subdir"), "_2"),
PathBuf::from("/test/subdir_2")
);
assert_eq!(
path_with_stem_suffix(&PathBuf::from("/test/subdir.other.txt"), "_2"),
PathBuf::from("/test/subdir.other_2.txt")
);
assert_eq!(
path_with_stem_suffix(&PathBuf::from("/test.d.ts"), "_2"),
PathBuf::from("/test_2.d.ts")
);
assert_eq!(
path_with_stem_suffix(&PathBuf::from("/test.D.TS"), "_2"),
PathBuf::from("/test_2.D.TS")
);
assert_eq!(
path_with_stem_suffix(&PathBuf::from("/test.d.mts"), "_2"),
PathBuf::from("/test_2.d.mts")
);
assert_eq!(
path_with_stem_suffix(&PathBuf::from("/test.d.cts"), "_2"),
PathBuf::from("/test_2.d.cts")
);
}
} }

14
cli/util/mod.rs Normal file
View file

@ -0,0 +1,14 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// Note: Only add code in this folder that has no application specific logic
pub mod checksum;
pub mod diff;
pub mod display;
pub mod file_watcher;
pub mod fs;
pub mod logger;
pub mod path;
pub mod progress_bar;
pub mod text_encoding;
pub mod unix;
pub mod windows;

452
cli/util/path.rs Normal file
View file

@ -0,0 +1,452 @@
use std::borrow::Cow;
use std::path::Path;
use std::path::PathBuf;
use deno_ast::ModuleSpecifier;
use deno_core::error::uri_error;
use deno_core::error::AnyError;
/// Checks if the path has extension Deno supports.
pub fn is_supported_ext(path: &Path) -> bool {
if let Some(ext) = get_extension(path) {
matches!(
ext.as_str(),
"ts" | "tsx" | "js" | "jsx" | "mjs" | "mts" | "cjs" | "cts"
)
} else {
false
}
}
/// Get the extension of a file in lowercase.
pub fn get_extension(file_path: &Path) -> Option<String> {
return file_path
.extension()
.and_then(|e| e.to_str())
.map(|e| e.to_lowercase());
}
/// Attempts to convert a specifier to a file path. By default, uses the Url
/// crate's `to_file_path()` method, but falls back to try and resolve unix-style
/// paths on Windows.
pub fn specifier_to_file_path(
specifier: &ModuleSpecifier,
) -> Result<PathBuf, AnyError> {
let result = if cfg!(windows) {
match specifier.to_file_path() {
Ok(path) => Ok(path),
Err(()) => {
// This might be a unix-style path which is used in the tests even on Windows.
// Attempt to see if we can convert it to a `PathBuf`. This code should be removed
// once/if https://github.com/servo/rust-url/issues/730 is implemented.
if specifier.scheme() == "file"
&& specifier.host().is_none()
&& specifier.port().is_none()
&& specifier.path_segments().is_some()
{
let path_str = specifier.path();
match String::from_utf8(
percent_encoding::percent_decode(path_str.as_bytes()).collect(),
) {
Ok(path_str) => Ok(PathBuf::from(path_str)),
Err(_) => Err(()),
}
} else {
Err(())
}
}
}
} else {
specifier.to_file_path()
};
match result {
Ok(path) => Ok(path),
Err(()) => Err(uri_error(format!(
"Invalid file path.\n Specifier: {}",
specifier
))),
}
}
/// Ensures a specifier that will definitely be a directory has a trailing slash.
pub fn ensure_directory_specifier(
mut specifier: ModuleSpecifier,
) -> ModuleSpecifier {
let path = specifier.path();
if !path.ends_with('/') {
let new_path = format!("{}/", path);
specifier.set_path(&new_path);
}
specifier
}
/// Gets the parent of this module specifier.
pub fn specifier_parent(specifier: &ModuleSpecifier) -> ModuleSpecifier {
let mut specifier = specifier.clone();
// don't use specifier.segments() because it will strip the leading slash
let mut segments = specifier.path().split('/').collect::<Vec<_>>();
if segments.iter().all(|s| s.is_empty()) {
return specifier;
}
if let Some(last) = segments.last() {
if last.is_empty() {
segments.pop();
}
segments.pop();
let new_path = format!("{}/", segments.join("/"));
specifier.set_path(&new_path);
}
specifier
}
/// `from.make_relative(to)` but with fixes.
pub fn relative_specifier(
from: &ModuleSpecifier,
to: &ModuleSpecifier,
) -> Option<String> {
let is_dir = to.path().ends_with('/');
if is_dir && from == to {
return Some("./".to_string());
}
// workaround using parent directory until https://github.com/servo/rust-url/pull/754 is merged
let from = if !from.path().ends_with('/') {
if let Some(end_slash) = from.path().rfind('/') {
let mut new_from = from.clone();
new_from.set_path(&from.path()[..end_slash + 1]);
Cow::Owned(new_from)
} else {
Cow::Borrowed(from)
}
} else {
Cow::Borrowed(from)
};
// workaround for url crate not adding a trailing slash for a directory
// it seems to be fixed once a version greater than 2.2.2 is released
let mut text = from.make_relative(to)?;
if is_dir && !text.ends_with('/') && to.query().is_none() {
text.push('/');
}
Some(if text.starts_with("../") || text.starts_with("./") {
text
} else {
format!("./{}", text)
})
}
/// This function checks if input path has trailing slash or not. If input path
/// has trailing slash it will return true else it will return false.
pub fn path_has_trailing_slash(path: &Path) -> bool {
if let Some(path_str) = path.to_str() {
if cfg!(windows) {
path_str.ends_with('\\')
} else {
path_str.ends_with('/')
}
} else {
false
}
}
/// Gets a path with the specified file stem suffix.
///
/// Ex. `file.ts` with suffix `_2` returns `file_2.ts`
pub fn path_with_stem_suffix(path: &Path, suffix: &str) -> PathBuf {
if let Some(file_name) = path.file_name().map(|f| f.to_string_lossy()) {
if let Some(file_stem) = path.file_stem().map(|f| f.to_string_lossy()) {
if let Some(ext) = path.extension().map(|f| f.to_string_lossy()) {
return if file_stem.to_lowercase().ends_with(".d") {
path.with_file_name(format!(
"{}{}.{}.{}",
&file_stem[..file_stem.len() - ".d".len()],
suffix,
// maintain casing
&file_stem[file_stem.len() - "d".len()..],
ext
))
} else {
path.with_file_name(format!("{}{}.{}", file_stem, suffix, ext))
};
}
}
path.with_file_name(format!("{}{}", file_name, suffix))
} else {
path.with_file_name(suffix)
}
}
/// Gets if the provided character is not supported on all
/// kinds of file systems.
pub fn is_banned_path_char(c: char) -> bool {
matches!(c, '<' | '>' | ':' | '"' | '|' | '?' | '*')
}
/// Gets a safe local directory name for the provided url.
///
/// For example:
/// https://deno.land:8080/path -> deno.land_8080/path
pub fn root_url_to_safe_local_dirname(root: &ModuleSpecifier) -> PathBuf {
fn sanitize_segment(text: &str) -> String {
text
.chars()
.map(|c| if is_banned_segment_char(c) { '_' } else { c })
.collect()
}
fn is_banned_segment_char(c: char) -> bool {
matches!(c, '/' | '\\') || is_banned_path_char(c)
}
let mut result = String::new();
if let Some(domain) = root.domain() {
result.push_str(&sanitize_segment(domain));
}
if let Some(port) = root.port() {
if !result.is_empty() {
result.push('_');
}
result.push_str(&port.to_string());
}
let mut result = PathBuf::from(result);
if let Some(segments) = root.path_segments() {
for segment in segments.filter(|s| !s.is_empty()) {
result = result.join(sanitize_segment(segment));
}
}
result
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_is_supported_ext() {
assert!(!is_supported_ext(Path::new("tests/subdir/redirects")));
assert!(!is_supported_ext(Path::new("README.md")));
assert!(is_supported_ext(Path::new("lib/typescript.d.ts")));
assert!(is_supported_ext(Path::new("testdata/run/001_hello.js")));
assert!(is_supported_ext(Path::new("testdata/run/002_hello.ts")));
assert!(is_supported_ext(Path::new("foo.jsx")));
assert!(is_supported_ext(Path::new("foo.tsx")));
assert!(is_supported_ext(Path::new("foo.TS")));
assert!(is_supported_ext(Path::new("foo.TSX")));
assert!(is_supported_ext(Path::new("foo.JS")));
assert!(is_supported_ext(Path::new("foo.JSX")));
assert!(is_supported_ext(Path::new("foo.mjs")));
assert!(is_supported_ext(Path::new("foo.mts")));
assert!(is_supported_ext(Path::new("foo.cjs")));
assert!(is_supported_ext(Path::new("foo.cts")));
assert!(!is_supported_ext(Path::new("foo.mjsx")));
}
#[test]
fn test_specifier_to_file_path() {
run_success_test("file:///", "/");
run_success_test("file:///test", "/test");
run_success_test("file:///dir/test/test.txt", "/dir/test/test.txt");
run_success_test(
"file:///dir/test%20test/test.txt",
"/dir/test test/test.txt",
);
fn run_success_test(specifier: &str, expected_path: &str) {
let result =
specifier_to_file_path(&ModuleSpecifier::parse(specifier).unwrap())
.unwrap();
assert_eq!(result, PathBuf::from(expected_path));
}
}
#[test]
fn test_ensure_directory_specifier() {
run_test("file:///", "file:///");
run_test("file:///test", "file:///test/");
run_test("file:///test/", "file:///test/");
run_test("file:///test/other", "file:///test/other/");
run_test("file:///test/other/", "file:///test/other/");
fn run_test(specifier: &str, expected: &str) {
let result =
ensure_directory_specifier(ModuleSpecifier::parse(specifier).unwrap());
assert_eq!(result.to_string(), expected);
}
}
#[test]
fn test_specifier_parent() {
run_test("file:///", "file:///");
run_test("file:///test", "file:///");
run_test("file:///test/", "file:///");
run_test("file:///test/other", "file:///test/");
run_test("file:///test/other.txt", "file:///test/");
run_test("file:///test/other/", "file:///test/");
fn run_test(specifier: &str, expected: &str) {
let result =
specifier_parent(&ModuleSpecifier::parse(specifier).unwrap());
assert_eq!(result.to_string(), expected);
}
}
#[test]
fn test_relative_specifier() {
let fixtures: Vec<(&str, &str, Option<&str>)> = vec![
("file:///from", "file:///to", Some("./to")),
("file:///from", "file:///from/other", Some("./from/other")),
("file:///from", "file:///from/other/", Some("./from/other/")),
("file:///from", "file:///other/from", Some("./other/from")),
("file:///from/", "file:///other/from", Some("../other/from")),
("file:///from", "file:///other/from/", Some("./other/from/")),
(
"file:///from",
"file:///to/other.txt",
Some("./to/other.txt"),
),
(
"file:///from/test",
"file:///to/other.txt",
Some("../to/other.txt"),
),
(
"file:///from/other.txt",
"file:///to/other.txt",
Some("../to/other.txt"),
),
(
"https://deno.land/x/a/b/d.ts",
"https://deno.land/x/a/b/c.ts",
Some("./c.ts"),
),
(
"https://deno.land/x/a/b/d.ts",
"https://deno.land/x/a/c.ts",
Some("../c.ts"),
),
(
"https://deno.land/x/a/b/d.ts",
"https://deno.land/x/a/b/c/d.ts",
Some("./c/d.ts"),
),
(
"https://deno.land/x/a/b/c/",
"https://deno.land/x/a/b/c/d.ts",
Some("./d.ts"),
),
(
"https://deno.land/x/a/b/c/",
"https://deno.land/x/a/b/c/d/e.ts",
Some("./d/e.ts"),
),
(
"https://deno.land/x/a/b/c/f.ts",
"https://deno.land/x/a/b/c/d/e.ts",
Some("./d/e.ts"),
),
(
"https://deno.land/x/a/b/d.ts",
"https://deno.land/x/a/c.ts?foo=bar",
Some("../c.ts?foo=bar"),
),
(
"https://deno.land/x/a/b/d.ts?foo=bar",
"https://deno.land/x/a/b/c.ts",
Some("./c.ts"),
),
("file:///a/b/d.ts", "file:///a/b/c.ts", Some("./c.ts")),
("https://deno.land/x/a/b/c.ts", "file:///a/b/c.ts", None),
(
"https://deno.land/",
"https://deno.land/x/a/b/c.ts",
Some("./x/a/b/c.ts"),
),
(
"https://deno.land/x/d/e/f.ts",
"https://deno.land/x/a/b/c.ts",
Some("../../a/b/c.ts"),
),
];
for (from_str, to_str, expected) in fixtures {
let from = ModuleSpecifier::parse(from_str).unwrap();
let to = ModuleSpecifier::parse(to_str).unwrap();
let actual = relative_specifier(&from, &to);
assert_eq!(
actual.as_deref(),
expected,
"from: \"{}\" to: \"{}\"",
from_str,
to_str
);
}
}
#[test]
fn test_path_has_trailing_slash() {
#[cfg(not(windows))]
{
run_test("/Users/johndoe/Desktop/deno-project/target/", true);
run_test(r"/Users/johndoe/deno-project/target//", true);
run_test("/Users/johndoe/Desktop/deno-project", false);
run_test(r"/Users/johndoe/deno-project\", false);
}
#[cfg(windows)]
{
run_test(r"C:\test\deno-project\", true);
run_test(r"C:\test\deno-project\\", true);
run_test(r"C:\test\file.txt", false);
run_test(r"C:\test\file.txt/", false);
}
fn run_test(path_str: &str, expected: bool) {
let path = Path::new(path_str);
let result = path_has_trailing_slash(path);
assert_eq!(result, expected);
}
}
#[test]
fn test_path_with_stem_suffix() {
assert_eq!(
path_with_stem_suffix(&PathBuf::from("/"), "_2"),
PathBuf::from("/_2")
);
assert_eq!(
path_with_stem_suffix(&PathBuf::from("/test"), "_2"),
PathBuf::from("/test_2")
);
assert_eq!(
path_with_stem_suffix(&PathBuf::from("/test.txt"), "_2"),
PathBuf::from("/test_2.txt")
);
assert_eq!(
path_with_stem_suffix(&PathBuf::from("/test/subdir"), "_2"),
PathBuf::from("/test/subdir_2")
);
assert_eq!(
path_with_stem_suffix(&PathBuf::from("/test/subdir.other.txt"), "_2"),
PathBuf::from("/test/subdir.other_2.txt")
);
assert_eq!(
path_with_stem_suffix(&PathBuf::from("/test.d.ts"), "_2"),
PathBuf::from("/test_2.d.ts")
);
assert_eq!(
path_with_stem_suffix(&PathBuf::from("/test.D.TS"), "_2"),
PathBuf::from("/test_2.D.TS")
);
assert_eq!(
path_with_stem_suffix(&PathBuf::from("/test.d.mts"), "_2"),
PathBuf::from("/test_2.d.mts")
);
assert_eq!(
path_with_stem_suffix(&PathBuf::from("/test.d.cts"), "_2"),
PathBuf::from("/test_2.d.cts")
);
}
}

View file

@ -24,7 +24,6 @@ use deno_runtime::worker::WorkerOptions;
use deno_runtime::BootstrapOptions; use deno_runtime::BootstrapOptions;
use crate::args::DenoSubcommand; use crate::args::DenoSubcommand;
use crate::checksum;
use crate::errors; use crate::errors;
use crate::module_loader::CliModuleLoader; use crate::module_loader::CliModuleLoader;
use crate::node; use crate::node;
@ -34,6 +33,7 @@ use crate::proc_state::ProcState;
use crate::tools; use crate::tools;
use crate::tools::coverage::CoverageCollector; use crate::tools::coverage::CoverageCollector;
use crate::tools::test::TestMode; use crate::tools::test::TestMode;
use crate::util::checksum;
use crate::version; use crate::version;
pub struct CliMainWorker { pub struct CliMainWorker {

View file

@ -1,7 +1,7 @@
#!/usr/bin/env -S deno run --unstable --allow-read --allow-write #!/usr/bin/env -S deno run --unstable --allow-read --allow-write
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
import exports from "../../cli/napi_sym/symbol_exports.json" assert { import exports from "../../cli/napi/sym/symbol_exports.json" assert {
type: "json", type: "json",
}; };