summaryrefslogtreecommitdiff
path: root/cli/emit.rs
diff options
context:
space:
mode:
authorDavid Sherret <dsherret@users.noreply.github.com>2022-07-19 11:58:18 -0400
committerGitHub <noreply@github.com>2022-07-19 11:58:18 -0400
commit0ab262b901348e9251262a02bef17d14ed13b997 (patch)
treefc5a6e3926ea7480714cbc844098eca6c43c1ab5 /cli/emit.rs
parente99d64acedb6e111d33f53599da494865978f1aa (diff)
feat: emit files on demand and fix racy emit (#15220)
Diffstat (limited to 'cli/emit.rs')
-rw-r--r--cli/emit.rs154
1 files changed, 26 insertions, 128 deletions
diff --git a/cli/emit.rs b/cli/emit.rs
index 584593869..1d8ecca43 100644
--- a/cli/emit.rs
+++ b/cli/emit.rs
@@ -10,7 +10,7 @@ use crate::args::EmitConfigOptions;
use crate::args::TsConfig;
use crate::args::TypeCheckMode;
use crate::cache::EmitCache;
-use crate::cache::SpecifierEmitCacheData;
+use crate::cache::FastInsecureHasher;
use crate::cache::TypeCheckCache;
use crate::colors;
use crate::diagnostics::Diagnostics;
@@ -22,6 +22,7 @@ use crate::version;
use deno_ast::swc::bundler::Hook;
use deno_ast::swc::bundler::ModuleRecord;
use deno_ast::swc::common::Span;
+use deno_ast::ParsedSource;
use deno_core::error::AnyError;
use deno_core::parking_lot::RwLock;
use deno_core::serde::Deserialize;
@@ -32,14 +33,11 @@ use deno_core::serde_json;
use deno_core::serde_json::json;
use deno_core::ModuleSpecifier;
use deno_graph::MediaType;
-use deno_graph::ModuleGraph;
use deno_graph::ModuleGraphError;
use deno_graph::ModuleKind;
use deno_graph::ResolutionError;
-use std::collections::HashSet;
use std::fmt;
use std::sync::Arc;
-use std::time::Instant;
/// A structure representing stats from an emit operation for a graph.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
@@ -116,8 +114,8 @@ pub enum TsConfigType {
/// Return a configuration for bundling, using swc to emit the bundle. This is
/// independent of type checking.
Bundle,
- /// Return a configuration to use tsc to type check and optionally emit. This
- /// is independent of either bundling or just emitting via swc
+ /// Return a configuration to use tsc to type check. This
+ /// is independent of either bundling or emitting via swc.
Check { lib: TsTypeLib },
/// Return a configuration to use swc to emit single module files.
Emit,
@@ -234,31 +232,30 @@ fn get_tsc_roots(
/// A hashing function that takes the source code, version and optionally a
/// user provided config and generates a string hash which can be stored to
/// determine if the cached emit is valid or not.
-fn get_version(source_bytes: &[u8], config_bytes: &[u8]) -> String {
- crate::checksum::gen(&[
- source_bytes,
- version::deno().as_bytes(),
- config_bytes,
- ])
+pub fn get_source_hash(source_text: &str, emit_options_hash: u64) -> u64 {
+ FastInsecureHasher::new()
+ .write_str(source_text)
+ .write_u64(emit_options_hash)
+ .finish()
}
-/// Determine if a given module kind and media type is emittable or not.
-pub fn is_emittable(
- kind: &ModuleKind,
- media_type: &MediaType,
- include_js: bool,
-) -> bool {
- if matches!(kind, ModuleKind::Synthetic) {
- return false;
- }
- match &media_type {
- MediaType::TypeScript
- | MediaType::Mts
- | MediaType::Cts
- | MediaType::Tsx
- | MediaType::Jsx => true,
- MediaType::JavaScript | MediaType::Mjs | MediaType::Cjs => include_js,
- _ => false,
+pub fn emit_parsed_source(
+ cache: &EmitCache,
+ specifier: &ModuleSpecifier,
+ parsed_source: &ParsedSource,
+ emit_options: &deno_ast::EmitOptions,
+ emit_config_hash: u64,
+) -> Result<String, AnyError> {
+ let source_hash =
+ get_source_hash(parsed_source.text_info().text_str(), emit_config_hash);
+
+ if let Some(emit_code) = cache.get_emit_code(specifier, source_hash) {
+ Ok(emit_code)
+ } else {
+ let transpiled_source = parsed_source.transpile(emit_options)?;
+ debug_assert!(transpiled_source.source_map.is_none());
+ cache.set_emit_code(specifier, source_hash, &transpiled_source.text);
+ Ok(transpiled_source.text)
}
}
@@ -376,72 +373,6 @@ pub fn check(
})
}
-pub struct EmitOptions {
- pub ts_config: TsConfig,
- pub reload: bool,
- pub reload_exclusions: HashSet<ModuleSpecifier>,
-}
-
-/// Given a module graph, emit any appropriate modules and cache them.
-// TODO(nayeemrmn): This would ideally take `GraphData` like
-// `check()`, but the AST isn't stored in that. Cleanup.
-pub fn emit(
- graph: &ModuleGraph,
- cache: &dyn EmitCache,
- options: EmitOptions,
-) -> Result<CheckResult, AnyError> {
- let start = Instant::now();
- let config_bytes = options.ts_config.as_bytes();
- let include_js = options.ts_config.get_check_js();
- let emit_options = options.ts_config.into();
-
- let mut emit_count = 0_u32;
- let mut file_count = 0_u32;
- for module in graph.modules() {
- file_count += 1;
- if !is_emittable(&module.kind, &module.media_type, include_js) {
- continue;
- }
- let needs_reload =
- options.reload && !options.reload_exclusions.contains(&module.specifier);
- let version = 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;
- }
- let transpiled_source = module
- .maybe_parsed_source
- .as_ref()
- .map(|source| source.transpile(&emit_options))
- .unwrap()?;
- emit_count += 1;
- cache.set_emit_data(
- module.specifier.clone(),
- SpecifierEmitCacheData {
- source_hash: version,
- text: transpiled_source.text,
- map: transpiled_source.source_map,
- },
- )?;
- }
-
- let stats = Stats(vec![
- ("Files".to_string(), file_count),
- ("Emitted".to_string(), emit_count),
- ("Total time".to_string(), start.elapsed().as_millis() as u32),
- ]);
-
- Ok(CheckResult {
- diagnostics: Diagnostics::default(),
- stats,
- })
-}
-
enum CheckHashResult {
Hash(u64),
NoFiles,
@@ -624,36 +555,3 @@ impl From<TsConfig> for deno_ast::EmitOptions {
}
}
}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn test_is_emittable() {
- assert!(is_emittable(
- &ModuleKind::Esm,
- &MediaType::TypeScript,
- false
- ));
- assert!(!is_emittable(
- &ModuleKind::Synthetic,
- &MediaType::TypeScript,
- false
- ));
- assert!(!is_emittable(&ModuleKind::Esm, &MediaType::Dts, false));
- assert!(!is_emittable(&ModuleKind::Esm, &MediaType::Dcts, false));
- assert!(!is_emittable(&ModuleKind::Esm, &MediaType::Dmts, false));
- assert!(is_emittable(&ModuleKind::Esm, &MediaType::Tsx, false));
- assert!(!is_emittable(
- &ModuleKind::Esm,
- &MediaType::JavaScript,
- false
- ));
- assert!(!is_emittable(&ModuleKind::Esm, &MediaType::Cjs, false));
- assert!(!is_emittable(&ModuleKind::Esm, &MediaType::Mjs, false));
- assert!(is_emittable(&ModuleKind::Esm, &MediaType::JavaScript, true));
- assert!(is_emittable(&ModuleKind::Esm, &MediaType::Jsx, false));
- assert!(!is_emittable(&ModuleKind::Esm, &MediaType::Json, false));
- }
-}