mirror of
https://github.com/denoland/deno.git
synced 2025-02-01 12:16:11 -05:00
perf: use emit from swc instead of tsc (#15118)
This commit is contained in:
parent
7610764980
commit
0c87dd1e98
28 changed files with 664 additions and 525 deletions
215
cli/cache/check.rs
vendored
Normal file
215
cli/cache/check.rs
vendored
Normal file
|
@ -0,0 +1,215 @@
|
||||||
|
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use deno_ast::ModuleSpecifier;
|
||||||
|
use deno_core::anyhow::Context;
|
||||||
|
use deno_core::error::AnyError;
|
||||||
|
use deno_runtime::deno_webstorage::rusqlite::params;
|
||||||
|
use deno_runtime::deno_webstorage::rusqlite::Connection;
|
||||||
|
|
||||||
|
use super::common::run_sqlite_pragma;
|
||||||
|
|
||||||
|
/// The cache used to tell whether type checking should occur again.
|
||||||
|
///
|
||||||
|
/// This simply stores a hash of the inputs of each successful type check
|
||||||
|
/// and only clears them out when changing CLI versions.
|
||||||
|
pub struct TypeCheckCache {
|
||||||
|
conn: Connection,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeCheckCache {
|
||||||
|
pub fn new(db_file_path: &Path) -> Result<Self, AnyError> {
|
||||||
|
let conn = Connection::open(db_file_path).with_context(|| {
|
||||||
|
format!(
|
||||||
|
concat!(
|
||||||
|
"Error opening type checking cache at {} -- ",
|
||||||
|
"Perhaps it's corrupt. Maybe try deleting it."
|
||||||
|
),
|
||||||
|
db_file_path.display()
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
Self::from_connection(conn, crate::version::deno())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_connection(
|
||||||
|
conn: Connection,
|
||||||
|
cli_version: String,
|
||||||
|
) -> Result<Self, AnyError> {
|
||||||
|
run_sqlite_pragma(&conn)?;
|
||||||
|
create_tables(&conn, cli_version)?;
|
||||||
|
|
||||||
|
Ok(Self { conn })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_check_hash(&self, hash: u64) -> bool {
|
||||||
|
match self.hash_check_hash_result(hash) {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(err) => {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
panic!("Error retrieving hash: {}", err);
|
||||||
|
} else {
|
||||||
|
log::debug!("Error retrieving hash: {}", err);
|
||||||
|
// fail silently when not debugging
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hash_check_hash_result(&self, hash: u64) -> Result<bool, AnyError> {
|
||||||
|
let query = "SELECT * FROM checkcache WHERE check_hash=?1 LIMIT 1";
|
||||||
|
let mut stmt = self.conn.prepare_cached(query)?;
|
||||||
|
Ok(stmt.exists(params![hash.to_string()])?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_check_hash(&self, check_hash: u64) {
|
||||||
|
if let Err(err) = self.add_check_hash_result(check_hash) {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
panic!("Error saving check hash: {}", err);
|
||||||
|
} else {
|
||||||
|
log::debug!("Error saving check hash: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_check_hash_result(&self, check_hash: u64) -> Result<(), AnyError> {
|
||||||
|
let sql = "
|
||||||
|
INSERT OR REPLACE INTO
|
||||||
|
checkcache (check_hash)
|
||||||
|
VALUES
|
||||||
|
(?1)";
|
||||||
|
let mut stmt = self.conn.prepare_cached(sql)?;
|
||||||
|
stmt.execute(params![&check_hash.to_string(),])?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_tsbuildinfo(&self, specifier: &ModuleSpecifier) -> Option<String> {
|
||||||
|
let mut stmt = self
|
||||||
|
.conn
|
||||||
|
.prepare_cached("SELECT text FROM tsbuildinfo WHERE specifier=?1 LIMIT 1")
|
||||||
|
.ok()?;
|
||||||
|
let mut rows = stmt.query(params![specifier.to_string()]).ok()?;
|
||||||
|
let row = rows.next().ok().flatten()?;
|
||||||
|
|
||||||
|
row.get(0).ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_tsbuildinfo(&self, specifier: &ModuleSpecifier, text: &str) {
|
||||||
|
if let Err(err) = self.set_tsbuildinfo_result(specifier, text) {
|
||||||
|
// should never error here, but if it ever does don't fail
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
panic!("Error saving tsbuildinfo: {}", err);
|
||||||
|
} else {
|
||||||
|
log::debug!("Error saving tsbuildinfo: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_tsbuildinfo_result(
|
||||||
|
&self,
|
||||||
|
specifier: &ModuleSpecifier,
|
||||||
|
text: &str,
|
||||||
|
) -> Result<(), AnyError> {
|
||||||
|
let mut stmt = self.conn.prepare_cached(
|
||||||
|
"INSERT OR REPLACE INTO tsbuildinfo (specifier, text) VALUES (?1, ?2)",
|
||||||
|
)?;
|
||||||
|
stmt.execute(params![specifier.to_string(), text])?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_tables(
|
||||||
|
conn: &Connection,
|
||||||
|
cli_version: String,
|
||||||
|
) -> Result<(), AnyError> {
|
||||||
|
// INT doesn't store up to u64, so use TEXT
|
||||||
|
conn.execute(
|
||||||
|
"CREATE TABLE IF NOT EXISTS checkcache (
|
||||||
|
check_hash TEXT PRIMARY KEY
|
||||||
|
)",
|
||||||
|
[],
|
||||||
|
)?;
|
||||||
|
conn.execute(
|
||||||
|
"CREATE TABLE IF NOT EXISTS tsbuildinfo (
|
||||||
|
specifier TEXT PRIMARY KEY,
|
||||||
|
text TEXT NOT NULL
|
||||||
|
)",
|
||||||
|
[],
|
||||||
|
)?;
|
||||||
|
conn.execute(
|
||||||
|
"CREATE TABLE IF NOT EXISTS info (
|
||||||
|
key TEXT PRIMARY KEY,
|
||||||
|
value TEXT NOT NULL
|
||||||
|
)",
|
||||||
|
[],
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// delete the cache when the CLI version changes
|
||||||
|
let data_cli_version: Option<String> = conn
|
||||||
|
.query_row(
|
||||||
|
"SELECT value FROM info WHERE key='CLI_VERSION' LIMIT 1",
|
||||||
|
[],
|
||||||
|
|row| row.get(0),
|
||||||
|
)
|
||||||
|
.ok();
|
||||||
|
if data_cli_version != Some(cli_version.to_string()) {
|
||||||
|
conn.execute("DELETE FROM checkcache", params![])?;
|
||||||
|
conn.execute("DELETE FROM tsbuildinfo", params![])?;
|
||||||
|
let mut stmt = conn
|
||||||
|
.prepare("INSERT OR REPLACE INTO info (key, value) VALUES (?1, ?2)")?;
|
||||||
|
stmt.execute(params!["CLI_VERSION", &cli_version])?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn check_cache_general_use() {
|
||||||
|
let conn = Connection::open_in_memory().unwrap();
|
||||||
|
let cache =
|
||||||
|
TypeCheckCache::from_connection(conn, "1.0.0".to_string()).unwrap();
|
||||||
|
|
||||||
|
assert!(!cache.has_check_hash(1));
|
||||||
|
cache.add_check_hash(1);
|
||||||
|
assert!(cache.has_check_hash(1));
|
||||||
|
assert!(!cache.has_check_hash(2));
|
||||||
|
|
||||||
|
let specifier1 = ModuleSpecifier::parse("file:///test.json").unwrap();
|
||||||
|
assert_eq!(cache.get_tsbuildinfo(&specifier1), None);
|
||||||
|
cache.set_tsbuildinfo(&specifier1, "test");
|
||||||
|
assert_eq!(cache.get_tsbuildinfo(&specifier1), Some("test".to_string()));
|
||||||
|
|
||||||
|
// try changing the cli version (should clear)
|
||||||
|
let conn = cache.conn;
|
||||||
|
let cache =
|
||||||
|
TypeCheckCache::from_connection(conn, "2.0.0".to_string()).unwrap();
|
||||||
|
assert!(!cache.has_check_hash(1));
|
||||||
|
cache.add_check_hash(1);
|
||||||
|
assert!(cache.has_check_hash(1));
|
||||||
|
assert_eq!(cache.get_tsbuildinfo(&specifier1), None);
|
||||||
|
cache.set_tsbuildinfo(&specifier1, "test");
|
||||||
|
assert_eq!(cache.get_tsbuildinfo(&specifier1), Some("test".to_string()));
|
||||||
|
|
||||||
|
// recreating the cache should not remove the data because the CLI version and state hash is the same
|
||||||
|
let conn = cache.conn;
|
||||||
|
let cache =
|
||||||
|
TypeCheckCache::from_connection(conn, "2.0.0".to_string()).unwrap();
|
||||||
|
assert!(cache.has_check_hash(1));
|
||||||
|
assert!(!cache.has_check_hash(2));
|
||||||
|
assert_eq!(cache.get_tsbuildinfo(&specifier1), Some("test".to_string()));
|
||||||
|
|
||||||
|
// adding when already exists should not cause issue
|
||||||
|
cache.add_check_hash(1);
|
||||||
|
assert!(cache.has_check_hash(1));
|
||||||
|
cache.set_tsbuildinfo(&specifier1, "other");
|
||||||
|
assert_eq!(
|
||||||
|
cache.get_tsbuildinfo(&specifier1),
|
||||||
|
Some("other".to_string())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
31
cli/cache/common.rs
vendored
Normal file
31
cli/cache/common.rs
vendored
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
use deno_core::error::AnyError;
|
||||||
|
use deno_runtime::deno_webstorage::rusqlite::Connection;
|
||||||
|
|
||||||
|
/// Very fast non-cryptographically secure hash.
|
||||||
|
pub fn fast_insecure_hash(bytes: &[u8]) -> u64 {
|
||||||
|
use std::hash::Hasher;
|
||||||
|
use twox_hash::XxHash64;
|
||||||
|
|
||||||
|
let mut hasher = XxHash64::default();
|
||||||
|
hasher.write(bytes);
|
||||||
|
hasher.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Runs the common sqlite pragma.
|
||||||
|
pub fn run_sqlite_pragma(conn: &Connection) -> Result<(), AnyError> {
|
||||||
|
// Enable write-ahead-logging and tweak some other stuff
|
||||||
|
let initial_pragmas = "
|
||||||
|
-- enable write-ahead-logging mode
|
||||||
|
PRAGMA journal_mode=WAL;
|
||||||
|
PRAGMA synchronous=NORMAL;
|
||||||
|
PRAGMA temp_store=memory;
|
||||||
|
PRAGMA page_size=4096;
|
||||||
|
PRAGMA mmap_size=6000000;
|
||||||
|
PRAGMA optimize;
|
||||||
|
";
|
||||||
|
|
||||||
|
conn.execute_batch(initial_pragmas)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
13
cli/disk_cache.rs → cli/cache/disk_cache.rs
vendored
13
cli/disk_cache.rs → cli/cache/disk_cache.rs
vendored
|
@ -1,14 +1,17 @@
|
||||||
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use crate::cache::CacheType;
|
|
||||||
use crate::cache::Cacher;
|
|
||||||
use crate::cache::EmitMetadata;
|
|
||||||
use crate::fs_util;
|
use crate::fs_util;
|
||||||
use crate::http_cache::url_to_filename;
|
use crate::http_cache::url_to_filename;
|
||||||
|
|
||||||
|
use super::CacheType;
|
||||||
|
use super::Cacher;
|
||||||
|
use super::EmitMetadata;
|
||||||
|
|
||||||
use deno_ast::ModuleSpecifier;
|
use deno_ast::ModuleSpecifier;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::serde_json;
|
use deno_core::serde_json;
|
||||||
use deno_core::url::{Host, Url};
|
use deno_core::url::Host;
|
||||||
|
use deno_core::url::Url;
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
@ -184,7 +187,6 @@ impl Cacher for DiskCache {
|
||||||
let extension = match cache_type {
|
let extension = match cache_type {
|
||||||
CacheType::Emit => "js",
|
CacheType::Emit => "js",
|
||||||
CacheType::SourceMap => "js.map",
|
CacheType::SourceMap => "js.map",
|
||||||
CacheType::TypeScriptBuildInfo => "buildinfo",
|
|
||||||
CacheType::Version => {
|
CacheType::Version => {
|
||||||
return self.get_emit_metadata(specifier).map(|d| d.version_hash)
|
return self.get_emit_metadata(specifier).map(|d| d.version_hash)
|
||||||
}
|
}
|
||||||
|
@ -206,7 +208,6 @@ impl Cacher for DiskCache {
|
||||||
let extension = match cache_type {
|
let extension = match cache_type {
|
||||||
CacheType::Emit => "js",
|
CacheType::Emit => "js",
|
||||||
CacheType::SourceMap => "js.map",
|
CacheType::SourceMap => "js.map",
|
||||||
CacheType::TypeScriptBuildInfo => "buildinfo",
|
|
||||||
CacheType::Version => {
|
CacheType::Version => {
|
||||||
let data = if let Some(mut data) = self.get_emit_metadata(specifier) {
|
let data = if let Some(mut data) = self.get_emit_metadata(specifier) {
|
||||||
data.version_hash = value;
|
data.version_hash = value;
|
71
cli/cache/emit.rs
vendored
Normal file
71
cli/cache/emit.rs
vendored
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
use deno_ast::ModuleSpecifier;
|
||||||
|
use deno_core::error::AnyError;
|
||||||
|
|
||||||
|
use super::CacheType;
|
||||||
|
use super::Cacher;
|
||||||
|
|
||||||
|
/// 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>;
|
||||||
|
/// Sets the emit data in the cache.
|
||||||
|
fn set_emit_data(
|
||||||
|
&self,
|
||||||
|
specifier: ModuleSpecifier,
|
||||||
|
data: SpecifierEmitCacheData,
|
||||||
|
) -> Result<(), AnyError>;
|
||||||
|
/// 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>;
|
||||||
|
}
|
||||||
|
|
||||||
|
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(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
@ -10,6 +12,9 @@ use deno_runtime::deno_webstorage::rusqlite::Connection;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
|
|
||||||
|
use super::common::fast_insecure_hash;
|
||||||
|
use super::common::run_sqlite_pragma;
|
||||||
|
|
||||||
/// Cache used to skip formatting/linting a file again when we
|
/// Cache used to skip formatting/linting a file again when we
|
||||||
/// know it is already formatted or has no lint diagnostics.
|
/// know it is already formatted or has no lint diagnostics.
|
||||||
pub struct IncrementalCache(Option<IncrementalCacheInner>);
|
pub struct IncrementalCache(Option<IncrementalCacheInner>);
|
||||||
|
@ -165,7 +170,7 @@ impl SqlIncrementalCache {
|
||||||
state_hash: u64,
|
state_hash: u64,
|
||||||
cli_version: String,
|
cli_version: String,
|
||||||
) -> Result<Self, AnyError> {
|
) -> Result<Self, AnyError> {
|
||||||
run_pragma(&conn)?;
|
run_sqlite_pragma(&conn)?;
|
||||||
create_tables(&conn, cli_version)?;
|
create_tables(&conn, cli_version)?;
|
||||||
|
|
||||||
Ok(Self { conn, state_hash })
|
Ok(Self { conn, state_hash })
|
||||||
|
@ -229,22 +234,6 @@ impl SqlIncrementalCache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_pragma(conn: &Connection) -> Result<(), AnyError> {
|
|
||||||
// Enable write-ahead-logging and tweak some other stuff
|
|
||||||
let initial_pragmas = "
|
|
||||||
-- enable write-ahead-logging mode
|
|
||||||
PRAGMA journal_mode=WAL;
|
|
||||||
PRAGMA synchronous=NORMAL;
|
|
||||||
PRAGMA temp_store=memory;
|
|
||||||
PRAGMA page_size=4096;
|
|
||||||
PRAGMA mmap_size=6000000;
|
|
||||||
PRAGMA optimize;
|
|
||||||
";
|
|
||||||
|
|
||||||
conn.execute_batch(initial_pragmas)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_tables(
|
fn create_tables(
|
||||||
conn: &Connection,
|
conn: &Connection,
|
||||||
cli_version: String,
|
cli_version: String,
|
||||||
|
@ -284,16 +273,6 @@ fn create_tables(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Very fast non-cryptographically secure hash.
|
|
||||||
fn fast_insecure_hash(bytes: &[u8]) -> u64 {
|
|
||||||
use std::hash::Hasher;
|
|
||||||
use twox_hash::XxHash64;
|
|
||||||
|
|
||||||
let mut hasher = XxHash64::default();
|
|
||||||
hasher.write(bytes);
|
|
||||||
hasher.finish()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
14
cli/cache.rs → cli/cache/mod.rs
vendored
14
cli/cache.rs → cli/cache/mod.rs
vendored
|
@ -1,6 +1,5 @@
|
||||||
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use crate::disk_cache::DiskCache;
|
|
||||||
use crate::errors::get_error_class_name;
|
use crate::errors::get_error_class_name;
|
||||||
use crate::file_fetcher::FileFetcher;
|
use crate::file_fetcher::FileFetcher;
|
||||||
|
|
||||||
|
@ -16,6 +15,18 @@ use deno_graph::source::Loader;
|
||||||
use deno_runtime::permissions::Permissions;
|
use deno_runtime::permissions::Permissions;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
mod check;
|
||||||
|
mod common;
|
||||||
|
mod disk_cache;
|
||||||
|
mod emit;
|
||||||
|
mod incremental;
|
||||||
|
|
||||||
|
pub use check::TypeCheckCache;
|
||||||
|
pub use disk_cache::DiskCache;
|
||||||
|
pub use emit::EmitCache;
|
||||||
|
pub use emit::SpecifierEmitCacheData;
|
||||||
|
pub use incremental::IncrementalCache;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
pub struct EmitMetadata {
|
pub struct EmitMetadata {
|
||||||
pub version_hash: String,
|
pub version_hash: String,
|
||||||
|
@ -24,7 +35,6 @@ pub struct EmitMetadata {
|
||||||
pub enum CacheType {
|
pub enum CacheType {
|
||||||
Emit,
|
Emit,
|
||||||
SourceMap,
|
SourceMap,
|
||||||
TypeScriptBuildInfo,
|
|
||||||
Version,
|
Version,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use crate::disk_cache::DiskCache;
|
use crate::cache::DiskCache;
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
/// `DenoDir` serves as coordinator for multiple `DiskCache`s containing them
|
/// `DenoDir` serves as coordinator for multiple `DiskCache`s containing them
|
||||||
|
@ -56,6 +57,12 @@ impl DenoDir {
|
||||||
// bump this version name to invalidate the entire cache
|
// bump this version name to invalidate the entire cache
|
||||||
self.root.join("lint_incremental_cache_v1")
|
self.root.join("lint_incremental_cache_v1")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Path for the incremental cache used for linting.
|
||||||
|
pub fn type_checking_cache_db_file_path(&self) -> PathBuf {
|
||||||
|
// bump this version name to invalidate the entire cache
|
||||||
|
self.root.join("check_cache_v1")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// To avoid the poorly managed dirs crate
|
/// To avoid the poorly managed dirs crate
|
||||||
|
|
331
cli/emit.rs
331
cli/emit.rs
|
@ -9,8 +9,9 @@ use crate::args::ConfigFile;
|
||||||
use crate::args::EmitConfigOptions;
|
use crate::args::EmitConfigOptions;
|
||||||
use crate::args::TsConfig;
|
use crate::args::TsConfig;
|
||||||
use crate::args::TypeCheckMode;
|
use crate::args::TypeCheckMode;
|
||||||
use crate::cache::CacheType;
|
use crate::cache::EmitCache;
|
||||||
use crate::cache::Cacher;
|
use crate::cache::SpecifierEmitCacheData;
|
||||||
|
use crate::cache::TypeCheckCache;
|
||||||
use crate::colors;
|
use crate::colors;
|
||||||
use crate::diagnostics::Diagnostics;
|
use crate::diagnostics::Diagnostics;
|
||||||
use crate::graph_util::GraphData;
|
use crate::graph_util::GraphData;
|
||||||
|
@ -35,97 +36,12 @@ use deno_graph::ModuleGraph;
|
||||||
use deno_graph::ModuleGraphError;
|
use deno_graph::ModuleGraphError;
|
||||||
use deno_graph::ModuleKind;
|
use deno_graph::ModuleKind;
|
||||||
use deno_graph::ResolutionError;
|
use deno_graph::ResolutionError;
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Instant;
|
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A structure representing stats from an emit operation for a graph.
|
/// A structure representing stats from an emit operation for a graph.
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||||
pub struct Stats(pub Vec<(String, u32)>);
|
pub struct Stats(pub Vec<(String, u32)>);
|
||||||
|
@ -236,13 +152,17 @@ pub fn get_ts_config_for_emit(
|
||||||
let mut ts_config = TsConfig::new(json!({
|
let mut ts_config = TsConfig::new(json!({
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"checkJs": false,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"incremental": true,
|
"incremental": true,
|
||||||
"jsx": "react",
|
"jsx": "react",
|
||||||
|
"jsxFactory": "React.createElement",
|
||||||
|
"jsxFragmentFactory": "React.Fragment",
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"lib": lib,
|
"lib": lib,
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
|
"sourceMap": false,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"tsBuildInfoFile": "deno:///.tsbuildinfo",
|
"tsBuildInfoFile": "deno:///.tsbuildinfo",
|
||||||
|
@ -378,10 +298,6 @@ pub struct CheckOptions {
|
||||||
pub type_check_mode: TypeCheckMode,
|
pub type_check_mode: TypeCheckMode,
|
||||||
/// Set the debug flag on the TypeScript type checker.
|
/// Set the debug flag on the TypeScript type checker.
|
||||||
pub debug: bool,
|
pub debug: bool,
|
||||||
/// If true, any files emitted will be cached, even if there are diagnostics
|
|
||||||
/// produced. If false, if there are diagnostics, caching emitted files will
|
|
||||||
/// be skipped.
|
|
||||||
pub emit_with_diagnostics: bool,
|
|
||||||
/// The module specifier to the configuration file, passed to tsc so that
|
/// The module specifier to the configuration file, passed to tsc so that
|
||||||
/// configuration related diagnostics are properly formed.
|
/// configuration related diagnostics are properly formed.
|
||||||
pub maybe_config_specifier: Option<ModuleSpecifier>,
|
pub maybe_config_specifier: Option<ModuleSpecifier>,
|
||||||
|
@ -389,46 +305,43 @@ pub struct CheckOptions {
|
||||||
pub ts_config: TsConfig,
|
pub ts_config: TsConfig,
|
||||||
/// If true, `Check <specifier>` will be written to stdout for each root.
|
/// If true, `Check <specifier>` will be written to stdout for each root.
|
||||||
pub log_checks: bool,
|
pub log_checks: bool,
|
||||||
/// If true, valid existing emits and `.tsbuildinfo` files will be ignored.
|
/// If true, valid `.tsbuildinfo` files will be ignored and type checking
|
||||||
|
/// will always occur.
|
||||||
pub reload: bool,
|
pub reload: bool,
|
||||||
pub reload_exclusions: HashSet<ModuleSpecifier>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The result of a check or emit of a module graph. Note that the actual
|
/// The result of a check of a module graph.
|
||||||
/// emitted sources are stored in the cache and are not returned in the result.
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct CheckEmitResult {
|
pub struct CheckResult {
|
||||||
pub diagnostics: Diagnostics,
|
pub diagnostics: Diagnostics,
|
||||||
pub stats: Stats,
|
pub stats: Stats,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a set of roots and graph data, type check the module graph and
|
/// Given a set of roots and graph data, type check the module graph.
|
||||||
/// optionally emit modules, updating the cache as appropriate. Emitting is
|
|
||||||
/// determined by the `ts_config` supplied in the options, and if emitting, the
|
|
||||||
/// files are stored in the cache.
|
|
||||||
///
|
///
|
||||||
/// It is expected that it is determined if a check and/or emit is validated
|
/// It is expected that it is determined if a check and/or emit is validated
|
||||||
/// before the function is called.
|
/// before the function is called.
|
||||||
pub fn check_and_maybe_emit(
|
pub fn check(
|
||||||
roots: &[(ModuleSpecifier, ModuleKind)],
|
roots: &[(ModuleSpecifier, ModuleKind)],
|
||||||
graph_data: Arc<RwLock<GraphData>>,
|
graph_data: Arc<RwLock<GraphData>>,
|
||||||
cache: &dyn EmitCache,
|
cache: &TypeCheckCache,
|
||||||
options: CheckOptions,
|
options: CheckOptions,
|
||||||
) -> Result<CheckEmitResult, AnyError> {
|
) -> Result<CheckResult, AnyError> {
|
||||||
let check_js = options.ts_config.get_check_js();
|
let check_js = options.ts_config.get_check_js();
|
||||||
let segment_graph_data = {
|
let segment_graph_data = {
|
||||||
let graph_data = graph_data.read();
|
let graph_data = graph_data.read();
|
||||||
graph_data.graph_segment(roots).unwrap()
|
graph_data.graph_segment(roots).unwrap()
|
||||||
};
|
};
|
||||||
if valid_emit(
|
let check_hash = match get_check_hash(&segment_graph_data, &options) {
|
||||||
&segment_graph_data,
|
CheckHashResult::NoFiles => return Ok(Default::default()),
|
||||||
cache,
|
CheckHashResult::Hash(hash) => hash,
|
||||||
&options.ts_config,
|
};
|
||||||
options.reload,
|
|
||||||
&options.reload_exclusions,
|
// do not type check if we know this is type checked
|
||||||
) {
|
if !options.reload && cache.has_check_hash(check_hash) {
|
||||||
return Ok(Default::default());
|
return Ok(Default::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
let root_names = get_tsc_roots(roots, &segment_graph_data, check_js);
|
let root_names = get_tsc_roots(roots, &segment_graph_data, check_js);
|
||||||
if options.log_checks {
|
if options.log_checks {
|
||||||
for (root, _) in roots {
|
for (root, _) in roots {
|
||||||
|
@ -454,12 +367,11 @@ pub fn check_and_maybe_emit(
|
||||||
options.ts_config.as_bytes(),
|
options.ts_config.as_bytes(),
|
||||||
version::deno().as_bytes().to_owned(),
|
version::deno().as_bytes().to_owned(),
|
||||||
];
|
];
|
||||||
let config_bytes = options.ts_config.as_bytes();
|
|
||||||
|
|
||||||
let response = tsc::exec(tsc::Request {
|
let response = tsc::exec(tsc::Request {
|
||||||
config: options.ts_config,
|
config: options.ts_config,
|
||||||
debug: options.debug,
|
debug: options.debug,
|
||||||
graph_data: graph_data.clone(),
|
graph_data,
|
||||||
hash_data,
|
hash_data,
|
||||||
maybe_config_specifier: options.maybe_config_specifier,
|
maybe_config_specifier: options.maybe_config_specifier,
|
||||||
maybe_tsbuildinfo,
|
maybe_tsbuildinfo,
|
||||||
|
@ -478,105 +390,15 @@ pub fn check_and_maybe_emit(
|
||||||
response.diagnostics
|
response.diagnostics
|
||||||
};
|
};
|
||||||
|
|
||||||
// sometimes we want to emit when there are diagnostics, and sometimes we
|
if let Some(tsbuildinfo) = response.maybe_tsbuildinfo {
|
||||||
// don't. tsc will always return an emit if there are diagnostics
|
cache.set_tsbuildinfo(&roots[0].0, &tsbuildinfo);
|
||||||
if (diagnostics.is_empty() || options.emit_with_diagnostics)
|
|
||||||
&& !response.emitted_files.is_empty()
|
|
||||||
{
|
|
||||||
if let Some(info) = &response.maybe_tsbuildinfo {
|
|
||||||
// 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_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);
|
|
||||||
// The emitted specifier might not be the file specifier we want, so we
|
|
||||||
// resolve it via the graph.
|
|
||||||
let graph_data = graph_data.read();
|
|
||||||
let specifier = graph_data.follow_redirect(&specifiers[0]);
|
|
||||||
let (source_bytes, media_type, ts_check) =
|
|
||||||
match graph_data.get(&specifier) {
|
|
||||||
Some(ModuleEntry::Module {
|
|
||||||
code,
|
|
||||||
media_type,
|
|
||||||
ts_check,
|
|
||||||
..
|
|
||||||
}) => (code.as_bytes(), *media_type, *ts_check),
|
|
||||||
_ => {
|
|
||||||
log::debug!("skipping emit for {}", specifier);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Sometimes if `tsc` sees a CommonJS file or a JSON module, it will
|
|
||||||
// _helpfully_ output it, which we don't really want to do unless
|
|
||||||
// someone has enabled check_js.
|
|
||||||
if matches!(media_type, MediaType::Json)
|
|
||||||
|| (!check_js
|
|
||||||
&& !ts_check
|
|
||||||
&& matches!(
|
|
||||||
media_type,
|
|
||||||
MediaType::JavaScript | MediaType::Cjs | MediaType::Mjs
|
|
||||||
))
|
|
||||||
{
|
|
||||||
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 => {
|
|
||||||
emit_data_item.text = Some(emit.data);
|
|
||||||
}
|
|
||||||
MediaType::SourceMap => {
|
|
||||||
emit_data_item.map = Some(emit.data);
|
|
||||||
}
|
|
||||||
_ => unreachable!(
|
|
||||||
"unexpected media_type {} {}",
|
|
||||||
emit.media_type, specifier
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 {
|
if diagnostics.is_empty() {
|
||||||
|
cache.add_check_hash(check_hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(CheckResult {
|
||||||
diagnostics,
|
diagnostics,
|
||||||
stats: response.stats,
|
stats: response.stats,
|
||||||
})
|
})
|
||||||
|
@ -590,12 +412,12 @@ pub struct EmitOptions {
|
||||||
|
|
||||||
/// Given a module graph, emit any appropriate modules and cache them.
|
/// Given a module graph, emit any appropriate modules and cache them.
|
||||||
// TODO(nayeemrmn): This would ideally take `GraphData` like
|
// TODO(nayeemrmn): This would ideally take `GraphData` like
|
||||||
// `check_and_maybe_emit()`, but the AST isn't stored in that. Cleanup.
|
// `check()`, but the AST isn't stored in that. Cleanup.
|
||||||
pub fn emit(
|
pub fn emit(
|
||||||
graph: &ModuleGraph,
|
graph: &ModuleGraph,
|
||||||
cache: &dyn EmitCache,
|
cache: &dyn EmitCache,
|
||||||
options: EmitOptions,
|
options: EmitOptions,
|
||||||
) -> Result<CheckEmitResult, AnyError> {
|
) -> Result<CheckResult, AnyError> {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let config_bytes = options.ts_config.as_bytes();
|
let config_bytes = options.ts_config.as_bytes();
|
||||||
let include_js = options.ts_config.get_check_js();
|
let include_js = options.ts_config.get_check_js();
|
||||||
|
@ -623,7 +445,7 @@ pub fn emit(
|
||||||
let transpiled_source = module
|
let transpiled_source = module
|
||||||
.maybe_parsed_source
|
.maybe_parsed_source
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|ps| ps.transpile(&emit_options))
|
.map(|source| source.transpile(&emit_options))
|
||||||
.unwrap()?;
|
.unwrap()?;
|
||||||
emit_count += 1;
|
emit_count += 1;
|
||||||
cache.set_emit_data(
|
cache.set_emit_data(
|
||||||
|
@ -642,26 +464,41 @@ pub fn emit(
|
||||||
("Total time".to_string(), start.elapsed().as_millis() as u32),
|
("Total time".to_string(), start.elapsed().as_millis() as u32),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Ok(CheckEmitResult {
|
Ok(CheckResult {
|
||||||
diagnostics: Diagnostics::default(),
|
diagnostics: Diagnostics::default(),
|
||||||
stats,
|
stats,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check a module graph to determine if the graph contains anything that
|
enum CheckHashResult {
|
||||||
/// is required to be emitted to be valid. It determines what modules in the
|
Hash(u64),
|
||||||
/// graph are emittable and for those that are emittable, if there is currently
|
NoFiles,
|
||||||
/// a valid emit in the cache.
|
}
|
||||||
fn valid_emit(
|
|
||||||
|
/// Gets a hash of the inputs for type checking. This can then
|
||||||
|
/// be used to tell
|
||||||
|
fn get_check_hash(
|
||||||
graph_data: &GraphData,
|
graph_data: &GraphData,
|
||||||
cache: &dyn EmitCache,
|
options: &CheckOptions,
|
||||||
ts_config: &TsConfig,
|
) -> CheckHashResult {
|
||||||
reload: bool,
|
// twox hash is insecure, but fast so it works for our purposes
|
||||||
reload_exclusions: &HashSet<ModuleSpecifier>,
|
use std::hash::Hasher;
|
||||||
) -> bool {
|
use twox_hash::XxHash64;
|
||||||
let config_bytes = ts_config.as_bytes();
|
|
||||||
let check_js = ts_config.get_check_js();
|
let mut hasher = XxHash64::default();
|
||||||
for (specifier, module_entry) in graph_data.entries() {
|
hasher.write_u8(match options.type_check_mode {
|
||||||
|
TypeCheckMode::All => 0,
|
||||||
|
TypeCheckMode::Local => 1,
|
||||||
|
TypeCheckMode::None => 2,
|
||||||
|
});
|
||||||
|
hasher.write(&options.ts_config.as_bytes());
|
||||||
|
|
||||||
|
let check_js = options.ts_config.get_check_js();
|
||||||
|
let mut sorted_entries = graph_data.entries().collect::<Vec<_>>();
|
||||||
|
sorted_entries.sort_by_key(|(s, _)| s.as_str()); // make it deterministic
|
||||||
|
let mut has_file = false;
|
||||||
|
let mut has_file_to_type_check = false;
|
||||||
|
for (specifier, module_entry) in sorted_entries {
|
||||||
if let ModuleEntry::Module {
|
if let ModuleEntry::Module {
|
||||||
code,
|
code,
|
||||||
media_type,
|
media_type,
|
||||||
|
@ -669,13 +506,26 @@ fn valid_emit(
|
||||||
..
|
..
|
||||||
} = module_entry
|
} = module_entry
|
||||||
{
|
{
|
||||||
|
if *ts_check {
|
||||||
|
has_file_to_type_check = true;
|
||||||
|
}
|
||||||
|
|
||||||
match media_type {
|
match media_type {
|
||||||
MediaType::TypeScript
|
MediaType::TypeScript
|
||||||
|
| MediaType::Dts
|
||||||
|
| MediaType::Dmts
|
||||||
|
| MediaType::Dcts
|
||||||
| MediaType::Mts
|
| MediaType::Mts
|
||||||
| MediaType::Cts
|
| MediaType::Cts
|
||||||
| MediaType::Tsx
|
| MediaType::Tsx => {
|
||||||
| MediaType::Jsx => {}
|
has_file = true;
|
||||||
MediaType::JavaScript | MediaType::Mjs | MediaType::Cjs => {
|
has_file_to_type_check = true;
|
||||||
|
}
|
||||||
|
MediaType::JavaScript
|
||||||
|
| MediaType::Mjs
|
||||||
|
| MediaType::Cjs
|
||||||
|
| MediaType::Jsx => {
|
||||||
|
has_file = true;
|
||||||
if !check_js && !ts_check {
|
if !check_js && !ts_check {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -683,25 +533,20 @@ fn valid_emit(
|
||||||
MediaType::Json
|
MediaType::Json
|
||||||
| MediaType::TsBuildInfo
|
| MediaType::TsBuildInfo
|
||||||
| MediaType::SourceMap
|
| MediaType::SourceMap
|
||||||
| MediaType::Dts
|
|
||||||
| MediaType::Dmts
|
|
||||||
| MediaType::Dcts
|
|
||||||
| MediaType::Wasm
|
| MediaType::Wasm
|
||||||
| MediaType::Unknown => continue,
|
| MediaType::Unknown => continue,
|
||||||
}
|
}
|
||||||
if reload && !reload_exclusions.contains(specifier) {
|
hasher.write(specifier.as_str().as_bytes());
|
||||||
return false;
|
hasher.write(code.as_bytes());
|
||||||
}
|
|
||||||
if let Some(source_hash) = cache.get_source_hash(specifier) {
|
|
||||||
if source_hash != get_version(code.as_bytes(), &config_bytes) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
true
|
|
||||||
|
if !has_file || !check_js && !has_file_to_type_check {
|
||||||
|
// no files to type check
|
||||||
|
CheckHashResult::NoFiles
|
||||||
|
} else {
|
||||||
|
CheckHashResult::Hash(hasher.finish())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An adapter struct to make a deno_graph::ModuleGraphError display as expected
|
/// An adapter struct to make a deno_graph::ModuleGraphError display as expected
|
||||||
|
|
|
@ -162,8 +162,10 @@ impl GraphData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn entries(&self) -> HashMap<&ModuleSpecifier, &ModuleEntry> {
|
pub fn entries(
|
||||||
self.modules.iter().collect()
|
&self,
|
||||||
|
) -> impl Iterator<Item = (&ModuleSpecifier, &ModuleEntry)> {
|
||||||
|
self.modules.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Walk dependencies from `roots` and return every encountered specifier.
|
/// Walk dependencies from `roots` and return every encountered specifier.
|
||||||
|
|
11
cli/main.rs
11
cli/main.rs
|
@ -9,7 +9,6 @@ mod compat;
|
||||||
mod deno_dir;
|
mod deno_dir;
|
||||||
mod diagnostics;
|
mod diagnostics;
|
||||||
mod diff;
|
mod diff;
|
||||||
mod disk_cache;
|
|
||||||
mod display;
|
mod display;
|
||||||
mod emit;
|
mod emit;
|
||||||
mod errors;
|
mod errors;
|
||||||
|
@ -59,6 +58,7 @@ use crate::args::TypeCheckMode;
|
||||||
use crate::args::UninstallFlags;
|
use crate::args::UninstallFlags;
|
||||||
use crate::args::UpgradeFlags;
|
use crate::args::UpgradeFlags;
|
||||||
use crate::args::VendorFlags;
|
use crate::args::VendorFlags;
|
||||||
|
use crate::cache::TypeCheckCache;
|
||||||
use crate::emit::TsConfigType;
|
use crate::emit::TsConfigType;
|
||||||
use crate::file_fetcher::File;
|
use crate::file_fetcher::File;
|
||||||
use crate::file_watcher::ResolutionResult;
|
use crate::file_watcher::ResolutionResult;
|
||||||
|
@ -661,19 +661,20 @@ async fn create_graph_and_maybe_check(
|
||||||
eprintln!("{}", ignored_options);
|
eprintln!("{}", ignored_options);
|
||||||
}
|
}
|
||||||
let maybe_config_specifier = ps.options.maybe_config_file_specifier();
|
let maybe_config_specifier = ps.options.maybe_config_file_specifier();
|
||||||
let check_result = emit::check_and_maybe_emit(
|
// todo: don't use anything on failure
|
||||||
|
let cache =
|
||||||
|
TypeCheckCache::new(&ps.dir.type_checking_cache_db_file_path())?;
|
||||||
|
let check_result = emit::check(
|
||||||
&graph.roots,
|
&graph.roots,
|
||||||
Arc::new(RwLock::new(graph.as_ref().into())),
|
Arc::new(RwLock::new(graph.as_ref().into())),
|
||||||
&ps.dir.gen_cache,
|
&cache,
|
||||||
emit::CheckOptions {
|
emit::CheckOptions {
|
||||||
type_check_mode: ps.options.type_check_mode(),
|
type_check_mode: ps.options.type_check_mode(),
|
||||||
debug,
|
debug,
|
||||||
emit_with_diagnostics: false,
|
|
||||||
maybe_config_specifier,
|
maybe_config_specifier,
|
||||||
ts_config: ts_config_result.ts_config,
|
ts_config: ts_config_result.ts_config,
|
||||||
log_checks: true,
|
log_checks: true,
|
||||||
reload: ps.options.reload_flag(),
|
reload: ps.options.reload_flag(),
|
||||||
reload_exclusions: Default::default(),
|
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
debug!("{}", check_result.stats);
|
debug!("{}", check_result.stats);
|
||||||
|
|
|
@ -5,11 +5,12 @@ use crate::args::DenoSubcommand;
|
||||||
use crate::args::Flags;
|
use crate::args::Flags;
|
||||||
use crate::args::TypeCheckMode;
|
use crate::args::TypeCheckMode;
|
||||||
use crate::cache;
|
use crate::cache;
|
||||||
|
use crate::cache::EmitCache;
|
||||||
|
use crate::cache::TypeCheckCache;
|
||||||
use crate::compat;
|
use crate::compat;
|
||||||
use crate::compat::NodeEsmResolver;
|
use crate::compat::NodeEsmResolver;
|
||||||
use crate::deno_dir;
|
use crate::deno_dir;
|
||||||
use crate::emit;
|
use crate::emit;
|
||||||
use crate::emit::EmitCache;
|
|
||||||
use crate::emit::TsConfigType;
|
use crate::emit::TsConfigType;
|
||||||
use crate::emit::TsTypeLib;
|
use crate::emit::TsTypeLib;
|
||||||
use crate::file_fetcher::FileFetcher;
|
use crate::file_fetcher::FileFetcher;
|
||||||
|
@ -394,7 +395,7 @@ impl ProcState {
|
||||||
// should be skipped.
|
// should be skipped.
|
||||||
let reload_exclusions: HashSet<ModuleSpecifier> = {
|
let reload_exclusions: HashSet<ModuleSpecifier> = {
|
||||||
let graph_data = self.graph_data.read();
|
let graph_data = self.graph_data.read();
|
||||||
graph_data.entries().into_keys().cloned().collect()
|
graph_data.entries().map(|(s, _)| s).cloned().collect()
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -426,36 +427,45 @@ impl ProcState {
|
||||||
log::warn!("{}", ignored_options);
|
log::warn!("{}", ignored_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.options.type_check_mode() == TypeCheckMode::None {
|
// start type checking if necessary
|
||||||
let options = emit::EmitOptions {
|
let type_checking_task =
|
||||||
ts_config: ts_config_result.ts_config,
|
if self.options.type_check_mode() != TypeCheckMode::None {
|
||||||
reload: self.options.reload_flag(),
|
let maybe_config_specifier = self.options.maybe_config_file_specifier();
|
||||||
reload_exclusions,
|
let roots = roots.clone();
|
||||||
|
let options = emit::CheckOptions {
|
||||||
|
type_check_mode: self.options.type_check_mode(),
|
||||||
|
debug: self.options.log_level() == Some(log::Level::Debug),
|
||||||
|
maybe_config_specifier,
|
||||||
|
ts_config: ts_config_result.ts_config.clone(),
|
||||||
|
log_checks: true,
|
||||||
|
reload: self.options.reload_flag()
|
||||||
|
&& !roots.iter().all(|r| reload_exclusions.contains(&r.0)),
|
||||||
|
};
|
||||||
|
// todo(THIS PR): don't use a cache on failure
|
||||||
|
let check_cache =
|
||||||
|
TypeCheckCache::new(&self.dir.type_checking_cache_db_file_path())?;
|
||||||
|
let graph_data = self.graph_data.clone();
|
||||||
|
Some(tokio::task::spawn_blocking(move || {
|
||||||
|
emit::check(&roots, graph_data, &check_cache, options)
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
};
|
};
|
||||||
let emit_result = emit::emit(&graph, &self.dir.gen_cache, options)?;
|
|
||||||
log::debug!("{}", emit_result.stats);
|
let options = emit::EmitOptions {
|
||||||
} else {
|
ts_config: ts_config_result.ts_config,
|
||||||
let maybe_config_specifier = self.options.maybe_config_file_specifier();
|
reload: self.options.reload_flag(),
|
||||||
let options = emit::CheckOptions {
|
reload_exclusions,
|
||||||
type_check_mode: self.options.type_check_mode(),
|
};
|
||||||
debug: self.options.log_level() == Some(log::Level::Debug),
|
let emit_result = emit::emit(&graph, &self.dir.gen_cache, options)?;
|
||||||
emit_with_diagnostics: false,
|
log::debug!("{}", emit_result.stats);
|
||||||
maybe_config_specifier,
|
|
||||||
ts_config: ts_config_result.ts_config,
|
if let Some(type_checking_task) = type_checking_task {
|
||||||
log_checks: true,
|
let type_check_result = type_checking_task.await??;
|
||||||
reload: self.options.reload_flag(),
|
if !type_check_result.diagnostics.is_empty() {
|
||||||
reload_exclusions,
|
return Err(anyhow!(type_check_result.diagnostics));
|
||||||
};
|
|
||||||
let emit_result = emit::check_and_maybe_emit(
|
|
||||||
&roots,
|
|
||||||
self.graph_data.clone(),
|
|
||||||
&self.dir.gen_cache,
|
|
||||||
options,
|
|
||||||
)?;
|
|
||||||
if !emit_result.diagnostics.is_empty() {
|
|
||||||
return Err(anyhow!(emit_result.diagnostics));
|
|
||||||
}
|
}
|
||||||
log::debug!("{}", emit_result.stats);
|
log::debug!("{}", type_check_result.stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.options.type_check_mode() != TypeCheckMode::None {
|
if self.options.type_check_mode() != TypeCheckMode::None {
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
use std::process::Stdio;
|
||||||
|
|
||||||
use crate::itest;
|
use crate::itest;
|
||||||
|
|
||||||
|
use test_util as util;
|
||||||
|
|
||||||
itest!(_095_check_with_bare_import {
|
itest!(_095_check_with_bare_import {
|
||||||
args: "check 095_cache_with_bare_import.ts",
|
args: "check 095_cache_with_bare_import.ts",
|
||||||
output: "095_cache_with_bare_import.ts.out",
|
output: "095_cache_with_bare_import.ts.out",
|
||||||
|
@ -43,3 +47,62 @@ itest!(declaration_header_file_with_no_exports {
|
||||||
args: "check --quiet declaration_header_file_with_no_exports.ts",
|
args: "check --quiet declaration_header_file_with_no_exports.ts",
|
||||||
output_str: Some(""),
|
output_str: Some(""),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cache_switching_config_then_no_config() {
|
||||||
|
let deno_dir = util::new_deno_dir();
|
||||||
|
assert!(does_type_checking(&deno_dir, true));
|
||||||
|
assert!(does_type_checking(&deno_dir, false));
|
||||||
|
|
||||||
|
// should now not do type checking even when it changes
|
||||||
|
// configs because it previously did
|
||||||
|
assert!(!does_type_checking(&deno_dir, true));
|
||||||
|
assert!(!does_type_checking(&deno_dir, false));
|
||||||
|
|
||||||
|
fn does_type_checking(deno_dir: &util::TempDir, with_config: bool) -> bool {
|
||||||
|
let mut cmd = util::deno_cmd_with_deno_dir(deno_dir);
|
||||||
|
cmd
|
||||||
|
.current_dir(util::testdata_path())
|
||||||
|
.stderr(Stdio::piped())
|
||||||
|
.arg("check")
|
||||||
|
.arg("check/cache_config_on_off/main.ts");
|
||||||
|
if with_config {
|
||||||
|
cmd
|
||||||
|
.arg("--config")
|
||||||
|
.arg("check/cache_config_on_off/deno.json");
|
||||||
|
}
|
||||||
|
let output = cmd.spawn().unwrap().wait_with_output().unwrap();
|
||||||
|
assert!(output.status.success());
|
||||||
|
|
||||||
|
let stderr = std::str::from_utf8(&output.stderr).unwrap();
|
||||||
|
stderr.contains("Check")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn reload_flag() {
|
||||||
|
// should do type checking whenever someone specifies --reload
|
||||||
|
let deno_dir = util::new_deno_dir();
|
||||||
|
assert!(does_type_checking(&deno_dir, false));
|
||||||
|
assert!(!does_type_checking(&deno_dir, false));
|
||||||
|
assert!(does_type_checking(&deno_dir, true));
|
||||||
|
assert!(does_type_checking(&deno_dir, true));
|
||||||
|
assert!(!does_type_checking(&deno_dir, false));
|
||||||
|
|
||||||
|
fn does_type_checking(deno_dir: &util::TempDir, reload: bool) -> bool {
|
||||||
|
let mut cmd = util::deno_cmd_with_deno_dir(deno_dir);
|
||||||
|
cmd
|
||||||
|
.current_dir(util::testdata_path())
|
||||||
|
.stderr(Stdio::piped())
|
||||||
|
.arg("check")
|
||||||
|
.arg("check/cache_config_on_off/main.ts");
|
||||||
|
if reload {
|
||||||
|
cmd.arg("--reload");
|
||||||
|
}
|
||||||
|
let output = cmd.spawn().unwrap().wait_with_output().unwrap();
|
||||||
|
assert!(output.status.success());
|
||||||
|
|
||||||
|
let stderr = std::str::from_utf8(&output.stderr).unwrap();
|
||||||
|
stderr.contains("Check")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -158,12 +158,6 @@ fn cache_test() {
|
||||||
.expect("Failed to spawn script");
|
.expect("Failed to spawn script");
|
||||||
assert!(output.status.success());
|
assert!(output.status.success());
|
||||||
|
|
||||||
let out = std::str::from_utf8(&output.stderr).unwrap();
|
|
||||||
// Check if file and dependencies are written successfully
|
|
||||||
assert!(out.contains("host.writeFile(\"deno://subdir/print_hello.js\")"));
|
|
||||||
assert!(out.contains("host.writeFile(\"deno://subdir/mod2.js\")"));
|
|
||||||
assert!(out.contains("host.writeFile(\"deno://006_url_imports.js\")"));
|
|
||||||
|
|
||||||
let prg = util::deno_exe_path();
|
let prg = util::deno_exe_path();
|
||||||
let output = Command::new(&prg)
|
let output = Command::new(&prg)
|
||||||
.env("DENO_DIR", deno_dir.path())
|
.env("DENO_DIR", deno_dir.path())
|
||||||
|
@ -369,46 +363,6 @@ fn ts_no_recheck_on_redirect() {
|
||||||
assert!(std::str::from_utf8(&output.stderr).unwrap().is_empty());
|
assert!(std::str::from_utf8(&output.stderr).unwrap().is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn ts_reload() {
|
|
||||||
let hello_ts = util::testdata_path().join("002_hello.ts");
|
|
||||||
assert!(hello_ts.is_file());
|
|
||||||
|
|
||||||
let deno_dir = TempDir::new();
|
|
||||||
let mut initial = util::deno_cmd_with_deno_dir(&deno_dir)
|
|
||||||
.current_dir(util::testdata_path())
|
|
||||||
.arg("cache")
|
|
||||||
.arg("--check=all")
|
|
||||||
.arg(&hello_ts)
|
|
||||||
.spawn()
|
|
||||||
.expect("failed to spawn script");
|
|
||||||
let status_initial =
|
|
||||||
initial.wait().expect("failed to wait for child process");
|
|
||||||
assert!(status_initial.success());
|
|
||||||
|
|
||||||
let output = util::deno_cmd_with_deno_dir(&deno_dir)
|
|
||||||
.current_dir(util::testdata_path())
|
|
||||||
.arg("cache")
|
|
||||||
.arg("--check=all")
|
|
||||||
.arg("--reload")
|
|
||||||
.arg("-L")
|
|
||||||
.arg("debug")
|
|
||||||
.arg(&hello_ts)
|
|
||||||
.output()
|
|
||||||
.expect("failed to spawn script");
|
|
||||||
|
|
||||||
// check the output of the the bundle program.
|
|
||||||
let output_path = hello_ts.canonicalize().unwrap();
|
|
||||||
assert!(
|
|
||||||
dbg!(std::str::from_utf8(&output.stderr).unwrap().trim()).contains(
|
|
||||||
&format!(
|
|
||||||
"host.getSourceFile(\"{}\", Latest)",
|
|
||||||
url::Url::from_file_path(&output_path).unwrap().as_str()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn timeout_clear() {
|
fn timeout_clear() {
|
||||||
// https://github.com/denoland/deno/issues/7599
|
// https://github.com/denoland/deno/issues/7599
|
||||||
|
|
|
@ -2,8 +2,10 @@
|
||||||
|
|
||||||
use deno_core::url;
|
use deno_core::url;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
use std::process::Stdio;
|
||||||
use test_util as util;
|
use test_util as util;
|
||||||
use test_util::TempDir;
|
use test_util::TempDir;
|
||||||
|
use util::assert_contains;
|
||||||
|
|
||||||
itest!(stdout_write_all {
|
itest!(stdout_write_all {
|
||||||
args: "run --quiet stdout_write_all.ts",
|
args: "run --quiet stdout_write_all.ts",
|
||||||
|
@ -268,7 +270,7 @@ fn webstorage_location_shares_origin() {
|
||||||
.arg("--location")
|
.arg("--location")
|
||||||
.arg("https://example.com/a.ts")
|
.arg("https://example.com/a.ts")
|
||||||
.arg("webstorage/fixture.ts")
|
.arg("webstorage/fixture.ts")
|
||||||
.stdout(std::process::Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.wait_with_output()
|
.wait_with_output()
|
||||||
|
@ -283,7 +285,7 @@ fn webstorage_location_shares_origin() {
|
||||||
.arg("--location")
|
.arg("--location")
|
||||||
.arg("https://example.com/b.ts")
|
.arg("https://example.com/b.ts")
|
||||||
.arg("webstorage/logger.ts")
|
.arg("webstorage/logger.ts")
|
||||||
.stdout(std::process::Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.wait_with_output()
|
.wait_with_output()
|
||||||
|
@ -305,7 +307,7 @@ fn webstorage_config_file() {
|
||||||
.arg("--config")
|
.arg("--config")
|
||||||
.arg("webstorage/config_a.jsonc")
|
.arg("webstorage/config_a.jsonc")
|
||||||
.arg("webstorage/fixture.ts")
|
.arg("webstorage/fixture.ts")
|
||||||
.stdout(std::process::Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.wait_with_output()
|
.wait_with_output()
|
||||||
|
@ -320,7 +322,7 @@ fn webstorage_config_file() {
|
||||||
.arg("--config")
|
.arg("--config")
|
||||||
.arg("webstorage/config_b.jsonc")
|
.arg("webstorage/config_b.jsonc")
|
||||||
.arg("webstorage/logger.ts")
|
.arg("webstorage/logger.ts")
|
||||||
.stdout(std::process::Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.wait_with_output()
|
.wait_with_output()
|
||||||
|
@ -335,7 +337,7 @@ fn webstorage_config_file() {
|
||||||
.arg("--config")
|
.arg("--config")
|
||||||
.arg("webstorage/config_a.jsonc")
|
.arg("webstorage/config_a.jsonc")
|
||||||
.arg("webstorage/logger.ts")
|
.arg("webstorage/logger.ts")
|
||||||
.stdout(std::process::Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.wait_with_output()
|
.wait_with_output()
|
||||||
|
@ -359,7 +361,7 @@ fn webstorage_location_precedes_config() {
|
||||||
.arg("--config")
|
.arg("--config")
|
||||||
.arg("webstorage/config_a.jsonc")
|
.arg("webstorage/config_a.jsonc")
|
||||||
.arg("webstorage/fixture.ts")
|
.arg("webstorage/fixture.ts")
|
||||||
.stdout(std::process::Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.wait_with_output()
|
.wait_with_output()
|
||||||
|
@ -376,7 +378,7 @@ fn webstorage_location_precedes_config() {
|
||||||
.arg("--config")
|
.arg("--config")
|
||||||
.arg("webstorage/config_b.jsonc")
|
.arg("webstorage/config_b.jsonc")
|
||||||
.arg("webstorage/logger.ts")
|
.arg("webstorage/logger.ts")
|
||||||
.stdout(std::process::Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.wait_with_output()
|
.wait_with_output()
|
||||||
|
@ -396,7 +398,7 @@ fn webstorage_main_module() {
|
||||||
.current_dir(util::testdata_path())
|
.current_dir(util::testdata_path())
|
||||||
.arg("run")
|
.arg("run")
|
||||||
.arg("webstorage/fixture.ts")
|
.arg("webstorage/fixture.ts")
|
||||||
.stdout(std::process::Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.wait_with_output()
|
.wait_with_output()
|
||||||
|
@ -409,7 +411,7 @@ fn webstorage_main_module() {
|
||||||
.current_dir(util::testdata_path())
|
.current_dir(util::testdata_path())
|
||||||
.arg("run")
|
.arg("run")
|
||||||
.arg("webstorage/logger.ts")
|
.arg("webstorage/logger.ts")
|
||||||
.stdout(std::process::Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.wait_with_output()
|
.wait_with_output()
|
||||||
|
@ -422,7 +424,7 @@ fn webstorage_main_module() {
|
||||||
.current_dir(util::testdata_path())
|
.current_dir(util::testdata_path())
|
||||||
.arg("run")
|
.arg("run")
|
||||||
.arg("webstorage/fixture.ts")
|
.arg("webstorage/fixture.ts")
|
||||||
.stdout(std::process::Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.wait_with_output()
|
.wait_with_output()
|
||||||
|
@ -1632,8 +1634,8 @@ fn no_validate_asm() {
|
||||||
.current_dir(util::testdata_path())
|
.current_dir(util::testdata_path())
|
||||||
.arg("run")
|
.arg("run")
|
||||||
.arg("no_validate_asm.js")
|
.arg("no_validate_asm.js")
|
||||||
.stderr(std::process::Stdio::piped())
|
.stderr(Stdio::piped())
|
||||||
.stdout(std::process::Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.wait_with_output()
|
.wait_with_output()
|
||||||
|
@ -1650,7 +1652,7 @@ fn exec_path() {
|
||||||
.arg("run")
|
.arg("run")
|
||||||
.arg("--allow-read")
|
.arg("--allow-read")
|
||||||
.arg("exec_path.ts")
|
.arg("exec_path.ts")
|
||||||
.stdout(std::process::Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.wait_with_output()
|
.wait_with_output()
|
||||||
|
@ -1776,7 +1778,7 @@ fn rust_log() {
|
||||||
.current_dir(util::testdata_path())
|
.current_dir(util::testdata_path())
|
||||||
.arg("run")
|
.arg("run")
|
||||||
.arg("001_hello.js")
|
.arg("001_hello.js")
|
||||||
.stderr(std::process::Stdio::piped())
|
.stderr(Stdio::piped())
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.wait_with_output()
|
.wait_with_output()
|
||||||
|
@ -1790,7 +1792,7 @@ fn rust_log() {
|
||||||
.arg("run")
|
.arg("run")
|
||||||
.arg("001_hello.js")
|
.arg("001_hello.js")
|
||||||
.env("RUST_LOG", "debug")
|
.env("RUST_LOG", "debug")
|
||||||
.stderr(std::process::Stdio::piped())
|
.stderr(Stdio::piped())
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.wait_with_output()
|
.wait_with_output()
|
||||||
|
@ -1810,7 +1812,7 @@ fn dont_cache_on_check_fail() {
|
||||||
.arg("--check=all")
|
.arg("--check=all")
|
||||||
.arg("--reload")
|
.arg("--reload")
|
||||||
.arg("error_003_typescript.ts")
|
.arg("error_003_typescript.ts")
|
||||||
.stderr(std::process::Stdio::piped())
|
.stderr(Stdio::piped())
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.wait_with_output()
|
.wait_with_output()
|
||||||
|
@ -1824,7 +1826,7 @@ fn dont_cache_on_check_fail() {
|
||||||
.arg("run")
|
.arg("run")
|
||||||
.arg("--check=all")
|
.arg("--check=all")
|
||||||
.arg("error_003_typescript.ts")
|
.arg("error_003_typescript.ts")
|
||||||
.stderr(std::process::Stdio::piped())
|
.stderr(Stdio::piped())
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.wait_with_output()
|
.wait_with_output()
|
||||||
|
@ -2374,8 +2376,8 @@ fn issue12740() {
|
||||||
.current_dir(util::testdata_path())
|
.current_dir(util::testdata_path())
|
||||||
.arg("run")
|
.arg("run")
|
||||||
.arg(&mod1_path)
|
.arg(&mod1_path)
|
||||||
.stderr(std::process::Stdio::null())
|
.stderr(Stdio::null())
|
||||||
.stdout(std::process::Stdio::null())
|
.stdout(Stdio::null())
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.wait()
|
.wait()
|
||||||
|
@ -2387,8 +2389,8 @@ fn issue12740() {
|
||||||
.current_dir(util::testdata_path())
|
.current_dir(util::testdata_path())
|
||||||
.arg("run")
|
.arg("run")
|
||||||
.arg(&mod1_path)
|
.arg(&mod1_path)
|
||||||
.stderr(std::process::Stdio::null())
|
.stderr(Stdio::null())
|
||||||
.stdout(std::process::Stdio::null())
|
.stdout(Stdio::null())
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.wait()
|
.wait()
|
||||||
|
@ -2411,8 +2413,8 @@ fn issue12807() {
|
||||||
.arg("run")
|
.arg("run")
|
||||||
.arg("--check")
|
.arg("--check")
|
||||||
.arg(&mod1_path)
|
.arg(&mod1_path)
|
||||||
.stderr(std::process::Stdio::null())
|
.stderr(Stdio::null())
|
||||||
.stdout(std::process::Stdio::null())
|
.stdout(Stdio::null())
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.wait()
|
.wait()
|
||||||
|
@ -2425,8 +2427,8 @@ fn issue12807() {
|
||||||
.arg("run")
|
.arg("run")
|
||||||
.arg("--check")
|
.arg("--check")
|
||||||
.arg(&mod1_path)
|
.arg(&mod1_path)
|
||||||
.stderr(std::process::Stdio::null())
|
.stderr(Stdio::null())
|
||||||
.stdout(std::process::Stdio::null())
|
.stdout(Stdio::null())
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.wait()
|
.wait()
|
||||||
|
@ -2663,6 +2665,36 @@ itest!(js_root_with_ts_check {
|
||||||
exit_code: 1,
|
exit_code: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn check_local_then_remote() {
|
||||||
|
let _http_guard = util::http_server();
|
||||||
|
let deno_dir = util::new_deno_dir();
|
||||||
|
let output = util::deno_cmd_with_deno_dir(&deno_dir)
|
||||||
|
.current_dir(util::testdata_path())
|
||||||
|
.arg("run")
|
||||||
|
.arg("--check")
|
||||||
|
.arg("run/remote_type_error/main.ts")
|
||||||
|
.spawn()
|
||||||
|
.unwrap()
|
||||||
|
.wait_with_output()
|
||||||
|
.unwrap();
|
||||||
|
assert!(output.status.success());
|
||||||
|
let output = util::deno_cmd_with_deno_dir(&deno_dir)
|
||||||
|
.current_dir(util::testdata_path())
|
||||||
|
.arg("run")
|
||||||
|
.arg("--check=all")
|
||||||
|
.arg("run/remote_type_error/main.ts")
|
||||||
|
.env("NO_COLOR", "1")
|
||||||
|
.stderr(Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
.unwrap()
|
||||||
|
.wait_with_output()
|
||||||
|
.unwrap();
|
||||||
|
assert!(!output.status.success());
|
||||||
|
let stderr = std::str::from_utf8(&output.stderr).unwrap();
|
||||||
|
assert_contains!(stderr, "Type 'string' is not assignable to type 'number'.");
|
||||||
|
}
|
||||||
|
|
||||||
itest!(no_prompt_flag {
|
itest!(no_prompt_flag {
|
||||||
args: "run --quiet --unstable --no-prompt no_prompt.ts",
|
args: "run --quiet --unstable --no-prompt no_prompt.ts",
|
||||||
output_str: Some(""),
|
output_str: Some(""),
|
||||||
|
|
5
cli/tests/testdata/check/cache_config_on_off/deno.json
vendored
Normal file
5
cli/tests/testdata/check/cache_config_on_off/deno.json
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"strict": false
|
||||||
|
}
|
||||||
|
}
|
1
cli/tests/testdata/check/cache_config_on_off/main.ts
vendored
Normal file
1
cli/tests/testdata/check/cache_config_on_off/main.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
console.log(5);
|
|
@ -11,7 +11,7 @@ BRH:0
|
||||||
DA:1,1
|
DA:1,1
|
||||||
DA:2,2
|
DA:2,2
|
||||||
DA:3,2
|
DA:3,2
|
||||||
DA:4,2
|
DA:4,0
|
||||||
DA:5,0
|
DA:5,0
|
||||||
DA:6,0
|
DA:6,0
|
||||||
DA:7,2
|
DA:7,2
|
||||||
|
@ -22,6 +22,6 @@ DA:12,0
|
||||||
DA:13,0
|
DA:13,0
|
||||||
DA:14,0
|
DA:14,0
|
||||||
DA:15,0
|
DA:15,0
|
||||||
LH:5
|
LH:4
|
||||||
LF:14
|
LF:14
|
||||||
end_of_record
|
end_of_record
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
cover [WILDCARD]/coverage/branch.ts ... 35.714% (5/14)
|
cover [WILDCARD]/coverage/branch.ts ... 28.571% (4/14)
|
||||||
|
4 | } else {
|
||||||
5 | return false;
|
5 | return false;
|
||||||
6 | }
|
6 | }
|
||||||
-----|-----
|
-----|-----
|
||||||
|
|
|
@ -11,44 +11,62 @@ FNF:4
|
||||||
FNH:2
|
FNH:2
|
||||||
BRF:0
|
BRF:0
|
||||||
BRH:0
|
BRH:0
|
||||||
|
DA:13,1
|
||||||
|
DA:14,1
|
||||||
|
DA:15,1
|
||||||
|
DA:16,1
|
||||||
DA:17,2
|
DA:17,2
|
||||||
DA:18,2
|
DA:18,2
|
||||||
DA:19,2
|
DA:19,2
|
||||||
DA:20,2
|
DA:20,2
|
||||||
|
DA:21,2
|
||||||
DA:22,2
|
DA:22,2
|
||||||
DA:23,2
|
DA:23,2
|
||||||
DA:24,2
|
DA:24,2
|
||||||
DA:25,2
|
DA:25,2
|
||||||
DA:26,2
|
DA:26,2
|
||||||
DA:27,2
|
DA:27,2
|
||||||
|
DA:29,1
|
||||||
|
DA:30,1
|
||||||
|
DA:31,1
|
||||||
DA:32,1
|
DA:32,1
|
||||||
DA:33,1
|
DA:33,1
|
||||||
DA:34,1
|
DA:34,1
|
||||||
DA:35,1
|
DA:35,1
|
||||||
|
DA:36,1
|
||||||
DA:37,2
|
DA:37,2
|
||||||
DA:38,2
|
DA:38,2
|
||||||
DA:39,2
|
DA:39,2
|
||||||
DA:40,2
|
DA:40,2
|
||||||
DA:41,2
|
DA:41,2
|
||||||
DA:42,2
|
DA:42,2
|
||||||
|
DA:44,1
|
||||||
|
DA:45,1
|
||||||
DA:46,0
|
DA:46,0
|
||||||
DA:47,0
|
DA:47,0
|
||||||
DA:48,0
|
DA:48,0
|
||||||
DA:49,0
|
DA:49,0
|
||||||
|
DA:50,0
|
||||||
DA:51,0
|
DA:51,0
|
||||||
DA:52,0
|
DA:52,0
|
||||||
DA:53,0
|
DA:53,0
|
||||||
DA:54,0
|
DA:54,0
|
||||||
DA:55,0
|
DA:55,0
|
||||||
DA:56,0
|
DA:56,0
|
||||||
|
DA:58,1
|
||||||
|
DA:59,1
|
||||||
DA:60,1
|
DA:60,1
|
||||||
|
DA:62,1
|
||||||
|
DA:63,1
|
||||||
DA:64,0
|
DA:64,0
|
||||||
DA:65,0
|
DA:65,0
|
||||||
DA:66,0
|
DA:66,0
|
||||||
DA:67,0
|
DA:67,0
|
||||||
DA:68,0
|
DA:68,0
|
||||||
|
DA:70,1
|
||||||
DA:71,0
|
DA:71,0
|
||||||
|
DA:73,1
|
||||||
DA:74,1
|
DA:74,1
|
||||||
LH:22
|
LH:39
|
||||||
LF:38
|
LF:56
|
||||||
end_of_record
|
end_of_record
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
cover [WILDCARD]/coverage/complex.ts ... 57.895% (22/38)
|
cover [WILDCARD]/coverage/complex.ts ... 69.643% (39/56)
|
||||||
46 | export function unused(
|
46 | export function unused(
|
||||||
47 | foo: string,
|
47 | foo: string,
|
||||||
48 | bar: string,
|
48 | bar: string,
|
||||||
49 | baz: string,
|
49 | baz: string,
|
||||||
-----|-----
|
50 | ): Complex {
|
||||||
51 | return complex(
|
51 | return complex(
|
||||||
52 | foo,
|
52 | foo,
|
||||||
53 | bar,
|
53 | bar,
|
||||||
|
|
3
cli/tests/testdata/run/remote_type_error/main.ts
vendored
Normal file
3
cli/tests/testdata/run/remote_type_error/main.ts
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
import { doAction } from "http://localhost:4545/run/remote_type_error/remote.ts";
|
||||||
|
|
||||||
|
doAction();
|
5
cli/tests/testdata/run/remote_type_error/remote.ts
vendored
Normal file
5
cli/tests/testdata/run/remote_type_error/remote.ts
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
export function doAction() {
|
||||||
|
// this is an intentional type error
|
||||||
|
const val: number = "test";
|
||||||
|
console.log(val);
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
use crate::args::CoverageFlags;
|
use crate::args::CoverageFlags;
|
||||||
use crate::args::Flags;
|
use crate::args::Flags;
|
||||||
|
use crate::cache::EmitCache;
|
||||||
use crate::colors;
|
use crate::colors;
|
||||||
use crate::fs_util::collect_files;
|
use crate::fs_util::collect_files;
|
||||||
use crate::proc_state::ProcState;
|
use crate::proc_state::ProcState;
|
||||||
|
@ -676,16 +677,9 @@ pub async fn cover_files(
|
||||||
| MediaType::Mts
|
| MediaType::Mts
|
||||||
| MediaType::Cts
|
| MediaType::Cts
|
||||||
| MediaType::Tsx => {
|
| MediaType::Tsx => {
|
||||||
let emit_path = ps
|
match ps.dir.gen_cache.get_emit_text(&file.specifier) {
|
||||||
.dir
|
Some(source) => source,
|
||||||
.gen_cache
|
None => {
|
||||||
.get_cache_filename_with_extension(&file.specifier, "js")
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
unreachable!("Unable to get cache filename: {}", &file.specifier)
|
|
||||||
});
|
|
||||||
match ps.dir.gen_cache.get(&emit_path) {
|
|
||||||
Ok(b) => String::from_utf8(b).unwrap(),
|
|
||||||
Err(_) => {
|
|
||||||
return Err(anyhow!(
|
return Err(anyhow!(
|
||||||
"Missing transpiled source code for: \"{}\".
|
"Missing transpiled source code for: \"{}\".
|
||||||
Before generating coverage report, run `deno test --coverage` to ensure consistent state.",
|
Before generating coverage report, run `deno test --coverage` to ensure consistent state.",
|
||||||
|
|
|
@ -39,7 +39,7 @@ use std::sync::atomic::AtomicUsize;
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use super::incremental_cache::IncrementalCache;
|
use crate::cache::IncrementalCache;
|
||||||
|
|
||||||
/// Format JavaScript/TypeScript files.
|
/// Format JavaScript/TypeScript files.
|
||||||
pub async fn format(
|
pub async fn format(
|
||||||
|
|
|
@ -41,7 +41,7 @@ use std::sync::atomic::Ordering;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
use super::incremental_cache::IncrementalCache;
|
use crate::cache::IncrementalCache;
|
||||||
|
|
||||||
static STDIN_FILE_NAME: &str = "_stdin.ts";
|
static STDIN_FILE_NAME: &str = "_stdin.ts";
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ pub mod bench;
|
||||||
pub mod coverage;
|
pub mod coverage;
|
||||||
pub mod doc;
|
pub mod doc;
|
||||||
pub mod fmt;
|
pub mod fmt;
|
||||||
pub mod incremental_cache;
|
|
||||||
pub mod installer;
|
pub mod installer;
|
||||||
pub mod lint;
|
pub mod lint;
|
||||||
pub mod repl;
|
pub mod repl;
|
||||||
|
|
112
cli/tsc.rs
112
cli/tsc.rs
|
@ -252,8 +252,6 @@ pub struct Request {
|
||||||
pub struct Response {
|
pub struct Response {
|
||||||
/// Any diagnostics that have been returned from the checker.
|
/// Any diagnostics that have been returned from the checker.
|
||||||
pub diagnostics: Diagnostics,
|
pub diagnostics: Diagnostics,
|
||||||
/// Any files that were emitted during the check.
|
|
||||||
pub emitted_files: Vec<EmittedFile>,
|
|
||||||
/// If there was any build info associated with the exec request.
|
/// If there was any build info associated with the exec request.
|
||||||
pub maybe_tsbuildinfo: Option<String>,
|
pub maybe_tsbuildinfo: Option<String>,
|
||||||
/// Statistics from the check.
|
/// Statistics from the check.
|
||||||
|
@ -263,7 +261,6 @@ pub struct Response {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct State {
|
struct State {
|
||||||
hash_data: Vec<Vec<u8>>,
|
hash_data: Vec<Vec<u8>>,
|
||||||
emitted_files: Vec<EmittedFile>,
|
|
||||||
graph_data: Arc<RwLock<GraphData>>,
|
graph_data: Arc<RwLock<GraphData>>,
|
||||||
maybe_config_specifier: Option<ModuleSpecifier>,
|
maybe_config_specifier: Option<ModuleSpecifier>,
|
||||||
maybe_tsbuildinfo: Option<String>,
|
maybe_tsbuildinfo: Option<String>,
|
||||||
|
@ -283,7 +280,6 @@ impl State {
|
||||||
) -> Self {
|
) -> Self {
|
||||||
State {
|
State {
|
||||||
hash_data,
|
hash_data,
|
||||||
emitted_files: Default::default(),
|
|
||||||
graph_data,
|
graph_data,
|
||||||
maybe_config_specifier,
|
maybe_config_specifier,
|
||||||
maybe_tsbuildinfo,
|
maybe_tsbuildinfo,
|
||||||
|
@ -337,10 +333,6 @@ struct EmitArgs {
|
||||||
/// The _internal_ filename for the file. This will be used to determine how
|
/// The _internal_ filename for the file. This will be used to determine how
|
||||||
/// the file is cached and stored.
|
/// the file is cached and stored.
|
||||||
file_name: String,
|
file_name: String,
|
||||||
/// A string representation of the specifier that was associated with a
|
|
||||||
/// module. This should be present on every module that represents a module
|
|
||||||
/// that was requested to be transformed.
|
|
||||||
maybe_specifiers: Option<Vec<String>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[op]
|
#[op]
|
||||||
|
@ -349,43 +341,9 @@ fn op_emit(state: &mut OpState, args: EmitArgs) -> bool {
|
||||||
match args.file_name.as_ref() {
|
match args.file_name.as_ref() {
|
||||||
"deno:///.tsbuildinfo" => state.maybe_tsbuildinfo = Some(args.data),
|
"deno:///.tsbuildinfo" => state.maybe_tsbuildinfo = Some(args.data),
|
||||||
_ => {
|
_ => {
|
||||||
let media_type = MediaType::from(&args.file_name);
|
if cfg!(debug_assertions) {
|
||||||
let media_type = if matches!(
|
panic!("Unhandled emit write: {}", args.file_name);
|
||||||
media_type,
|
}
|
||||||
MediaType::JavaScript
|
|
||||||
| MediaType::Mjs
|
|
||||||
| MediaType::Cjs
|
|
||||||
| MediaType::Dts
|
|
||||||
| MediaType::Dmts
|
|
||||||
| MediaType::Dcts
|
|
||||||
| MediaType::SourceMap
|
|
||||||
| MediaType::TsBuildInfo
|
|
||||||
) {
|
|
||||||
media_type
|
|
||||||
} else {
|
|
||||||
MediaType::JavaScript
|
|
||||||
};
|
|
||||||
state.emitted_files.push(EmittedFile {
|
|
||||||
data: args.data,
|
|
||||||
maybe_specifiers: if let Some(specifiers) = &args.maybe_specifiers {
|
|
||||||
let specifiers = specifiers
|
|
||||||
.iter()
|
|
||||||
.map(|s| {
|
|
||||||
if let Some(data_specifier) = state.remapped_specifiers.get(s) {
|
|
||||||
data_specifier.clone()
|
|
||||||
} else if let Some(remapped_specifier) = state.root_map.get(s) {
|
|
||||||
remapped_specifier.clone()
|
|
||||||
} else {
|
|
||||||
normalize_specifier(s).unwrap()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
Some(specifiers)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
},
|
|
||||||
media_type,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -703,13 +661,11 @@ pub fn exec(request: Request) -> Result<Response, AnyError> {
|
||||||
|
|
||||||
if let Some(response) = state.maybe_response {
|
if let Some(response) = state.maybe_response {
|
||||||
let diagnostics = response.diagnostics;
|
let diagnostics = response.diagnostics;
|
||||||
let emitted_files = state.emitted_files;
|
|
||||||
let maybe_tsbuildinfo = state.maybe_tsbuildinfo;
|
let maybe_tsbuildinfo = state.maybe_tsbuildinfo;
|
||||||
let stats = response.stats;
|
let stats = response.stats;
|
||||||
|
|
||||||
Ok(Response {
|
Ok(Response {
|
||||||
diagnostics,
|
diagnostics,
|
||||||
emitted_files,
|
|
||||||
maybe_tsbuildinfo,
|
maybe_tsbuildinfo,
|
||||||
stats,
|
stats,
|
||||||
})
|
})
|
||||||
|
@ -907,64 +863,6 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn test_emit() {
|
|
||||||
let mut state = setup(None, None, None).await;
|
|
||||||
let actual = op_emit::call(
|
|
||||||
&mut state,
|
|
||||||
EmitArgs {
|
|
||||||
data: "some file content".to_string(),
|
|
||||||
file_name: "cache:///some/file.js".to_string(),
|
|
||||||
maybe_specifiers: Some(vec!["file:///some/file.ts".to_string()]),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
assert!(actual);
|
|
||||||
let state = state.borrow::<State>();
|
|
||||||
assert_eq!(state.emitted_files.len(), 1);
|
|
||||||
assert!(state.maybe_tsbuildinfo.is_none());
|
|
||||||
assert_eq!(
|
|
||||||
state.emitted_files[0],
|
|
||||||
EmittedFile {
|
|
||||||
data: "some file content".to_string(),
|
|
||||||
maybe_specifiers: Some(vec![resolve_url_or_path(
|
|
||||||
"file:///some/file.ts"
|
|
||||||
)
|
|
||||||
.unwrap()]),
|
|
||||||
media_type: MediaType::JavaScript,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn test_emit_strange_specifier() {
|
|
||||||
let mut state = setup(None, None, None).await;
|
|
||||||
let actual = op_emit::call(
|
|
||||||
&mut state,
|
|
||||||
EmitArgs {
|
|
||||||
data: "some file content".to_string(),
|
|
||||||
file_name: "deno:///some.file.ts?q=.json".to_string(),
|
|
||||||
maybe_specifiers: Some(
|
|
||||||
vec!["file:///some/file.ts?q=.json".to_string()],
|
|
||||||
),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
assert!(actual);
|
|
||||||
let state = state.borrow::<State>();
|
|
||||||
assert_eq!(state.emitted_files.len(), 1);
|
|
||||||
assert!(state.maybe_tsbuildinfo.is_none());
|
|
||||||
assert_eq!(
|
|
||||||
state.emitted_files[0],
|
|
||||||
EmittedFile {
|
|
||||||
data: "some file content".to_string(),
|
|
||||||
maybe_specifiers: Some(vec![resolve_url_or_path(
|
|
||||||
"file:///some/file.ts?q=.json"
|
|
||||||
)
|
|
||||||
.unwrap()]),
|
|
||||||
media_type: MediaType::JavaScript,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_emit_tsbuildinfo() {
|
async fn test_emit_tsbuildinfo() {
|
||||||
let mut state = setup(None, None, None).await;
|
let mut state = setup(None, None, None).await;
|
||||||
|
@ -973,12 +871,10 @@ mod tests {
|
||||||
EmitArgs {
|
EmitArgs {
|
||||||
data: "some file content".to_string(),
|
data: "some file content".to_string(),
|
||||||
file_name: "deno:///.tsbuildinfo".to_string(),
|
file_name: "deno:///.tsbuildinfo".to_string(),
|
||||||
maybe_specifiers: None,
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
assert!(actual);
|
assert!(actual);
|
||||||
let state = state.borrow::<State>();
|
let state = state.borrow::<State>();
|
||||||
assert_eq!(state.emitted_files.len(), 0);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
state.maybe_tsbuildinfo,
|
state.maybe_tsbuildinfo,
|
||||||
Some("some file content".to_string())
|
Some("some file content".to_string())
|
||||||
|
@ -1169,7 +1065,6 @@ mod tests {
|
||||||
.expect("exec should not have errored");
|
.expect("exec should not have errored");
|
||||||
eprintln!("diagnostics {:#?}", actual.diagnostics);
|
eprintln!("diagnostics {:#?}", actual.diagnostics);
|
||||||
assert!(actual.diagnostics.is_empty());
|
assert!(actual.diagnostics.is_empty());
|
||||||
assert!(actual.emitted_files.is_empty());
|
|
||||||
assert!(actual.maybe_tsbuildinfo.is_some());
|
assert!(actual.maybe_tsbuildinfo.is_some());
|
||||||
assert_eq!(actual.stats.0.len(), 12);
|
assert_eq!(actual.stats.0.len(), 12);
|
||||||
}
|
}
|
||||||
|
@ -1182,7 +1077,6 @@ mod tests {
|
||||||
.expect("exec should not have errored");
|
.expect("exec should not have errored");
|
||||||
eprintln!("diagnostics {:#?}", actual.diagnostics);
|
eprintln!("diagnostics {:#?}", actual.diagnostics);
|
||||||
assert!(actual.diagnostics.is_empty());
|
assert!(actual.diagnostics.is_empty());
|
||||||
assert!(actual.emitted_files.is_empty());
|
|
||||||
assert!(actual.maybe_tsbuildinfo.is_some());
|
assert!(actual.maybe_tsbuildinfo.is_some());
|
||||||
assert_eq!(actual.stats.0.len(), 12);
|
assert_eq!(actual.stats.0.len(), 12);
|
||||||
}
|
}
|
||||||
|
|
|
@ -336,15 +336,11 @@ delete Object.prototype.__proto__;
|
||||||
getDefaultLibLocation() {
|
getDefaultLibLocation() {
|
||||||
return ASSETS;
|
return ASSETS;
|
||||||
},
|
},
|
||||||
writeFile(fileName, data, _writeByteOrderMark, _onError, sourceFiles) {
|
writeFile(fileName, data, _writeByteOrderMark, _onError, _sourceFiles) {
|
||||||
debug(`host.writeFile("${fileName}")`);
|
debug(`host.writeFile("${fileName}")`);
|
||||||
let maybeSpecifiers;
|
|
||||||
if (sourceFiles) {
|
|
||||||
maybeSpecifiers = sourceFiles.map((sf) => sf.moduleName);
|
|
||||||
}
|
|
||||||
return core.opSync(
|
return core.opSync(
|
||||||
"op_emit",
|
"op_emit",
|
||||||
{ maybeSpecifiers, fileName, data },
|
{ fileName, data },
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
getCurrentDirectory() {
|
getCurrentDirectory() {
|
||||||
|
@ -557,16 +553,18 @@ delete Object.prototype.__proto__;
|
||||||
configFileParsingDiagnostics,
|
configFileParsingDiagnostics,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { diagnostics: emitDiagnostics } = program.emit();
|
|
||||||
|
|
||||||
const diagnostics = [
|
const diagnostics = [
|
||||||
...program.getConfigFileParsingDiagnostics(),
|
...program.getConfigFileParsingDiagnostics(),
|
||||||
...program.getSyntacticDiagnostics(),
|
...program.getSyntacticDiagnostics(),
|
||||||
...program.getOptionsDiagnostics(),
|
...program.getOptionsDiagnostics(),
|
||||||
...program.getGlobalDiagnostics(),
|
...program.getGlobalDiagnostics(),
|
||||||
...program.getSemanticDiagnostics(),
|
...program.getSemanticDiagnostics(),
|
||||||
...emitDiagnostics,
|
|
||||||
].filter(({ code }) => !IGNORED_DIAGNOSTICS.includes(code));
|
].filter(({ code }) => !IGNORED_DIAGNOSTICS.includes(code));
|
||||||
|
|
||||||
|
// emit the tsbuildinfo file
|
||||||
|
// @ts-ignore: emitBuildInfo is not exposed (https://github.com/microsoft/TypeScript/issues/49871)
|
||||||
|
program.emitBuildInfo(host.writeFile);
|
||||||
|
|
||||||
performanceProgram({ program });
|
performanceProgram({ program });
|
||||||
|
|
||||||
core.opSync("op_respond", {
|
core.opSync("op_respond", {
|
||||||
|
|
Loading…
Add table
Reference in a new issue