summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKitson Kelly <me@kitsonkelly.com>2020-12-30 15:17:17 +1100
committerGitHub <noreply@github.com>2020-12-30 15:17:17 +1100
commit8011eced141e7bf0e1eac334daf326bd49504748 (patch)
tree3d2bdd36cc4f19285ba5292b9946cdabf466d25b
parente8a81724bb3b3767edaddbe78edc52108ae78b5f (diff)
feat(lsp): add cache command (#8911)
-rw-r--r--cli/file_fetcher.rs14
-rw-r--r--cli/lsp/diagnostics.rs4
-rw-r--r--cli/lsp/language_server.rs97
-rw-r--r--cli/lsp/sources.rs20
-rw-r--r--cli/main.rs8
-rw-r--r--cli/module_graph.rs87
-rw-r--r--cli/ops/runtime_compiler.rs11
-rw-r--r--cli/program_state.rs4
-rw-r--r--cli/specifier_handler.rs7
-rw-r--r--cli/tsc.rs24
10 files changed, 165 insertions, 111 deletions
diff --git a/cli/file_fetcher.rs b/cli/file_fetcher.rs
index 86c0ac966..52e9cc800 100644
--- a/cli/file_fetcher.rs
+++ b/cli/file_fetcher.rs
@@ -364,25 +364,25 @@ impl FileFetcher {
specifier: &ModuleSpecifier,
permissions: &Permissions,
redirect_limit: i64,
- ) -> Pin<Box<dyn Future<Output = Result<File, AnyError>>>> {
+ ) -> Pin<Box<dyn Future<Output = Result<File, AnyError>> + Send>> {
debug!("FileFetcher::fetch_remote() - specifier: {}", specifier);
if redirect_limit < 0 {
return futures::future::err(custom_error("Http", "Too many redirects."))
- .boxed_local();
+ .boxed();
}
if let Err(err) = permissions.check_specifier(specifier) {
- return futures::future::err(err).boxed_local();
+ return futures::future::err(err).boxed();
}
if self.cache_setting.should_use(specifier) {
match self.fetch_cached(specifier, redirect_limit) {
Ok(Some(file)) => {
- return futures::future::ok(file).boxed_local();
+ return futures::future::ok(file).boxed();
}
Ok(None) => {}
Err(err) => {
- return futures::future::err(err).boxed_local();
+ return futures::future::err(err).boxed();
}
}
}
@@ -395,7 +395,7 @@ impl FileFetcher {
specifier
),
))
- .boxed_local();
+ .boxed();
}
info!("{} {}", colors::green("Download"), specifier);
@@ -436,7 +436,7 @@ impl FileFetcher {
}
}
}
- .boxed_local()
+ .boxed()
}
/// Fetch a source file and asynchronously return it.
diff --git a/cli/lsp/diagnostics.rs b/cli/lsp/diagnostics.rs
index ac938d063..e7be61cdc 100644
--- a/cli/lsp/diagnostics.rs
+++ b/cli/lsp/diagnostics.rs
@@ -60,6 +60,10 @@ impl DiagnosticCollection {
self.versions.get(file_id).cloned()
}
+ pub fn invalidate(&mut self, file_id: &FileId) {
+ self.versions.remove(file_id);
+ }
+
pub fn take_changes(&mut self) -> Option<HashSet<FileId>> {
if self.changes.is_empty() {
return None;
diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs
index e70c0198d..08ece2b62 100644
--- a/cli/lsp/language_server.rs
+++ b/cli/lsp/language_server.rs
@@ -9,9 +9,8 @@ use deno_core::serde_json::json;
use deno_core::serde_json::Value;
use deno_core::ModuleSpecifier;
use dprint_plugin_typescript as dprint;
-use lspower::jsonrpc::Error as LSPError;
-use lspower::jsonrpc::ErrorCode as LSPErrorCode;
-use lspower::jsonrpc::Result as LSPResult;
+use lspower::jsonrpc::Error as LspError;
+use lspower::jsonrpc::Result as LspResult;
use lspower::lsp_types::*;
use lspower::Client;
use std::collections::HashMap;
@@ -33,6 +32,7 @@ use super::diagnostics;
use super::diagnostics::DiagnosticCollection;
use super::diagnostics::DiagnosticSource;
use super::memory_cache::MemoryCache;
+use super::sources;
use super::sources::Sources;
use super::text;
use super::text::apply_content_changes;
@@ -361,7 +361,7 @@ impl lspower::LanguageServer for LanguageServer {
async fn initialize(
&self,
params: InitializeParams,
- ) -> LSPResult<InitializeResult> {
+ ) -> LspResult<InitializeResult> {
info!("Starting Deno language server...");
let capabilities = capabilities::server_capabilities(&params.capabilities);
@@ -439,7 +439,7 @@ impl lspower::LanguageServer for LanguageServer {
info!("Server ready.");
}
- async fn shutdown(&self) -> LSPResult<()> {
+ async fn shutdown(&self) -> LspResult<()> {
Ok(())
}
@@ -586,7 +586,7 @@ impl lspower::LanguageServer for LanguageServer {
async fn formatting(
&self,
params: DocumentFormattingParams,
- ) -> LSPResult<Option<Vec<TextEdit>>> {
+ ) -> LspResult<Option<Vec<TextEdit>>> {
let specifier = utils::normalize_url(params.text_document.uri.clone());
let file_text = {
let file_cache = self.file_cache.read().unwrap();
@@ -631,7 +631,7 @@ impl lspower::LanguageServer for LanguageServer {
}
}
- async fn hover(&self, params: HoverParams) -> LSPResult<Option<Hover>> {
+ async fn hover(&self, params: HoverParams) -> LspResult<Option<Hover>> {
if !self.enabled() {
return Ok(None);
}
@@ -662,7 +662,7 @@ impl lspower::LanguageServer for LanguageServer {
async fn document_highlight(
&self,
params: DocumentHighlightParams,
- ) -> LSPResult<Option<Vec<DocumentHighlight>>> {
+ ) -> LspResult<Option<Vec<DocumentHighlight>>> {
if !self.enabled() {
return Ok(None);
}
@@ -702,7 +702,7 @@ impl lspower::LanguageServer for LanguageServer {
async fn references(
&self,
params: ReferenceParams,
- ) -> LSPResult<Option<Vec<Location>>> {
+ ) -> LspResult<Option<Vec<Location>>> {
if !self.enabled() {
return Ok(None);
}
@@ -743,7 +743,7 @@ impl lspower::LanguageServer for LanguageServer {
async fn goto_definition(
&self,
params: GotoDefinitionParams,
- ) -> LSPResult<Option<GotoDefinitionResponse>> {
+ ) -> LspResult<Option<GotoDefinitionResponse>> {
if !self.enabled() {
return Ok(None);
}
@@ -779,7 +779,7 @@ impl lspower::LanguageServer for LanguageServer {
async fn completion(
&self,
params: CompletionParams,
- ) -> LSPResult<Option<CompletionResponse>> {
+ ) -> LspResult<Option<CompletionResponse>> {
if !self.enabled() {
return Ok(None);
}
@@ -812,7 +812,7 @@ impl lspower::LanguageServer for LanguageServer {
async fn rename(
&self,
params: RenameParams,
- ) -> LSPResult<Option<WorkspaceEdit>> {
+ ) -> LspResult<Option<WorkspaceEdit>> {
if !self.enabled() {
return Ok(None);
}
@@ -827,7 +827,7 @@ impl lspower::LanguageServer for LanguageServer {
.await
.map_err(|err| {
error!("Failed to get line_index {:#?}", err);
- LSPError::internal_error()
+ LspError::internal_error()
})?;
let req = tsc::RequestMethod::FindRenameLocations((
@@ -844,7 +844,7 @@ impl lspower::LanguageServer for LanguageServer {
.await
.map_err(|err| {
error!("Failed to request to tsserver {:#?}", err);
- LSPError::invalid_request()
+ LspError::invalid_request()
})?;
let maybe_locations = serde_json::from_value::<
@@ -855,7 +855,7 @@ impl lspower::LanguageServer for LanguageServer {
"Failed to deserialize tsserver response to Vec<RenameLocation> {:#?}",
err
);
- LSPError::internal_error()
+ LspError::internal_error()
})?;
match maybe_locations {
@@ -873,7 +873,7 @@ impl lspower::LanguageServer for LanguageServer {
"Failed to convert tsc::RenameLocations to WorkspaceEdit {:#?}",
err
);
- LSPError::internal_error()
+ LspError::internal_error()
})?;
Ok(Some(workpace_edits))
}
@@ -885,8 +885,18 @@ impl lspower::LanguageServer for LanguageServer {
&self,
method: &str,
params: Option<Value>,
- ) -> LSPResult<Option<Value>> {
+ ) -> LspResult<Option<Value>> {
match method {
+ "deno/cache" => match params.map(serde_json::from_value) {
+ Some(Ok(params)) => Ok(Some(
+ serde_json::to_value(self.cache(params).await?).map_err(|err| {
+ error!("Failed to serialize cache response: {:#?}", err);
+ LspError::internal_error()
+ })?,
+ )),
+ Some(Err(err)) => Err(LspError::invalid_params(err.to_string())),
+ None => Err(LspError::invalid_params("Missing parameters")),
+ },
"deno/virtualTextDocument" => match params.map(serde_json::from_value) {
Some(Ok(params)) => Ok(Some(
serde_json::to_value(self.virtual_text_document(params).await?)
@@ -895,25 +905,60 @@ impl lspower::LanguageServer for LanguageServer {
"Failed to serialize virtual_text_document response: {:#?}",
err
);
- LSPError::internal_error()
+ LspError::internal_error()
})?,
)),
- Some(Err(err)) => Err(LSPError::invalid_params(err.to_string())),
- None => Err(LSPError::invalid_params("Missing parameters")),
+ Some(Err(err)) => Err(LspError::invalid_params(err.to_string())),
+ None => Err(LspError::invalid_params("Missing parameters")),
},
_ => {
error!("Got a {} request, but no handler is defined", method);
- Err(LSPError::method_not_found())
+ Err(LspError::method_not_found())
}
}
}
}
+#[derive(Debug, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct CacheParams {
+ pub text_document: TextDocumentIdentifier,
+}
+
+#[derive(Debug, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct VirtualTextDocumentParams {
+ pub text_document: TextDocumentIdentifier,
+}
+
impl LanguageServer {
+ async fn cache(&self, params: CacheParams) -> LspResult<bool> {
+ let specifier = utils::normalize_url(params.text_document.uri);
+ let maybe_import_map = self.maybe_import_map.read().unwrap().clone();
+ sources::cache(specifier.clone(), maybe_import_map)
+ .await
+ .map_err(|err| {
+ error!("{}", err);
+ LspError::internal_error()
+ })?;
+ {
+ let file_cache = self.file_cache.read().unwrap();
+ if let Some(file_id) = file_cache.lookup(&specifier) {
+ let mut diagnostics_collection = self.diagnostics.write().unwrap();
+ diagnostics_collection.invalidate(&file_id);
+ }
+ }
+ self.prepare_diagnostics().await.map_err(|err| {
+ error!("{}", err);
+ LspError::internal_error()
+ })?;
+ Ok(true)
+ }
+
async fn virtual_text_document(
&self,
params: VirtualTextDocumentParams,
- ) -> LSPResult<Option<String>> {
+ ) -> LspResult<Option<String>> {
let specifier = utils::normalize_url(params.text_document.uri);
let url = specifier.as_url();
let contents = if url.as_str() == "deno:/status.md" {
@@ -933,7 +978,7 @@ impl LanguageServer {
if let Some(text) =
tsc::get_asset(&specifier, &self.ts_server, &state_snapshot)
.await
- .map_err(|_| LSPError::new(LSPErrorCode::InternalError))?
+ .map_err(|_| LspError::internal_error())?
{
Some(text)
} else {
@@ -1009,12 +1054,6 @@ impl DocumentData {
}
}
-#[derive(Debug, Deserialize, Serialize)]
-#[serde(rename_all = "camelCase")]
-pub struct VirtualTextDocumentParams {
- pub text_document: TextDocumentIdentifier,
-}
-
#[cfg(test)]
mod tests {
use super::*;
diff --git a/cli/lsp/sources.rs b/cli/lsp/sources.rs
index c6ab87f21..5ef16a876 100644
--- a/cli/lsp/sources.rs
+++ b/cli/lsp/sources.rs
@@ -10,16 +10,36 @@ use crate::http_cache;
use crate::http_cache::HttpCache;
use crate::import_map::ImportMap;
use crate::media_type::MediaType;
+use crate::module_graph::GraphBuilder;
+use crate::program_state::ProgramState;
+use crate::specifier_handler::FetchHandler;
use crate::text_encoding;
+use crate::Permissions;
+use deno_core::error::AnyError;
use deno_core::serde_json;
use deno_core::ModuleSpecifier;
use std::collections::HashMap;
use std::fs;
use std::path::Path;
use std::path::PathBuf;
+use std::sync::Arc;
+use std::sync::Mutex;
use std::time::SystemTime;
+pub async fn cache(
+ specifier: ModuleSpecifier,
+ maybe_import_map: Option<ImportMap>,
+) -> Result<(), AnyError> {
+ let program_state = Arc::new(ProgramState::new(Default::default())?);
+ let handler = Arc::new(Mutex::new(FetchHandler::new(
+ &program_state,
+ Permissions::allow_all(),
+ )?));
+ let mut builder = GraphBuilder::new(handler, maybe_import_map, None);
+ builder.add(&specifier, false).await
+}
+
#[derive(Debug, Clone, Default)]
struct Metadata {
dependencies: Option<HashMap<String, analysis::Dependency>>,
diff --git a/cli/main.rs b/cli/main.rs
index 578ea6846..ac0d2f591 100644
--- a/cli/main.rs
+++ b/cli/main.rs
@@ -76,7 +76,6 @@ use deno_runtime::worker::MainWorker;
use deno_runtime::worker::WorkerOptions;
use log::Level;
use log::LevelFilter;
-use std::cell::RefCell;
use std::env;
use std::io::Read;
use std::io::Write;
@@ -85,6 +84,7 @@ use std::path::PathBuf;
use std::pin::Pin;
use std::rc::Rc;
use std::sync::Arc;
+use std::sync::Mutex;
fn create_web_worker_callback(
program_state: Arc<ProgramState>,
@@ -349,7 +349,7 @@ async fn info_command(
let program_state = ProgramState::new(flags)?;
if let Some(specifier) = maybe_specifier {
let specifier = ModuleSpecifier::resolve_url_or_path(&specifier)?;
- let handler = Rc::new(RefCell::new(specifier_handler::FetchHandler::new(
+ let handler = Arc::new(Mutex::new(specifier_handler::FetchHandler::new(
&program_state,
// info accesses dynamically imported modules just for their information
// so we allow access to all of them.
@@ -497,7 +497,7 @@ async fn create_module_graph_and_maybe_check(
program_state: Arc<ProgramState>,
debug: bool,
) -> Result<module_graph::Graph, AnyError> {
- let handler = Rc::new(RefCell::new(FetchHandler::new(
+ let handler = Arc::new(Mutex::new(FetchHandler::new(
&program_state,
// when bundling, dynamic imports are only access for their type safety,
// therefore we will allow the graph to access any module.
@@ -850,7 +850,7 @@ async fn run_with_watch(flags: Flags, script: String) -> Result<(), AnyError> {
async move {
let main_module = ModuleSpecifier::resolve_url_or_path(&script1)?;
let program_state = ProgramState::new(flags)?;
- let handler = Rc::new(RefCell::new(FetchHandler::new(
+ let handler = Arc::new(Mutex::new(FetchHandler::new(
&program_state,
Permissions::allow_all(),
)?));
diff --git a/cli/module_graph.rs b/cli/module_graph.rs
index f5e08882e..be0f428b4 100644
--- a/cli/module_graph.rs
+++ b/cli/module_graph.rs
@@ -43,7 +43,6 @@ use deno_core::ModuleResolutionError;
use deno_core::ModuleSource;
use deno_core::ModuleSpecifier;
use regex::Regex;
-use std::cell::RefCell;
use std::collections::HashSet;
use std::collections::{BTreeSet, HashMap};
use std::error::Error;
@@ -239,8 +238,7 @@ pub struct Module {
is_parsed: bool,
maybe_emit: Option<Emit>,
maybe_emit_path: Option<(PathBuf, Option<PathBuf>)>,
- maybe_import_map: Option<Rc<RefCell<ImportMap>>>,
- maybe_parsed_module: Option<ParsedModule>,
+ maybe_import_map: Option<Arc<Mutex<ImportMap>>>,
maybe_types: Option<(String, ModuleSpecifier)>,
maybe_version: Option<String>,
media_type: MediaType,
@@ -258,7 +256,6 @@ impl Default for Module {
maybe_emit: None,
maybe_emit_path: None,
maybe_import_map: None,
- maybe_parsed_module: None,
maybe_types: None,
maybe_version: None,
media_type: MediaType::Unknown,
@@ -273,7 +270,7 @@ impl Module {
pub fn new(
cached_module: CachedModule,
is_root: bool,
- maybe_import_map: Option<Rc<RefCell<ImportMap>>>,
+ maybe_import_map: Option<Arc<Mutex<ImportMap>>>,
) -> Self {
// If this is a local root file, and its media type is unknown, set the
// media type to JavaScript. This allows easier ability to create "shell"
@@ -330,7 +327,7 @@ impl Module {
/// Parse a module, populating the structure with data retrieved from the
/// source of the module.
- pub fn parse(&mut self) -> Result<(), AnyError> {
+ pub fn parse(&mut self) -> Result<ParsedModule, AnyError> {
let parsed_module =
parse(self.specifier.as_str(), &self.source, &self.media_type)?;
@@ -430,9 +427,7 @@ impl Module {
dep.maybe_type = maybe_type;
}
}
-
- self.maybe_parsed_module = Some(parsed_module);
- Ok(())
+ Ok(parsed_module)
}
fn resolve_import(
@@ -443,7 +438,8 @@ impl Module {
let maybe_resolve = if let Some(import_map) = self.maybe_import_map.clone()
{
import_map
- .borrow()
+ .lock()
+ .unwrap()
.resolve(specifier, self.specifier.as_str())?
} else {
None
@@ -650,7 +646,7 @@ pub struct TranspileOptions {
#[derive(Debug, Clone)]
enum ModuleSlot {
/// The module fetch resulted in a non-recoverable error.
- Err(Rc<AnyError>),
+ Err(Arc<AnyError>),
/// The the fetch resulted in a module.
Module(Box<Module>),
/// Used to denote a module that isn't part of the graph.
@@ -666,7 +662,7 @@ enum ModuleSlot {
pub struct Graph {
/// A reference to the specifier handler that will retrieve and cache modules
/// for the graph.
- handler: Rc<RefCell<dyn SpecifierHandler>>,
+ handler: Arc<Mutex<dyn SpecifierHandler>>,
/// Optional TypeScript build info that will be passed to `tsc` if `tsc` is
/// invoked.
maybe_tsbuildinfo: Option<String>,
@@ -734,7 +730,7 @@ impl Graph {
/// `SpecifierHandler` trait.
///
pub fn new(
- handler: Rc<RefCell<dyn SpecifierHandler>>,
+ handler: Arc<Mutex<dyn SpecifierHandler>>,
maybe_lockfile: Option<Arc<Mutex<Lockfile>>>,
) -> Self {
Graph {
@@ -844,7 +840,7 @@ impl Graph {
let maybe_tsbuildinfo = self.maybe_tsbuildinfo.clone();
let hash_data =
vec![config.as_bytes(), version::deno().as_bytes().to_owned()];
- let graph = Rc::new(RefCell::new(self));
+ let graph = Arc::new(Mutex::new(self));
let response = tsc::exec(
js::compiler_isolate_init(),
@@ -858,7 +854,7 @@ impl Graph {
},
)?;
- let mut graph = graph.borrow_mut();
+ let mut graph = graph.lock().unwrap();
graph.maybe_tsbuildinfo = response.maybe_tsbuildinfo;
// Only process changes to the graph if there are no diagnostics and there
// were files emitted.
@@ -964,7 +960,7 @@ impl Graph {
let root_names = self.get_root_names(!config.get_check_js());
let hash_data =
vec![config.as_bytes(), version::deno().as_bytes().to_owned()];
- let graph = Rc::new(RefCell::new(self));
+ let graph = Arc::new(Mutex::new(self));
let response = tsc::exec(
js::compiler_isolate_init(),
@@ -979,7 +975,7 @@ impl Graph {
)?;
let mut emitted_files = HashMap::new();
- let graph = graph.borrow();
+ let graph = graph.lock().unwrap();
match options.bundle_type {
BundleType::Esm => {
assert!(
@@ -1081,7 +1077,7 @@ impl Graph {
/// Update the handler with any modules that are marked as _dirty_ and update
/// any build info if present.
fn flush(&mut self) -> Result<(), AnyError> {
- let mut handler = self.handler.borrow_mut();
+ let mut handler = self.handler.lock().unwrap();
for (_, module_slot) in self.modules.iter_mut() {
if let ModuleSlot::Module(module) = module_slot {
if module.is_dirty {
@@ -1595,10 +1591,7 @@ impl Graph {
if !options.reload && module.is_emit_valid(&config) {
continue;
}
- if module.maybe_parsed_module.is_none() {
- module.parse()?;
- }
- let parsed_module = module.maybe_parsed_module.clone().unwrap();
+ let parsed_module = module.parse()?;
let emit = parsed_module.transpile(&emit_options)?;
emit_count += 1;
module.maybe_emit = Some(Emit::Cli(emit));
@@ -1647,18 +1640,18 @@ impl swc_bundler::Resolve for Graph {
/// A structure for building a dependency graph of modules.
pub struct GraphBuilder {
graph: Graph,
- maybe_import_map: Option<Rc<RefCell<ImportMap>>>,
+ maybe_import_map: Option<Arc<Mutex<ImportMap>>>,
pending: FuturesUnordered<FetchFuture>,
}
impl GraphBuilder {
pub fn new(
- handler: Rc<RefCell<dyn SpecifierHandler>>,
+ handler: Arc<Mutex<dyn SpecifierHandler>>,
maybe_import_map: Option<ImportMap>,
maybe_lockfile: Option<Arc<Mutex<Lockfile>>>,
) -> Self {
let internal_import_map = if let Some(import_map) = maybe_import_map {
- Some(Rc::new(RefCell::new(import_map)))
+ Some(Arc::new(Mutex::new(import_map)))
} else {
None
};
@@ -1685,7 +1678,7 @@ impl GraphBuilder {
self
.graph
.modules
- .insert(specifier, ModuleSlot::Err(Rc::new(err)));
+ .insert(specifier, ModuleSlot::Err(Arc::new(err)));
}
Some(Ok(cached_module)) => {
let is_root = &cached_module.specifier == specifier;
@@ -1702,7 +1695,7 @@ impl GraphBuilder {
self.graph.roots.push(specifier.clone());
self.graph.roots_dynamic = self.graph.roots_dynamic && is_dynamic;
if self.graph.maybe_tsbuildinfo.is_none() {
- let handler = self.graph.handler.borrow();
+ let handler = self.graph.handler.lock().unwrap();
self.graph.maybe_tsbuildinfo = handler.get_tsbuildinfo(specifier)?;
}
}
@@ -1723,11 +1716,9 @@ impl GraphBuilder {
.graph
.modules
.insert(specifier.clone(), ModuleSlot::Pending);
- let future = self.graph.handler.borrow_mut().fetch(
- specifier.clone(),
- maybe_referrer.clone(),
- is_dynamic,
- );
+ let mut handler = self.graph.handler.lock().unwrap();
+ let future =
+ handler.fetch(specifier.clone(), maybe_referrer.clone(), is_dynamic);
self.pending.push(future);
}
}
@@ -1763,7 +1754,7 @@ impl GraphBuilder {
let has_types = module.maybe_types.is_some();
module.parse()?;
if self.maybe_import_map.is_none() {
- let mut handler = self.graph.handler.borrow_mut();
+ let mut handler = self.graph.handler.lock().unwrap();
handler.set_deps(&specifier, module.dependencies.clone())?;
if !has_types {
if let Some((types, _)) = module.maybe_types.clone() {
@@ -1934,10 +1925,10 @@ pub mod tests {
async fn setup(
specifier: ModuleSpecifier,
- ) -> (Graph, Rc<RefCell<MockSpecifierHandler>>) {
+ ) -> (Graph, Arc<Mutex<MockSpecifierHandler>>) {
let c = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
let fixtures = c.join("tests/module_graph");
- let handler = Rc::new(RefCell::new(MockSpecifierHandler {
+ let handler = Arc::new(Mutex::new(MockSpecifierHandler {
fixtures,
..MockSpecifierHandler::default()
}));
@@ -1958,7 +1949,7 @@ pub mod tests {
.iter()
.map(|(k, v)| (k.to_string(), v.to_string()))
.collect();
- let handler = Rc::new(RefCell::new(MemoryHandler::new(sources)));
+ let handler = Arc::new(Mutex::new(MemoryHandler::new(sources)));
let mut builder = GraphBuilder::new(handler.clone(), None, None);
builder
.add(&specifier, false)
@@ -2064,7 +2055,7 @@ pub mod tests {
for (specifier, expected_str) in tests {
let specifier = ModuleSpecifier::resolve_url_or_path(specifier).unwrap();
- let handler = Rc::new(RefCell::new(MockSpecifierHandler {
+ let handler = Arc::new(Mutex::new(MockSpecifierHandler {
fixtures: fixtures.clone(),
..MockSpecifierHandler::default()
}));
@@ -2103,7 +2094,7 @@ pub mod tests {
assert!(result_info.maybe_ignored_options.is_none());
assert_eq!(result_info.stats.0.len(), 12);
assert!(result_info.diagnostics.is_empty());
- let h = handler.borrow();
+ let h = handler.lock().unwrap();
assert_eq!(h.cache_calls.len(), 2);
assert_eq!(h.tsbuildinfo_calls.len(), 1);
}
@@ -2144,7 +2135,7 @@ pub mod tests {
assert!(result_info.maybe_ignored_options.is_none());
assert_eq!(result_info.stats.0.len(), 12);
assert!(!result_info.diagnostics.is_empty());
- let h = handler.borrow();
+ let h = handler.lock().unwrap();
// we shouldn't cache any files or write out tsbuildinfo if there are
// diagnostic errors
assert_eq!(h.cache_calls.len(), 0);
@@ -2169,7 +2160,7 @@ pub mod tests {
assert!(result_info.maybe_ignored_options.is_none());
assert_eq!(result_info.stats.0.len(), 12);
assert!(result_info.diagnostics.is_empty());
- let h = handler.borrow();
+ let h = handler.lock().unwrap();
assert_eq!(h.cache_calls.len(), 0);
assert_eq!(h.tsbuildinfo_calls.len(), 1);
}
@@ -2190,7 +2181,7 @@ pub mod tests {
.expect("should have checked");
assert!(result_info.maybe_ignored_options.is_none());
assert!(result_info.diagnostics.is_empty());
- let h = handler.borrow();
+ let h = handler.lock().unwrap();
assert_eq!(h.cache_calls.len(), 1);
assert_eq!(h.tsbuildinfo_calls.len(), 1);
}
@@ -2231,7 +2222,7 @@ pub mod tests {
.expect("should have checked");
assert!(result_info.maybe_ignored_options.is_none());
assert!(result_info.diagnostics.is_empty());
- let h = handler.borrow();
+ let h = handler.lock().unwrap();
assert_eq!(h.version_calls.len(), 2);
let ver0 = h.version_calls[0].1.clone();
let ver1 = h.version_calls[1].1.clone();
@@ -2251,7 +2242,7 @@ pub mod tests {
.expect("should have checked");
assert!(result_info.maybe_ignored_options.is_none());
assert!(result_info.diagnostics.is_empty());
- let h = handler.borrow();
+ let h = handler.lock().unwrap();
assert_eq!(h.version_calls.len(), 2);
assert!(h.version_calls[0].1 == ver0 || h.version_calls[0].1 == ver1);
assert!(h.version_calls[1].1 == ver0 || h.version_calls[1].1 == ver1);
@@ -2403,7 +2394,7 @@ pub mod tests {
.expect("could not resolve module");
let c = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
let fixtures = c.join("tests/module_graph");
- let handler = Rc::new(RefCell::new(MockSpecifierHandler {
+ let handler = Arc::new(Mutex::new(MockSpecifierHandler {
fixtures,
..MockSpecifierHandler::default()
}));
@@ -2430,7 +2421,7 @@ pub mod tests {
let result_info = graph.transpile(TranspileOptions::default()).unwrap();
assert_eq!(result_info.stats.0.len(), 3);
assert_eq!(result_info.maybe_ignored_options, None);
- let h = handler.borrow();
+ let h = handler.lock().unwrap();
assert_eq!(h.cache_calls.len(), 2);
match &h.cache_calls[0].1 {
Emit::Cli((code, maybe_map)) => {
@@ -2492,7 +2483,7 @@ pub mod tests {
vec!["target".to_string()],
"the 'target' options should have been ignored"
);
- let h = handler.borrow();
+ let h = handler.lock().unwrap();
assert_eq!(h.cache_calls.len(), 1, "only one file should be emitted");
// FIXME(bartlomieju): had to add space in `<div>`, probably a quirk in swc_ecma_codegen
match &h.cache_calls[0].1 {
@@ -2521,7 +2512,7 @@ pub mod tests {
)
.expect("could not parse import map"),
);
- let handler = Rc::new(RefCell::new(MockSpecifierHandler {
+ let handler = Arc::new(Mutex::new(MockSpecifierHandler {
fixtures,
..Default::default()
}));
@@ -2541,7 +2532,7 @@ pub mod tests {
let lockfile =
Lockfile::new(lockfile_path, false).expect("could not load lockfile");
let maybe_lockfile = Some(Arc::new(Mutex::new(lockfile)));
- let handler = Rc::new(RefCell::new(MockSpecifierHandler {
+ let handler = Arc::new(Mutex::new(MockSpecifierHandler {
fixtures,
..MockSpecifierHandler::default()
}));
diff --git a/cli/ops/runtime_compiler.rs b/cli/ops/runtime_compiler.rs
index ec9806e60..bb3e47226 100644
--- a/cli/ops/runtime_compiler.rs
+++ b/cli/ops/runtime_compiler.rs
@@ -11,8 +11,6 @@ use crate::specifier_handler::FetchHandler;
use crate::specifier_handler::MemoryHandler;
use crate::specifier_handler::SpecifierHandler;
use crate::tsc_config;
-use deno_runtime::permissions::Permissions;
-use std::sync::Arc;
use deno_core::error::AnyError;
use deno_core::error::Context;
@@ -23,10 +21,13 @@ use deno_core::serde_json::Value;
use deno_core::BufVec;
use deno_core::ModuleSpecifier;
use deno_core::OpState;
+use deno_runtime::permissions::Permissions;
use serde::Deserialize;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
+use std::sync::Arc;
+use std::sync::Mutex;
pub fn init(rt: &mut deno_core::JsRuntime) {
super::reg_json_async(rt, "op_compile", op_compile);
@@ -58,11 +59,11 @@ async fn op_compile(
let state = state.borrow();
state.borrow::<Permissions>().clone()
};
- let handler: Rc<RefCell<dyn SpecifierHandler>> =
+ let handler: Arc<Mutex<dyn SpecifierHandler>> =
if let Some(sources) = args.sources {
- Rc::new(RefCell::new(MemoryHandler::new(sources)))
+ Arc::new(Mutex::new(MemoryHandler::new(sources)))
} else {
- Rc::new(RefCell::new(FetchHandler::new(
+ Arc::new(Mutex::new(FetchHandler::new(
&program_state,
runtime_permissions,
)?))
diff --git a/cli/program_state.rs b/cli/program_state.rs
index afae8c125..e55386fe5 100644
--- a/cli/program_state.rs
+++ b/cli/program_state.rs
@@ -23,10 +23,8 @@ use deno_core::error::AnyError;
use deno_core::url::Url;
use deno_core::ModuleSource;
use deno_core::ModuleSpecifier;
-use std::cell::RefCell;
use std::collections::HashMap;
use std::env;
-use std::rc::Rc;
use std::sync::Arc;
use std::sync::Mutex;
@@ -144,7 +142,7 @@ impl ProgramState {
runtime_permissions.check_specifier(&specifier)?;
}
let handler =
- Rc::new(RefCell::new(FetchHandler::new(self, runtime_permissions)?));
+ Arc::new(Mutex::new(FetchHandler::new(self, runtime_permissions)?));
let mut builder =
GraphBuilder::new(handler, maybe_import_map, self.lockfile.clone());
builder.add(&specifier, is_dynamic).await?;
diff --git a/cli/specifier_handler.rs b/cli/specifier_handler.rs
index 752316467..25ee915f9 100644
--- a/cli/specifier_handler.rs
+++ b/cli/specifier_handler.rs
@@ -28,7 +28,8 @@ pub type DependencyMap = HashMap<String, Dependency>;
pub type FetchFuture = Pin<
Box<
(dyn Future<Output = Result<CachedModule, (ModuleSpecifier, AnyError)>>
- + 'static),
+ + 'static
+ + Send),
>,
>;
@@ -129,7 +130,7 @@ impl Dependency {
}
}
-pub trait SpecifierHandler {
+pub trait SpecifierHandler: Sync + Send {
/// Instructs the handler to fetch a specifier or retrieve its value from the
/// cache.
fn fetch(
@@ -361,7 +362,7 @@ impl SpecifierHandler for FetchHandler {
specifier: source_file.specifier,
})
}
- .boxed_local()
+ .boxed()
}
fn get_tsbuildinfo(
diff --git a/cli/tsc.rs b/cli/tsc.rs
index d6de4e122..c21c52a56 100644
--- a/cli/tsc.rs
+++ b/cli/tsc.rs
@@ -20,10 +20,10 @@ use deno_core::OpFn;
use deno_core::RuntimeOptions;
use deno_core::Snapshot;
use serde::Deserialize;
-use std::cell::RefCell;
use std::collections::HashMap;
use std::path::PathBuf;
-use std::rc::Rc;
+use std::sync::Arc;
+use std::sync::Mutex;
/// Provide static assets that are not preloaded in the compiler snapshot.
pub fn get_asset(asset: &str) -> Option<&'static str> {
@@ -115,7 +115,7 @@ pub struct Request {
pub config: TsConfig,
/// Indicates to the tsc runtime if debug logging should occur.
pub debug: bool,
- pub graph: Rc<RefCell<Graph>>,
+ pub graph: Arc<Mutex<Graph>>,
pub hash_data: Vec<Vec<u8>>,
pub maybe_tsbuildinfo: Option<String>,
/// A vector of strings that represent the root/entry point modules for the
@@ -138,7 +138,7 @@ pub struct Response {
struct State {
hash_data: Vec<Vec<u8>>,
emitted_files: Vec<EmittedFile>,
- graph: Rc<RefCell<Graph>>,
+ graph: Arc<Mutex<Graph>>,
maybe_tsbuildinfo: Option<String>,
maybe_response: Option<RespondArgs>,
root_map: HashMap<String, ModuleSpecifier>,
@@ -146,7 +146,7 @@ struct State {
impl State {
pub fn new(
- graph: Rc<RefCell<Graph>>,
+ graph: Arc<Mutex<Graph>>,
hash_data: Vec<Vec<u8>>,
maybe_tsbuildinfo: Option<String>,
root_map: HashMap<String, ModuleSpecifier>,
@@ -260,7 +260,7 @@ fn load(state: &mut State, args: Value) -> Result<Value, AnyError> {
media_type = MediaType::from(&v.specifier);
maybe_source
} else {
- let graph = state.graph.borrow();
+ let graph = state.graph.lock().unwrap();
let specifier =
if let Some(remapped_specifier) = state.root_map.get(&v.specifier) {
remapped_specifier.clone()
@@ -310,7 +310,7 @@ fn resolve(state: &mut State, args: Value) -> Result<Value, AnyError> {
MediaType::from(specifier).as_ts_extension().to_string(),
));
} else {
- let graph = state.graph.borrow();
+ let graph = state.graph.lock().unwrap();
match graph.resolve(specifier, &referrer, true) {
Ok(resolved_specifier) => {
let media_type = if let Some(media_type) =
@@ -446,9 +446,9 @@ mod tests {
use crate::module_graph::tests::MockSpecifierHandler;
use crate::module_graph::GraphBuilder;
use crate::tsc_config::TsConfig;
- use std::cell::RefCell;
use std::env;
use std::path::PathBuf;
+ use std::sync::Mutex;
async fn setup(
maybe_specifier: Option<ModuleSpecifier>,
@@ -461,7 +461,7 @@ mod tests {
let hash_data = maybe_hash_data.unwrap_or_else(|| vec![b"".to_vec()]);
let c = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
let fixtures = c.join("tests/tsc2");
- let handler = Rc::new(RefCell::new(MockSpecifierHandler {
+ let handler = Arc::new(Mutex::new(MockSpecifierHandler {
fixtures,
..MockSpecifierHandler::default()
}));
@@ -470,7 +470,7 @@ mod tests {
.add(&specifier, false)
.await
.expect("module not inserted");
- let graph = Rc::new(RefCell::new(builder.get_graph()));
+ let graph = Arc::new(Mutex::new(builder.get_graph()));
State::new(graph, hash_data, maybe_tsbuildinfo, HashMap::new())
}
@@ -480,13 +480,13 @@ mod tests {
let hash_data = vec![b"something".to_vec()];
let c = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
let fixtures = c.join("tests/tsc2");
- let handler = Rc::new(RefCell::new(MockSpecifierHandler {
+ let handler = Arc::new(Mutex::new(MockSpecifierHandler {
fixtures,
..Default::default()
}));
let mut builder = GraphBuilder::new(handler.clone(), None, None);
builder.add(&specifier, false).await?;
- let graph = Rc::new(RefCell::new(builder.get_graph()));
+ let graph = Arc::new(Mutex::new(builder.get_graph()));
let config = TsConfig::new(json!({
"allowJs": true,
"checkJs": false,