summaryrefslogtreecommitdiff
path: root/cli/emit.rs
diff options
context:
space:
mode:
authorDavid Sherret <dsherret@users.noreply.github.com>2022-06-20 17:59:52 -0400
committerGitHub <noreply@github.com>2022-06-20 17:59:52 -0400
commita7339f756c5f871026ab080e849d3dd37f2ca124 (patch)
tree900d033db951a5e43d67b0ab0cc582fe3cc23b1a /cli/emit.rs
parenta7a64438e2cb054700cb35936c941b7444b8bd2d (diff)
refactor: add `EmitCache` trait (#14925)
Diffstat (limited to 'cli/emit.rs')
-rw-r--r--cli/emit.rs176
1 files changed, 148 insertions, 28 deletions
diff --git a/cli/emit.rs b/cli/emit.rs
index 1722cd881..10089bc8a 100644
--- a/cli/emit.rs
+++ b/cli/emit.rs
@@ -43,6 +43,90 @@ use std::result;
use std::sync::Arc;
use std::time::Instant;
+/// Emit cache for a single file.
+#[derive(Debug, Clone, PartialEq)]
+pub struct SpecifierEmitCacheData {
+ pub source_hash: String,
+ pub text: String,
+ pub map: Option<String>,
+}
+
+pub trait EmitCache {
+ /// Gets the emit data from the cache.
+ fn get_emit_data(
+ &self,
+ specifier: &ModuleSpecifier,
+ ) -> Option<SpecifierEmitCacheData>;
+ /// Gets the stored hash of the source of the provider specifier
+ /// to tell if the emit is out of sync with the source.
+ /// TODO(13302): this is actually not reliable and should be removed
+ /// once switching to an sqlite db
+ fn get_source_hash(&self, specifier: &ModuleSpecifier) -> Option<String>;
+ /// Gets the emitted JavaScript of the TypeScript source.
+ /// TODO(13302): remove this once switching to an sqlite db
+ fn get_emit_text(&self, specifier: &ModuleSpecifier) -> Option<String>;
+ /// Sets the emit data in the cache.
+ fn set_emit_data(
+ &self,
+ specifier: ModuleSpecifier,
+ data: SpecifierEmitCacheData,
+ ) -> Result<(), AnyError>;
+ /// Gets the .tsbuildinfo file from the cache.
+ fn get_tsbuildinfo(&self, specifier: &ModuleSpecifier) -> Option<String>;
+ /// Sets the .tsbuildinfo file in the cache.
+ fn set_tsbuildinfo(
+ &self,
+ specifier: ModuleSpecifier,
+ text: String,
+ ) -> Result<(), AnyError>;
+}
+
+impl<T: Cacher> EmitCache for T {
+ fn get_emit_data(
+ &self,
+ specifier: &ModuleSpecifier,
+ ) -> Option<SpecifierEmitCacheData> {
+ Some(SpecifierEmitCacheData {
+ source_hash: self.get_source_hash(specifier)?,
+ text: self.get_emit_text(specifier)?,
+ map: self.get(CacheType::SourceMap, specifier),
+ })
+ }
+
+ fn get_source_hash(&self, specifier: &ModuleSpecifier) -> Option<String> {
+ self.get(CacheType::Version, specifier)
+ }
+
+ fn get_emit_text(&self, specifier: &ModuleSpecifier) -> Option<String> {
+ self.get(CacheType::Emit, specifier)
+ }
+
+ fn set_emit_data(
+ &self,
+ specifier: ModuleSpecifier,
+ data: SpecifierEmitCacheData,
+ ) -> Result<(), AnyError> {
+ self.set(CacheType::Version, &specifier, data.source_hash)?;
+ self.set(CacheType::Emit, &specifier, data.text)?;
+ if let Some(map) = data.map {
+ self.set(CacheType::SourceMap, &specifier, map)?;
+ }
+ Ok(())
+ }
+
+ fn get_tsbuildinfo(&self, specifier: &ModuleSpecifier) -> Option<String> {
+ self.get(CacheType::TypeScriptBuildInfo, specifier)
+ }
+
+ fn set_tsbuildinfo(
+ &self,
+ specifier: ModuleSpecifier,
+ text: String,
+ ) -> Result<(), AnyError> {
+ self.set(CacheType::TypeScriptBuildInfo, &specifier, text)
+ }
+}
+
/// Represents the "default" type library that should be used when type
/// checking the code in the module graph. Note that a user provided config
/// of `"lib"` would override this value.
@@ -325,7 +409,7 @@ pub struct CheckEmitResult {
pub fn check_and_maybe_emit(
roots: &[(ModuleSpecifier, ModuleKind)],
graph_data: Arc<RwLock<GraphData>>,
- cache: &mut dyn Cacher,
+ cache: &dyn EmitCache,
options: CheckOptions,
) -> Result<CheckEmitResult, AnyError> {
let check_js = options.ts_config.get_check_js();
@@ -358,7 +442,7 @@ pub fn check_and_maybe_emit(
let maybe_tsbuildinfo = if options.reload {
None
} else {
- cache.get(CacheType::TypeScriptBuildInfo, &roots[0].0)
+ cache.get_tsbuildinfo(&roots[0].0)
};
// to make tsc build info work, we need to consistently hash modules, so that
// tsc can better determine if an emit is still valid or not, so we provide
@@ -400,9 +484,29 @@ pub fn check_and_maybe_emit(
// while we retrieve the build info for just the first module, it can be
// used for all the roots in the graph, so we will cache it for all roots
for (root, _) in roots {
- cache.set(CacheType::TypeScriptBuildInfo, root, info.clone())?;
+ cache.set_tsbuildinfo(root.clone(), info.to_string())?;
+ }
+ }
+
+ struct SpecifierEmitData {
+ pub version_hash: String,
+ pub text: Option<String>,
+ pub map: Option<String>,
+ }
+
+ impl SpecifierEmitData {
+ fn into_cache_data(self) -> Option<SpecifierEmitCacheData> {
+ self.text.map(|text| SpecifierEmitCacheData {
+ source_hash: self.version_hash,
+ text,
+ map: self.map,
+ })
}
}
+
+ // combine the emitted files into groups based on their specifier and media type
+ let mut emit_data_items: HashMap<ModuleSpecifier, SpecifierEmitData> =
+ HashMap::with_capacity(response.emitted_files.len());
for emit in response.emitted_files.into_iter() {
if let Some(specifiers) = emit.maybe_specifiers {
assert!(specifiers.len() == 1);
@@ -437,14 +541,21 @@ pub fn check_and_maybe_emit(
log::debug!("skipping emit for {}", specifier);
continue;
}
+
+ let mut emit_data_item = emit_data_items
+ .entry(specifier.clone())
+ .or_insert_with(|| SpecifierEmitData {
+ version_hash: get_version(source_bytes, &config_bytes),
+ text: None,
+ map: None,
+ });
+
match emit.media_type {
MediaType::JavaScript | MediaType::Mjs | MediaType::Cjs => {
- let version = get_version(source_bytes, &config_bytes);
- cache.set(CacheType::Version, &specifier, version)?;
- cache.set(CacheType::Emit, &specifier, emit.data)?;
+ emit_data_item.text = Some(emit.data);
}
MediaType::SourceMap => {
- cache.set(CacheType::SourceMap, &specifier, emit.data)?;
+ emit_data_item.map = Some(emit.data);
}
_ => unreachable!(
"unexpected media_type {} {}",
@@ -453,6 +564,13 @@ pub fn check_and_maybe_emit(
}
}
}
+
+ // now insert these items into the cache
+ for (specifier, data) in emit_data_items.into_iter() {
+ if let Some(cache_data) = data.into_cache_data() {
+ cache.set_emit_data(specifier, cache_data)?;
+ }
+ }
}
Ok(CheckEmitResult {
@@ -472,7 +590,7 @@ pub struct EmitOptions {
// `check_and_maybe_emit()`, but the AST isn't stored in that. Cleanup.
pub fn emit(
graph: &ModuleGraph,
- cache: &mut dyn Cacher,
+ cache: &dyn EmitCache,
options: EmitOptions,
) -> Result<CheckEmitResult, AnyError> {
let start = Instant::now();
@@ -493,15 +611,9 @@ pub fn emit(
module.maybe_source.as_ref().map(|s| s.as_bytes()).unwrap(),
&config_bytes,
);
- let is_valid =
- cache
- .get(CacheType::Version, &module.specifier)
- .map_or(false, |v| {
- v == get_version(
- module.maybe_source.as_ref().map(|s| s.as_bytes()).unwrap(),
- &config_bytes,
- )
- });
+ let is_valid = cache
+ .get_source_hash(&module.specifier)
+ .map_or(false, |v| v == version);
if is_valid && !needs_reload {
continue;
}
@@ -511,13 +623,14 @@ pub fn emit(
.map(|ps| ps.transpile(&emit_options))
.unwrap()?;
emit_count += 1;
- cache.set(CacheType::Emit, &module.specifier, transpiled_source.text)?;
- if let Some(map) = transpiled_source.source_map {
- cache.set(CacheType::SourceMap, &module.specifier, map)?;
- }
- if !is_valid {
- cache.set(CacheType::Version, &module.specifier, version)?;
- }
+ cache.set_emit_data(
+ module.specifier.clone(),
+ SpecifierEmitCacheData {
+ source_hash: version,
+ text: transpiled_source.text,
+ map: transpiled_source.source_map,
+ },
+ )?;
}
let stats = Stats(vec![
@@ -538,7 +651,7 @@ pub fn emit(
/// a valid emit in the cache.
fn valid_emit(
graph_data: &GraphData,
- cache: &dyn Cacher,
+ cache: &dyn EmitCache,
ts_config: &TsConfig,
reload: bool,
reload_exclusions: &HashSet<ModuleSpecifier>,
@@ -564,13 +677,20 @@ fn valid_emit(
continue;
}
}
- _ => continue,
+ MediaType::Json
+ | MediaType::TsBuildInfo
+ | MediaType::SourceMap
+ | MediaType::Dts
+ | MediaType::Dmts
+ | MediaType::Dcts
+ | MediaType::Wasm
+ | MediaType::Unknown => continue,
}
if reload && !reload_exclusions.contains(specifier) {
return false;
}
- if let Some(version) = cache.get(CacheType::Version, specifier) {
- if version != get_version(code.as_bytes(), &config_bytes) {
+ if let Some(source_hash) = cache.get_source_hash(specifier) {
+ if source_hash != get_version(code.as_bytes(), &config_bytes) {
return false;
}
} else {