summaryrefslogtreecommitdiff
path: root/cli/tsc.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/tsc.rs')
-rw-r--r--cli/tsc.rs149
1 files changed, 149 insertions, 0 deletions
diff --git a/cli/tsc.rs b/cli/tsc.rs
index 9f8216e52..2a1307432 100644
--- a/cli/tsc.rs
+++ b/cli/tsc.rs
@@ -302,6 +302,13 @@ impl CompiledFileMetadata {
}
}
+#[derive(Serialize, Debug)]
+#[serde(rename_all = "camelCase")]
+struct TranspileSourceFile {
+ pub source_code: String,
+ pub file_name: String,
+}
+
/// Emit a SHA256 hash based on source code, deno version and TS config.
/// Used to check if a recompilation for source code is needed.
fn source_code_version_hash(
@@ -376,6 +383,13 @@ struct CompileResponse {
build_info: Option<String>,
stats: Option<Vec<Stat>>,
}
+#[derive(Deserialize)]
+#[serde(rename_all = "camelCase")]
+struct TranspileResponse {
+ diagnostics: Diagnostic,
+ emit_map: HashMap<String, EmittedSource>,
+ stats: Option<Vec<Stat>>,
+}
// TODO(bartlomieju): possible deduplicate once TS refactor is stabilized
#[derive(Deserialize)]
@@ -704,6 +718,72 @@ impl TsCompiler {
Ok(output)
}
+ pub async fn transpile(
+ &self,
+ global_state: GlobalState,
+ permissions: Permissions,
+ module_graph: ModuleGraph,
+ ) -> Result<(), ErrBox> {
+ let mut source_files: Vec<TranspileSourceFile> = Vec::new();
+ for (_, value) in module_graph.iter() {
+ let url = Url::parse(&value.url).expect("Filename is not a valid url");
+ if !value.url.ends_with(".d.ts")
+ && (!self.use_disk_cache || !self.has_compiled_source(&url))
+ {
+ source_files.push(TranspileSourceFile {
+ source_code: value.source_code.clone(),
+ file_name: value.url.clone(),
+ });
+ }
+ }
+ if source_files.is_empty() {
+ return Ok(());
+ }
+
+ let source_files_json =
+ serde_json::to_value(source_files).expect("Filed to serialize data");
+ let compiler_config = self.config.clone();
+ let cwd = std::env::current_dir().unwrap();
+ let performance = match global_state.flags.log_level {
+ Some(Level::Debug) => true,
+ _ => false,
+ };
+ let j = match (compiler_config.path, compiler_config.content) {
+ (Some(config_path), Some(config_data)) => json!({
+ "config": str::from_utf8(&config_data).unwrap(),
+ "configPath": config_path,
+ "cwd": cwd,
+ "performance": performance,
+ "sourceFiles": source_files_json,
+ "type": msg::CompilerRequestType::Transpile,
+ }),
+ _ => json!({
+ "performance": performance,
+ "sourceFiles": source_files_json,
+ "type": msg::CompilerRequestType::Transpile,
+ }),
+ };
+
+ let req_msg = j.to_string().into_boxed_str().into_boxed_bytes();
+
+ let msg =
+ execute_in_same_thread(global_state.clone(), permissions, req_msg)
+ .await?;
+
+ let json_str = std::str::from_utf8(&msg).unwrap();
+
+ let transpile_response: TranspileResponse = serde_json::from_str(json_str)?;
+
+ if !transpile_response.diagnostics.items.is_empty() {
+ return Err(ErrBox::from(transpile_response.diagnostics));
+ }
+
+ maybe_log_stats(transpile_response.stats);
+
+ self.cache_emitted_files(transpile_response.emit_map)?;
+ Ok(())
+ }
+
/// Get associated `CompiledFileMetadata` for given module if it exists.
fn get_metadata(&self, url: &Url) -> Option<CompiledFileMetadata> {
// Try to load cached version:
@@ -1575,6 +1655,75 @@ mod tests {
}
#[tokio::test]
+ async fn test_transpile() {
+ let p = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
+ .parent()
+ .unwrap()
+ .join("cli/tests/002_hello.ts");
+ let specifier =
+ ModuleSpecifier::resolve_url_or_path(p.to_str().unwrap()).unwrap();
+ let out = SourceFile {
+ url: specifier.as_url().clone(),
+ filename: PathBuf::from(p.to_str().unwrap().to_string()),
+ media_type: msg::MediaType::TypeScript,
+ source_code: include_bytes!("./tests/002_hello.ts").to_vec(),
+ types_header: None,
+ };
+ let dir =
+ deno_dir::DenoDir::new(Some(test_util::new_deno_dir().path().to_owned()))
+ .unwrap();
+ let http_cache = http_cache::HttpCache::new(&dir.root.join("deps"));
+ let mock_state = GlobalState::mock(
+ vec![String::from("deno"), String::from("hello.ts")],
+ None,
+ );
+ let file_fetcher = SourceFileFetcher::new(
+ http_cache,
+ true,
+ mock_state.flags.cache_blocklist.clone(),
+ false,
+ false,
+ None,
+ )
+ .unwrap();
+
+ let mut module_graph_loader = ModuleGraphLoader::new(
+ file_fetcher.clone(),
+ None,
+ Permissions::allow_all(),
+ false,
+ false,
+ );
+ module_graph_loader
+ .add_to_graph(&specifier, None)
+ .await
+ .expect("Failed to create graph");
+ let module_graph = module_graph_loader.get_graph();
+
+ let ts_compiler = TsCompiler::new(
+ file_fetcher,
+ mock_state.flags.clone(),
+ dir.gen_cache.clone(),
+ )
+ .unwrap();
+
+ let result = ts_compiler
+ .transpile(mock_state.clone(), Permissions::allow_all(), module_graph)
+ .await;
+ assert!(result.is_ok());
+ let compiled_file = ts_compiler.get_compiled_module(&out.url).unwrap();
+ let source_code = compiled_file.code;
+ assert!(source_code
+ .as_bytes()
+ .starts_with(b"console.log(\"Hello World\");"));
+ let mut lines: Vec<String> =
+ source_code.split('\n').map(|s| s.to_string()).collect();
+ let last_line = lines.pop().unwrap();
+ assert!(last_line
+ .starts_with("//# sourceMappingURL=data:application/json;base64"));
+ }
+
+ #[tokio::test]
async fn test_bundle() {
let p = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()