Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(cli): restore tripleslash lib refs support #8157

Merged
merged 1 commit into from
Oct 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions cli/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,8 +343,19 @@ impl fmt::Display for Diagnostic {
}
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Diagnostics(pub Vec<Diagnostic>);
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Diagnostics(Vec<Diagnostic>);

impl Diagnostics {
#[cfg(test)]
pub fn new(diagnostics: Vec<Diagnostic>) -> Self {
Diagnostics(diagnostics)
}

pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}

impl<'de> Deserialize<'de> for Diagnostics {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
Expand Down
2 changes: 1 addition & 1 deletion cli/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ async fn bundle_command(
if let Some(ignored_options) = maybe_ignored_options {
eprintln!("{}", ignored_options);
}
if !diagnostics.0.is_empty() {
if !diagnostics.is_empty() {
return Err(generic_error(diagnostics.to_string()));
}
}
Expand Down
8 changes: 4 additions & 4 deletions cli/module_graph2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -747,7 +747,7 @@ impl Graph2 {
debug!("graph does not need to be checked or emitted.");
return Ok((
Stats(Vec::new()),
Diagnostics(Vec::new()),
Diagnostics::default(),
maybe_ignored_options,
));
}
Expand Down Expand Up @@ -786,7 +786,7 @@ impl Graph2 {
graph.maybe_tsbuildinfo = response.maybe_tsbuildinfo;
// Only process changes to the graph if there are no diagnostics and there
// were files emitted.
if response.diagnostics.0.is_empty() && !response.emitted_files.is_empty() {
if response.diagnostics.is_empty() && !response.emitted_files.is_empty() {
let mut codes = HashMap::new();
let mut maps = HashMap::new();
let check_js = config.get_check_js();
Expand Down Expand Up @@ -1694,7 +1694,7 @@ pub mod tests {
.expect("should have checked");
assert!(maybe_ignored_options.is_none());
assert_eq!(stats.0.len(), 12);
assert!(diagnostics.0.is_empty());
assert!(diagnostics.is_empty());
let h = handler.borrow();
assert_eq!(h.cache_calls.len(), 2);
assert_eq!(h.tsbuildinfo_calls.len(), 1);
Expand All @@ -1717,7 +1717,7 @@ pub mod tests {
.expect("should have checked");
assert!(maybe_ignored_options.is_none());
assert_eq!(stats.0.len(), 12);
assert!(diagnostics.0.is_empty());
assert!(diagnostics.is_empty());
let h = handler.borrow();
assert_eq!(h.cache_calls.len(), 0);
assert_eq!(h.tsbuildinfo_calls.len(), 1);
Expand Down
2 changes: 1 addition & 1 deletion cli/op_fetch_asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use std::collections::HashMap;
use std::path::PathBuf;
use std::rc::Rc;

fn get_asset(name: &str) -> Option<&'static str> {
pub fn get_asset(name: &str) -> Option<&'static str> {
macro_rules! inc {
($e:expr) => {
Some(include_str!(concat!("dts/", $e)))
Expand Down
2 changes: 1 addition & 1 deletion cli/program_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ impl ProgramState {
if let Some(ignored_options) = maybe_ignored_options {
eprintln!("{}", ignored_options);
}
if !diagnostics.0.is_empty() {
if !diagnostics.is_empty() {
return Err(generic_error(diagnostics.to_string()));
}
};
Expand Down
7 changes: 7 additions & 0 deletions cli/tests/tsc2/file_libref.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/// <reference no-default-lib="true"/>
/// <reference lib="dom" />
/// <reference lib="deno.ns" />

export const div = document.createElement("div");
div.innerHTML = `<span>Hello World!</span>`;
console.log(Deno.args);
2 changes: 1 addition & 1 deletion cli/tsc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,7 @@ pub async fn runtime_compile(
execute_in_tsc(program_state.clone(), req_msg).map_err(extract_js_error)?;
let response: RuntimeCompileResponse = serde_json::from_str(&json_str)?;

if response.diagnostics.0.is_empty() && sources.is_none() {
if response.diagnostics.is_empty() && sources.is_none() {
compiler.cache_emitted_files(response.emit_map)?;
}

Expand Down
2 changes: 1 addition & 1 deletion cli/tsc/99_main_compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ delete Object.prototype.__proto__;
return sourceFile;
}

/** @type {{ data: string; hash: string; }} */
/** @type {{ data: string; hash?: string; scriptKind: ts.ScriptKind }} */
const { data, hash, scriptKind } = core.jsonOpSync(
"op_load",
{ specifier },
Expand Down
198 changes: 111 additions & 87 deletions cli/tsc2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use crate::diagnostics::Diagnostics;
use crate::media_type::MediaType;
use crate::module_graph2::Graph2;
use crate::module_graph2::Stats;
// TODO(@kitsonk) this needs to be refactored when we drop MG1
use crate::op_fetch_asset::get_asset;
use crate::tsc_config::TsConfig;

use deno_core::error::anyhow;
Expand All @@ -24,6 +26,19 @@ use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

fn get_maybe_hash(
maybe_source: &Option<String>,
hash_data: &[Vec<u8>],
) -> Option<String> {
if let Some(source) = maybe_source {
let mut data = vec![source.as_bytes().to_owned()];
data.extend_from_slice(hash_data);
Some(crate::checksum::gen(&data))
} else {
None
}
}

#[derive(Debug, Clone, Default, Eq, PartialEq)]
pub struct EmittedFile {
pub data: String,
Expand Down Expand Up @@ -177,6 +192,12 @@ fn load(state: &mut State, args: Value) -> Result<Value, AnyError> {
hash = Some("1".to_string());
media_type = MediaType::TypeScript;
Some("declare var a: any;\nexport = a;\n".to_string())
} else if v.specifier.starts_with("asset:///") {
let name = v.specifier.replace("asset:///", "");
let maybe_source = get_asset(&name).map(|s| s.to_string());
hash = get_maybe_hash(&maybe_source, &state.hash_data);
media_type = MediaType::from(&v.specifier);
maybe_source
} else {
let graph = state.graph.borrow();
let specifier =
Expand All @@ -191,11 +212,7 @@ fn load(state: &mut State, args: Value) -> Result<Value, AnyError> {
} else {
MediaType::Unknown
};
if let Some(source) = &maybe_source {
let mut data = vec![source.as_bytes().to_owned()];
data.extend_from_slice(&state.hash_data);
hash = Some(crate::checksum::gen(&data));
}
hash = get_maybe_hash(&maybe_source, &state.hash_data);
maybe_source
};

Expand Down Expand Up @@ -396,6 +413,47 @@ mod tests {
State::new(graph, hash_data, maybe_tsbuildinfo, HashMap::new())
}

async fn test_exec(
specifier: &ModuleSpecifier,
) -> Result<Response, AnyError> {
let hash_data = vec![b"something".to_vec()];
let c = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
let fixtures = c.join("tests/tsc2");
let handler = Rc::new(RefCell::new(MockSpecifierHandler {
fixtures,
..Default::default()
}));
let mut builder = GraphBuilder2::new(handler.clone(), None, None);
builder.add(&specifier, false).await?;
let graph = Rc::new(RefCell::new(builder.get_graph()));
let config = TsConfig::new(json!({
"allowJs": true,
"checkJs": false,
"esModuleInterop": true,
"emitDecoratorMetadata": false,
"incremental": true,
"jsx": "react",
"jsxFactory": "React.createElement",
"jsxFragmentFactory": "React.Fragment",
"lib": ["deno.window"],
"module": "esnext",
"noEmit": true,
"outDir": "deno:///",
"strict": true,
"target": "esnext",
"tsBuildInfoFile": "deno:///.tsbuildinfo",
}));
let request = Request {
config,
debug: false,
graph,
hash_data,
maybe_tsbuildinfo: None,
root_names: vec![(specifier.clone(), MediaType::TypeScript)],
};
exec(js::compiler_isolate_init(), request)
}

#[tokio::test]
async fn test_create_hash() {
let mut state = setup(None, Some(vec![b"something".to_vec()]), None).await;
Expand Down Expand Up @@ -481,6 +539,36 @@ mod tests {
);
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct LoadResponse {
data: String,
hash: Option<String>,
script_kind: i64,
}

#[tokio::test]
async fn test_load_asset() {
let mut state = setup(
Some(
ModuleSpecifier::resolve_url_or_path("https://deno.land/x/mod.ts")
.unwrap(),
),
None,
Some("some content".to_string()),
)
.await;
let value =
load(&mut state, json!({ "specifier": "asset:///lib.dom.d.ts" }))
.expect("should have invoked op");
let actual: LoadResponse =
serde_json::from_value(value).expect("failed to deserialize");
let expected = get_asset("lib.dom.d.ts").unwrap();
assert_eq!(actual.data, expected);
assert!(actual.hash.is_some());
assert_eq!(actual.script_kind, 3);
}

#[tokio::test]
async fn test_load_tsbuildinfo() {
let mut state = setup(
Expand Down Expand Up @@ -581,7 +669,7 @@ mod tests {
assert_eq!(
state.maybe_response,
Some(RespondArgs {
diagnostics: Diagnostics(vec![Diagnostic {
diagnostics: Diagnostics::new(vec![Diagnostic {
category: DiagnosticCategory::Error,
code: 5023,
start: None,
Expand All @@ -601,50 +689,13 @@ mod tests {
}

#[tokio::test]
async fn test_exec() {
async fn test_exec_basic() {
let specifier =
ModuleSpecifier::resolve_url_or_path("https://deno.land/x/a.ts").unwrap();
let hash_data = vec![b"something".to_vec()];
let c = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
let fixtures = c.join("tests/tsc2");
let handler = Rc::new(RefCell::new(MockSpecifierHandler {
fixtures,
..MockSpecifierHandler::default()
}));
let mut builder = GraphBuilder2::new(handler.clone(), None, None);
builder
.add(&specifier, false)
let actual = test_exec(&specifier)
.await
.expect("module not inserted");
let graph = Rc::new(RefCell::new(builder.get_graph()));
let config = TsConfig::new(json!({
"allowJs": true,
"checkJs": false,
"esModuleInterop": true,
"emitDecoratorMetadata": false,
"incremental": true,
"jsx": "react",
"jsxFactory": "React.createElement",
"jsxFragmentFactory": "React.Fragment",
"lib": ["deno.window"],
"module": "esnext",
"noEmit": true,
"outDir": "deno:///",
"strict": true,
"target": "esnext",
"tsBuildInfoFile": "deno:///.tsbuildinfo",
}));
let request = Request {
config,
debug: false,
graph,
hash_data,
maybe_tsbuildinfo: None,
root_names: vec![(specifier, MediaType::TypeScript)],
};
let actual = exec(js::compiler_isolate_init(), request)
.expect("exec should have not errored");
assert!(actual.diagnostics.0.is_empty());
.expect("exec should not have errored");
assert!(actual.diagnostics.is_empty());
assert!(actual.emitted_files.is_empty());
assert!(actual.maybe_tsbuildinfo.is_some());
assert_eq!(actual.stats.0.len(), 12);
Expand All @@ -654,49 +705,22 @@ mod tests {
async fn test_exec_reexport_dts() {
let specifier =
ModuleSpecifier::resolve_url_or_path("file:///reexports.ts").unwrap();
let hash_data = vec![b"something".to_vec()];
let c = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
let fixtures = c.join("tests/tsc2");
let handler = Rc::new(RefCell::new(MockSpecifierHandler {
fixtures,
..MockSpecifierHandler::default()
}));
let mut builder = GraphBuilder2::new(handler.clone(), None, None);
builder
.add(&specifier, false)
let actual = test_exec(&specifier)
.await
.expect("module not inserted");
let graph = Rc::new(RefCell::new(builder.get_graph()));
let config = TsConfig::new(json!({
"allowJs": true,
"checkJs": false,
"esModuleInterop": true,
"emitDecoratorMetadata": false,
"incremental": true,
"jsx": "react",
"jsxFactory": "React.createElement",
"jsxFragmentFactory": "React.Fragment",
"lib": ["deno.window"],
"module": "esnext",
"noEmit": true,
"outDir": "deno:///",
"strict": true,
"target": "esnext",
"tsBuildInfoFile": "deno:///.tsbuildinfo",
}));
let request = Request {
config,
debug: false,
graph,
hash_data,
maybe_tsbuildinfo: None,
root_names: vec![(specifier, MediaType::TypeScript)],
};
let actual = exec(js::compiler_isolate_init(), request)
.expect("exec should have not errored");
assert!(actual.diagnostics.0.is_empty());
.expect("exec should not have errored");
assert!(actual.diagnostics.is_empty());
assert!(actual.emitted_files.is_empty());
assert!(actual.maybe_tsbuildinfo.is_some());
assert_eq!(actual.stats.0.len(), 12);
}

#[tokio::test]
async fn fix_lib_ref() {
let specifier =
ModuleSpecifier::resolve_url_or_path("file:///libref.ts").unwrap();
let actual = test_exec(&specifier)
.await
.expect("exec should not have errored");
assert!(actual.diagnostics.is_empty());
}
}