feat(lsp): add cache command (#8911)

This commit is contained in:
Kitson Kelly 2020-12-30 15:17:17 +11:00 committed by GitHub
parent e8a81724bb
commit 8011eced14
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 165 additions and 111 deletions

View File

@ -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.

View File

@ -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;

View File

@ -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::*;

View File

@ -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>>,

View File

@ -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(),
)?));

View File

@ -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()
}));

View File

@ -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,
)?))

View File

@ -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?;

View File

@ -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(

View File

@ -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,