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 = [
"bench_util",
"cli",
"cli/napi_sym",
"cli/napi/sym",
"core",
"ops",
"runtime",
@ -47,7 +47,7 @@ deno_core = { version = "0.161.0", path = "./core" }
deno_ops = { version = "0.39.0", path = "./ops" }
serde_v8 = { version = "0.72.0", path = "./serde_v8" }
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" }
test_util = { path = "./test_util" }

View file

@ -3,10 +3,9 @@
use crate::args::ConfigFlag;
use crate::args::Flags;
use crate::args::TaskFlags;
use crate::fs_util;
use crate::fs_util::canonicalize_path;
use crate::fs_util::specifier_parent;
use crate::fs_util::specifier_to_file_path;
use crate::util::fs::canonicalize_path;
use crate::util::path::specifier_parent;
use crate::util::path::specifier_to_file_path;
use deno_core::anyhow::anyhow;
use deno_core::anyhow::bail;
@ -467,7 +466,7 @@ impl ConfigFile {
..
}) = &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)? {
return Ok(Some(path));
}

View file

@ -20,6 +20,7 @@ use crate::npm::NpmPackageId;
use crate::npm::NpmPackageReq;
use crate::npm::NpmResolutionPackage;
use crate::tools::fmt::format_json;
use crate::util;
use crate::Flags;
#[derive(Debug)]
@ -260,7 +261,7 @@ impl Lockfile {
/// is not included, insert it.
fn check_or_insert(&mut self, specifier: &str, code: &str) -> bool {
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
} else {
self.insert(specifier, code);
@ -269,7 +270,7 @@ impl Lockfile {
}
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.has_content_changed = true;
}
@ -359,7 +360,7 @@ impl deno_graph::source::Locker for Locker {
}
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> {

View file

@ -22,6 +22,10 @@ pub use config_file::TsConfig;
pub use config_file::TsConfigForEmit;
pub use config_file::TsConfigType;
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 lockfile::Lockfile;
pub use lockfile::LockfileError;
@ -40,16 +44,130 @@ use deno_runtime::inspector_server::InspectorServer;
use deno_runtime::permissions::PermissionsOptions;
use std::collections::BTreeMap;
use std::env;
use std::io::BufReader;
use std::net::SocketAddr;
use std::path::PathBuf;
use std::sync::Arc;
use crate::cache::DenoDir;
use crate::file_fetcher::get_root_cert_store;
use crate::file_fetcher::CacheSetting;
use crate::fs_util;
use crate::util::fs::canonicalize_path_maybe_not_exists;
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
/// use these values over the values derived from the
/// CLI flags or config file.
@ -176,7 +294,7 @@ impl CliOptions {
} else {
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> {

View file

@ -1,7 +1,8 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use crate::fs_util;
use crate::http_cache::url_to_filename;
use super::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::Url;
@ -144,7 +145,7 @@ impl DiskCache {
Some(parent) => self.ensure_dir_exists(parent),
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)))
}
}

View file

@ -3,8 +3,8 @@
//! as defined in RFC 7234 (<https://tools.ietf.org/html/rfc7234>).
//! Currently it's a very simplified version to fulfill Deno needs
//! at hand.
use crate::fs_util;
use crate::http_util::HeadersMap;
use crate::util;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::serde::Deserialize;
@ -19,7 +19,7 @@ use std::path::Path;
use std::path::PathBuf;
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.
/// 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
// account when caching - it denotes parts of webpage, which
// 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);
Some(cache_filename)
}
/// Cached metadata about a url.
#[derive(Serialize, Deserialize)]
pub struct Metadata {
pub struct CachedUrlMetadata {
pub headers: HeadersMap,
pub url: String,
#[serde(default = "SystemTime::now")]
pub now: SystemTime,
}
impl Metadata {
impl CachedUrlMetadata {
pub fn write(&self, cache_filename: &Path) -> Result<(), AnyError> {
let metadata_filename = Self::filename(cache_filename);
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(())
}
pub fn read(cache_filename: &Path) -> Result<Metadata, AnyError> {
let metadata_filename = Metadata::filename(cache_filename);
pub fn read(cache_filename: &Path) -> Result<Self, AnyError> {
let metadata_filename = Self::filename(cache_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)
}
@ -149,10 +150,10 @@ impl HttpCache {
url_to_filename(url)
.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 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))
}
@ -172,9 +173,9 @@ impl HttpCache {
.expect("Cache filename should have a parent dir");
self.ensure_dir_exists(parent_filename)?;
// 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(),
url: url.to_string(),
headers: headers_map,

6
cli/cache/mod.rs vendored
View file

@ -19,6 +19,7 @@ mod common;
mod deno_dir;
mod disk_cache;
mod emit;
mod http_cache;
mod incremental;
mod node;
mod parsed_source;
@ -28,10 +29,15 @@ pub use common::FastInsecureHasher;
pub use deno_dir::DenoDir;
pub use disk_cache::DiskCache;
pub use emit::EmitCache;
pub use http_cache::CachedUrlMetadata;
pub use http_cache::HttpCache;
pub use incremental::IncrementalCache;
pub use node::NodeAnalysisCache;
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 concise interface to the DENO_DIR when building module graphs.
pub struct FetchCacher {

View file

@ -1,18 +1,18 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use crate::args::CacheSetting;
use crate::auth_tokens::AuthTokens;
use crate::cache::HttpCache;
use crate::colors;
use crate::http_cache::HttpCache;
use crate::http_util::CacheSemantics;
use crate::http_util::FetchOnceArgs;
use crate::http_util::FetchOnceResult;
use crate::http_util::HttpClient;
use crate::progress_bar::ProgressBar;
use crate::text_encoding;
use crate::util::progress_bar::ProgressBar;
use crate::util::text_encoding;
use data_url::DataUrl;
use deno_ast::MediaType;
use deno_core::anyhow::anyhow;
use deno_core::error::custom_error;
use deno_core::error::generic_error;
use deno_core::error::uri_error;
@ -21,11 +21,6 @@ use deno_core::futures;
use deno_core::futures::future::FutureExt;
use deno_core::parking_lot::Mutex;
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::permissions::Permissions;
use log::debug;
@ -34,7 +29,6 @@ use std::collections::HashMap;
use std::env;
use std::fs;
use std::future::Future;
use std::io::BufReader;
use std::io::Read;
use std::path::PathBuf;
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.
fn fetch_local(specifier: &ModuleSpecifier) -> Result<File, AnyError> {
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
/// data URL.
pub fn get_source_from_data_url(
@ -571,7 +411,7 @@ impl FileFetcher {
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) {
Ok(Some(file)) => {
return futures::future::ok(file).boxed();
@ -654,6 +494,41 @@ impl FileFetcher {
.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.
pub async fn fetch(
&self,
@ -754,6 +629,7 @@ impl FileFetcher {
#[cfg(test)]
mod tests {
use crate::cache::CachedUrlMetadata;
use crate::http_util::HttpClient;
use super::*;
@ -1175,8 +1051,7 @@ mod tests {
.http_cache
.get_cache_filename(&specifier)
.unwrap();
let mut metadata =
crate::http_cache::Metadata::read(&cache_filename).unwrap();
let mut metadata = CachedUrlMetadata::read(&cache_filename).unwrap();
metadata.headers = HashMap::new();
metadata
.headers
@ -1265,8 +1140,7 @@ mod tests {
.await;
assert!(result.is_ok());
let metadata_filename =
crate::http_cache::Metadata::filename(&cache_filename);
let metadata_filename = CachedUrlMetadata::filename(&cache_filename);
let metadata_file = fs::File::open(metadata_filename).unwrap();
let metadata_file_metadata = metadata_file.metadata().unwrap();
let metadata_file_modified_01 = metadata_file_metadata.modified().unwrap();
@ -1285,8 +1159,7 @@ mod tests {
.await;
assert!(result.is_ok());
let metadata_filename =
crate::http_cache::Metadata::filename(&cache_filename);
let metadata_filename = CachedUrlMetadata::filename(&cache_filename);
let metadata_file = fs::File::open(metadata_filename).unwrap();
let metadata_file_metadata = metadata_file.metadata().unwrap();
let metadata_file_modified_02 = metadata_file_metadata.modified().unwrap();
@ -1438,7 +1311,7 @@ mod tests {
assert!(result.is_ok());
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_metadata = metadata_file.metadata().unwrap();
let metadata_file_modified_01 = metadata_file_metadata.modified().unwrap();
@ -1458,7 +1331,7 @@ mod tests {
assert!(result.is_ok());
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_metadata = metadata_file.metadata().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.
use crate::http_cache;
use crate::cache::CachedUrlMetadata;
use crate::cache::HttpCache;
use deno_core::parking_lot::Mutex;
use deno_core::ModuleSpecifier;
@ -49,14 +50,14 @@ struct Metadata {
#[derive(Debug, Default, Clone)]
pub struct CacheMetadata {
cache: http_cache::HttpCache,
cache: HttpCache,
metadata: Arc<Mutex<HashMap<ModuleSpecifier, Metadata>>>,
}
impl CacheMetadata {
pub fn new(location: &Path) -> Self {
Self {
cache: http_cache::HttpCache::new(location),
cache: HttpCache::new(location),
metadata: Default::default(),
}
}
@ -87,8 +88,7 @@ impl CacheMetadata {
return None;
}
let cache_filename = self.cache.get_cache_filename(specifier)?;
let specifier_metadata =
http_cache::Metadata::read(&cache_filename).ok()?;
let specifier_metadata = CachedUrlMetadata::read(&cache_filename).ok()?;
let values = Arc::new(parse_metadata(&specifier_metadata.headers));
let version = calculate_fs_version(&cache_filename);
let mut metadata_map = self.metadata.lock();
@ -98,7 +98,7 @@ impl CacheMetadata {
}
pub fn set_location(&mut self, location: &Path) {
self.cache = http_cache::HttpCache::new(location);
self.cache = HttpCache::new(location);
self.metadata.lock().clear();
}
}

View file

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

View file

@ -2,7 +2,8 @@
use super::client::Client;
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::serde::Deserialize;
use deno_core::serde::Serialize;
@ -549,11 +550,11 @@ impl Config {
workspace: &ModuleSpecifier,
enabled_paths: Vec<String>,
) -> bool {
let workspace = fs_util::ensure_directory_specifier(workspace.clone());
let workspace = ensure_directory_specifier(workspace.clone());
let key = workspace.to_string();
let mut touched = false;
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();
for path in &enabled_paths {
let fs_path = workspace_path.join(path);

View file

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

View file

@ -57,6 +57,8 @@ use super::tsc::Assets;
use super::tsc::AssetsSnapshot;
use super::tsc::TsServer;
use super::urls;
use crate::args::get_root_cert_store;
use crate::args::CacheSetting;
use crate::args::CliOptions;
use crate::args::ConfigFile;
use crate::args::Flags;
@ -64,10 +66,7 @@ use crate::args::FmtConfig;
use crate::args::LintConfig;
use crate::args::TsConfig;
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::CacheSetting;
use crate::fs_util;
use crate::graph_util::graph_valid;
use crate::http_util::HttpClient;
use crate::npm::NpmCache;
@ -75,9 +74,12 @@ use crate::npm::NpmPackageResolver;
use crate::npm::RealNpmRegistryApi;
use crate::proc_state::import_map_from_text;
use crate::proc_state::ProcState;
use crate::progress_bar::ProgressBar;
use crate::tools::fmt::format_file;
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)]
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
// automatically discover the configuration
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 maybe_config = ConfigFile::discover_from(&root_path, &mut checked)?;
Ok(maybe_config.map(|c| {
@ -481,7 +483,7 @@ impl Inner {
let cache_url = if let Ok(url) = Url::from_file_path(cache_str) {
Ok(url)
} 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);
Url::from_file_path(cache_path).map_err(|_| {
anyhow!("Bad file path for import path: {:?}", cache_str)
@ -492,7 +494,7 @@ impl Inner {
cache_str
))
}?;
let cache_path = fs_util::specifier_to_file_path(&cache_url)?;
let cache_path = specifier_to_file_path(&cache_url)?;
lsp_log!(
" Resolved cache path: \"{}\"",
cache_path.to_string_lossy()
@ -521,7 +523,7 @@ impl Inner {
.config
.root_uri
.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(
maybe_root_path,
workspace_settings.certificate_stores.clone(),
@ -569,7 +571,7 @@ impl Inner {
anyhow!("Bad data url for import map: {}", import_map_str)
})?)
} 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);
Some(Url::from_file_path(import_map_path).map_err(|_| {
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" {
get_source_from_data_url(&import_map_url)?.0
} 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!(
" Resolved import map: \"{}\"",
import_map_path.to_string_lossy()
@ -768,7 +770,7 @@ impl Inner {
self.config.root_uri = params
.root_uri
.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 {
self.config.set_workspace_settings(value).map_err(|err| {
@ -1137,11 +1139,10 @@ impl Inner {
_ => return Ok(None),
};
let mark = self.performance.mark("formatting", Some(&params));
let file_path =
fs_util::specifier_to_file_path(&specifier).map_err(|err| {
error!("{}", err);
LspError::invalid_request()
})?;
let file_path = specifier_to_file_path(&specifier).map_err(|err| {
error!("{}", err);
LspError::invalid_request()
})?;
let fmt_options = if let Some(fmt_config) = self.maybe_fmt_config.as_ref() {
// skip formatting any files ignored by the config file
@ -2063,7 +2064,7 @@ impl Inner {
.config
.root_uri
.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();
for item in incoming_calls.iter() {
if let Some(resolved) = item.try_resolve_call_hierarchy_incoming_call(
@ -2109,7 +2110,7 @@ impl Inner {
.config
.root_uri
.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();
for item in outgoing_calls.iter() {
if let Some(resolved) = item.try_resolve_call_hierarchy_outgoing_call(
@ -2162,7 +2163,7 @@ impl Inner {
.config
.root_uri
.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();
match one_or_many {
tsc::OneOrMany::One(item) => {
@ -3010,7 +3011,7 @@ impl Inner {
}
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
.map_err(|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::Token;
use crate::args::CacheSetting;
use crate::cache::DenoDir;
use crate::file_fetcher::CacheSetting;
use crate::cache::HttpCache;
use crate::file_fetcher::FileFetcher;
use crate::http_cache::HttpCache;
use crate::http_util::HttpClient;
use deno_core::anyhow::anyhow;

View file

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

View file

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

View file

@ -18,10 +18,10 @@ use super::urls::LspUrlMap;
use super::urls::INVALID_SPECIFIER;
use crate::args::TsConfig;
use crate::fs_util::relative_specifier;
use crate::fs_util::specifier_to_file_path;
use crate::tsc;
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::error::custom_error;
@ -3445,7 +3445,7 @@ pub fn request(
#[cfg(test)]
mod tests {
use super::*;
use crate::http_cache::HttpCache;
use crate::cache::HttpCache;
use crate::http_util::HeadersMap;
use crate::lsp::config::WorkspaceSettings;
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_str(query);
}
crate::checksum::gen(&[file_name_str.as_bytes()])
crate::util::checksum::gen(&[file_name_str.as_bytes()])
}
#[derive(Debug, Default)]

View file

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

View file

@ -5,8 +5,8 @@ use crate::emit::emit_parsed_source;
use crate::graph_util::ModuleEntry;
use crate::node;
use crate::proc_state::ProcState;
use crate::text_encoding::code_without_source_map;
use crate::text_encoding::source_map_from_code;
use crate::util::text_encoding::code_without_source_map;
use crate::util::text_encoding::source_map_from_code;
use deno_ast::MediaType;
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;
assert!(
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;

View file

@ -14,11 +14,13 @@ use deno_core::error::AnyError;
use deno_core::parking_lot::Mutex;
use deno_core::url::Url;
use crate::args::CacheSetting;
use crate::cache::DenoDir;
use crate::file_fetcher::CacheSetting;
use crate::fs_util;
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::semver::NpmVersion;
@ -162,7 +164,7 @@ impl ReadonlyNpmCache {
std::fs::create_dir_all(root_dir)
.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
@ -227,7 +229,7 @@ impl ReadonlyNpmCache {
pub fn registry_folder(&self, registry_url: &Url) -> PathBuf {
self
.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(
@ -252,7 +254,7 @@ impl ReadonlyNpmCache {
.root_dir_url
.join(&format!(
"{}/",
fs_util::root_url_to_safe_local_dirname(registry_url)
root_url_to_safe_local_dirname(registry_url)
.to_string_lossy()
.replace('\\', "/")
))
@ -457,12 +459,7 @@ impl NpmCache {
with_folder_sync_lock(
(id.name.as_str(), &id.version),
&package_folder,
|| {
fs_util::hard_link_dir_recursive(
&original_package_folder,
&package_folder,
)
},
|| hard_link_dir_recursive(&original_package_folder, &package_folder),
)?;
Ok(())
}

View file

@ -21,11 +21,11 @@ use deno_core::url::Url;
use deno_runtime::colors;
use serde::Serialize;
use crate::file_fetcher::CacheSetting;
use crate::fs_util;
use crate::http_cache::CACHE_PERM;
use crate::args::CacheSetting;
use crate::cache::CACHE_PERM;
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::resolution::NpmVersionMatcher;
@ -405,7 +405,7 @@ impl RealNpmRegistryApiInner {
let file_cache_path = self.get_package_file_cache_path(name);
let file_text = serde_json::to_string(&package_info)?;
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(())
}

View file

@ -16,7 +16,6 @@ use deno_runtime::deno_node::PackageJson;
use deno_runtime::deno_node::TYPES_CONDITIONS;
use crate::args::Lockfile;
use crate::fs_util;
use crate::npm::resolution::NpmResolution;
use crate::npm::resolution::NpmResolutionSnapshot;
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> {
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 {

View file

@ -10,6 +10,7 @@ use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
use crate::util::fs::symlink_dir;
use deno_ast::ModuleSpecifier;
use deno_core::anyhow::bail;
use deno_core::anyhow::Context;
@ -23,7 +24,6 @@ use deno_runtime::deno_node::TYPES_CONDITIONS;
use tokio::task::JoinHandle;
use crate::args::Lockfile;
use crate::fs_util;
use crate::npm::cache::mixed_case_package_name_encode;
use crate::npm::cache::should_sync_download;
use crate::npm::cache::NpmPackageCacheFolderId;
@ -34,6 +34,8 @@ use crate::npm::NpmPackageId;
use crate::npm::NpmPackageReq;
use crate::npm::NpmResolutionPackage;
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::types_package_name;
@ -203,7 +205,7 @@ impl InnerNpmPackageResolver for LocalNpmPackageResolver {
fn package_size(&self, package_id: &NpmPackageId) -> Result<u64, AnyError> {
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 {
@ -318,7 +320,7 @@ async fn sync_resolution_with_fs(
&registry_url,
);
// 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
fs::write(initialized_file, "")?;
Ok(())
@ -356,7 +358,7 @@ async fn sync_resolution_with_fs(
.join("node_modules"),
&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
fs::write(initialized_file, "")?;
}
@ -467,7 +469,7 @@ fn symlink_package_dir(
#[cfg(windows)]
return junction_or_symlink_dir(old_path, new_path);
#[cfg(not(windows))]
fs_util::symlink_dir(old_path, new_path)
symlink_dir(old_path, new_path)
}
#[cfg(windows)]
@ -477,6 +479,7 @@ fn junction_or_symlink_dir(
) -> Result<(), AnyError> {
// Use junctions because they're supported on ntfs file systems without
// needing to elevate privileges on Windows
match junction::create(old_path, new_path) {
Ok(()) => Ok(()),
Err(junction_err) => {
@ -486,7 +489,7 @@ fn junction_or_symlink_dir(
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(()),
Err(symlink_err) => bail!(
concat!(

View file

@ -23,7 +23,7 @@ use std::path::PathBuf;
use std::sync::Arc;
use crate::args::Lockfile;
use crate::fs_util;
use crate::util::fs::canonicalize_path_maybe_not_exists;
use self::common::InnerNpmPackageResolver;
use self::local::LocalNpmPackageResolver;
@ -187,7 +187,7 @@ impl NpmPackageResolver {
let path = self
.inner
.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());
Ok(path)
}

View file

@ -11,6 +11,7 @@ use crate::cache;
use crate::cache::DenoDir;
use crate::cache::EmitCache;
use crate::cache::FastInsecureHasher;
use crate::cache::HttpCache;
use crate::cache::NodeAnalysisCache;
use crate::cache::ParsedSourceCache;
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::GraphData;
use crate::graph_util::ModuleEntry;
use crate::http_cache;
use crate::http_util::HttpClient;
use crate::node;
use crate::node::NodeResolution;
@ -28,9 +28,9 @@ use crate::npm::NpmCache;
use crate::npm::NpmPackageReference;
use crate::npm::NpmPackageResolver;
use crate::npm::RealNpmRegistryApi;
use crate::progress_bar::ProgressBar;
use crate::resolver::CliResolver;
use crate::tools::check;
use crate::util::progress_bar::ProgressBar;
use deno_ast::MediaType;
use deno_core::anyhow::anyhow;
@ -153,7 +153,7 @@ impl ProcState {
let compiled_wasm_module_store = CompiledWasmModuleStore::default();
let dir = cli_options.resolve_deno_dir()?;
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 cache_usage = cli_options.cache_setting();
let progress_bar = ProgressBar::default();

View file

@ -4,16 +4,16 @@ use crate::args::BenchFlags;
use crate::args::Flags;
use crate::args::TypeCheckMode;
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::graph_valid;
use crate::ops;
use crate::proc_state::ProcState;
use crate::tools::test::format_test_error;
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 deno_core::error::generic_error;
@ -32,6 +32,7 @@ use log::Level;
use serde::Deserialize;
use serde::Serialize;
use std::collections::HashSet;
use std::path::Path;
use std::path::PathBuf;
use tokio::sync::mpsc::unbounded_channel;
use tokio::sync::mpsc::UnboundedSender;
@ -469,6 +470,19 @@ async fn bench_specifiers(
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(
flags: Flags,
bench_flags: BenchFlags,

View file

@ -3,10 +3,10 @@
use crate::args::CoverageFlags;
use crate::args::Flags;
use crate::colors;
use crate::fs_util::collect_files;
use crate::proc_state::ProcState;
use crate::text_encoding::source_map_from_code;
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::ModuleSpecifier;

View file

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

View file

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

View file

@ -4,8 +4,8 @@ use crate::args::ConfigFlag;
use crate::args::Flags;
use crate::args::InstallFlags;
use crate::args::TypeCheckMode;
use crate::fs_util;
use crate::npm::NpmPackageReference;
use crate::util::fs::canonicalize_path_maybe_not_exists;
use deno_core::anyhow::Context;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
@ -107,9 +107,7 @@ exec deno {} "$@"
fn get_installer_root() -> Result<PathBuf, io::Error> {
if let Ok(env_dir) = env::var("DENO_INSTALL_ROOT") {
if !env_dir.is_empty() {
return fs_util::canonicalize_path_maybe_not_exists(&PathBuf::from(
env_dir,
));
return canonicalize_path_maybe_not_exists(&PathBuf::from(env_dir));
}
}
// 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> {
let root = if let Some(root) = root {
fs_util::canonicalize_path_maybe_not_exists(&root)?
canonicalize_path_maybe_not_exists(&root)?
} else {
get_installer_root()?
};
@ -275,7 +273,7 @@ fn resolve_shim_data(
install_flags: &InstallFlags,
) -> Result<ShimData, AnyError> {
let root = if let Some(root) = &install_flags.root {
fs_util::canonicalize_path_maybe_not_exists(root)?
canonicalize_path_maybe_not_exists(root)?
} else {
get_installer_root()?
};
@ -450,6 +448,7 @@ mod tests {
use super::*;
use crate::args::ConfigFlag;
use crate::util::fs::canonicalize_path;
use std::process::Command;
use test_util::testdata_path;
use test_util::TempDir;
@ -746,7 +745,7 @@ mod tests {
#[test]
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(
&Flags {
allow_all: true,

View file

@ -10,13 +10,13 @@ use crate::args::Flags;
use crate::args::LintConfig;
use crate::args::LintFlags;
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::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_core::anyhow::anyhow;
use deno_core::error::generic_error;

View file

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

View file

@ -3,8 +3,8 @@
use crate::args::Flags;
use crate::args::TaskFlags;
use crate::colors;
use crate::fs_util;
use crate::proc_state::ProcState;
use crate::util::fs::canonicalize_path;
use deno_core::anyhow::bail;
use deno_core::anyhow::Context;
use deno_core::error::AnyError;
@ -40,7 +40,7 @@ pub async fn execute_script(
}
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(),
};
let task_name = task_flags.task;

View file

@ -3,20 +3,20 @@
use crate::args::Flags;
use crate::args::TestFlags;
use crate::args::TypeCheckMode;
use crate::checksum;
use crate::colors;
use crate::display;
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::graph_valid;
use crate::ops;
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 deno_ast::swc::common::comments::CommentKind;
@ -51,6 +51,7 @@ use std::fmt::Write as _;
use std::io::Read;
use std::io::Write;
use std::num::NonZeroUsize;
use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;
@ -1184,6 +1185,44 @@ async fn test_specifiers(
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
/// 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::Resolved;
use crate::fs_util::path_with_stem_suffix;
use crate::fs_util::relative_specifier;
use crate::util::path::path_with_stem_suffix;
use crate::util::path::relative_specifier;
use super::specifiers::dir_name_for_root;
use super::specifiers::get_unique_path;

View file

@ -15,11 +15,12 @@ use crate::args::CliOptions;
use crate::args::Flags;
use crate::args::FmtOptionsConfig;
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::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 build;
@ -38,7 +39,7 @@ pub async fn vendor(
Some(output_path) => output_path.to_owned(),
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_options(&mut cli_options, &output_dir)?;
let ps = ProcState::from_options(Arc::new(cli_options)).await?;
@ -110,18 +111,17 @@ fn validate_options(
if let Some(import_map_path) = options
.resolve_import_map_specifier()?
.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
std::fs::create_dir_all(output_dir)?;
let output_dir =
fs_util::canonicalize_path(output_dir).with_context(|| {
format!("Failed to canonicalize: {}", output_dir.display())
})?;
let output_dir = canonicalize_path(output_dir).with_context(|| {
format!("Failed to canonicalize: {}", output_dir.display())
})?;
if import_map_path.starts_with(&output_dir) {
// 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
// new state because this may lead to cryptic error messages.
log::warn!(

View file

@ -8,8 +8,9 @@ use deno_ast::ModuleSpecifier;
use deno_core::anyhow::anyhow;
use deno_core::error::AnyError;
use crate::fs_util;
use crate::fs_util::path_with_stem_suffix;
use crate::util::path::is_banned_path_char;
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.
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.
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
@ -74,13 +75,7 @@ pub fn is_remote_specifier_text(text: &str) -> bool {
pub fn sanitize_filepath(text: &str) -> String {
text
.chars()
.map(|c| {
if fs_util::is_banned_path_char(c) {
'_'
} else {
c
}
})
.map(|c| if is_banned_path_char(c) { '_' } else { c })
.collect()
}

View file

@ -9,6 +9,7 @@ use crate::node::NodeResolution;
use crate::node::NodeResolutionMode;
use crate::npm::NpmPackageReference;
use crate::npm::NpmPackageResolver;
use crate::util::checksum;
use deno_ast::MediaType;
use deno_core::anyhow::anyhow;
@ -178,7 +179,7 @@ fn get_maybe_hash(
if let Some(source) = maybe_source {
let mut data = vec![source.as_bytes().to_owned()];
data.extend_from_slice(hash_data);
Some(crate::checksum::gen(&data))
Some(checksum::gen(&data))
} else {
None
}
@ -186,7 +187,7 @@ fn get_maybe_hash(
/// Hash the URL so it can be sent to `tsc` in a supportable way
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!(
"{}:///{}{}",
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\".")?;
let mut data = vec![v.data.as_bytes().to_owned()];
data.extend_from_slice(&state.hash_data);
let hash = crate::checksum::gen(&data);
let hash = checksum::gen(&data);
Ok(json!({ "hash": hash }))
}

View file

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

View file

@ -1,13 +1,11 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use deno_core::anyhow::Context;
use deno_core::error::uri_error;
use deno_core::error::AnyError;
pub use deno_core::normalize_path;
use deno_core::ModuleSpecifier;
use deno_runtime::deno_crypto::rand;
use deno_runtime::deno_node::PathClean;
use std::borrow::Cow;
use std::env::current_dir;
use std::fs::OpenOptions;
use std::io::Error;
@ -18,6 +16,8 @@ use std::path::PathBuf;
use std::time::Duration;
use walkdir::WalkDir;
use super::path::specifier_to_file_path;
pub fn atomic_write_file<T: AsRef<[u8]>>(
filename: &Path,
data: T,
@ -163,77 +163,6 @@ pub fn resolve_from_cwd(path: &Path) -> Result<PathBuf, AnyError> {
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`.
/// If the walker visits a path that is listed in `ignore`, it skips descending into the directory.
pub fn collect_files<P>(
@ -461,201 +390,6 @@ pub fn symlink_dir(oldpath: &Path, newpath: &Path) -> Result<(), AnyError> {
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.
pub fn dir_size(path: &Path) -> std::io::Result<u64> {
let entries = std::fs::read_dir(path)?;
@ -718,83 +452,6 @@ mod tests {
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]
fn test_collect_files() {
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 crate::args::DenoSubcommand;
use crate::checksum;
use crate::errors;
use crate::module_loader::CliModuleLoader;
use crate::node;
@ -34,6 +33,7 @@ use crate::proc_state::ProcState;
use crate::tools;
use crate::tools::coverage::CoverageCollector;
use crate::tools::test::TestMode;
use crate::util::checksum;
use crate::version;
pub struct CliMainWorker {

View file

@ -1,7 +1,7 @@
#!/usr/bin/env -S deno run --unstable --allow-read --allow-write
// 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",
};