diff --git a/cli/dts/lib.deno.unstable.d.ts b/cli/dts/lib.deno.unstable.d.ts index 78a7e79c2e9239..6eb39c21c4a20b 100644 --- a/cli/dts/lib.deno.unstable.d.ts +++ b/cli/dts/lib.deno.unstable.d.ts @@ -303,9 +303,6 @@ declare namespace Deno { /** Provide full support for iterables in `for..of`, spread and * destructuring when targeting ES5 or ES3. Defaults to `false`. */ downlevelIteration?: boolean; - /** Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. - * Defaults to `false`. */ - emitBOM?: boolean; /** Only emit `.d.ts` declaration files. Defaults to `false`. */ emitDeclarationOnly?: boolean; /** Emit design-type metadata for decorated declarations in source. See issue @@ -316,8 +313,11 @@ declare namespace Deno { * ecosystem compatibility and enable `allowSyntheticDefaultImports` for type * system compatibility. Defaults to `true`. */ esModuleInterop?: boolean; - /** Enables experimental support for ES decorators. Defaults to `false`. */ + /** Enables experimental support for ES decorators. Defaults to `true`. */ experimentalDecorators?: boolean; + /** Import emit helpers (e.g. `__extends`, `__rest`, etc..) from + * [tslib](https://www.npmjs.com/package/tslib). */ + importHelpers?: boolean; /** Emit a single file with source maps instead of having a separate file. * Defaults to `false`. */ inlineSourceMap?: boolean; @@ -325,7 +325,7 @@ declare namespace Deno { * `inlineSourceMap` or `sourceMap` to be set. Defaults to `false`. */ inlineSources?: boolean; /** Perform additional checks to ensure that transpile only would be safe. - * Defaults to `false`. */ + * Defaults to `true`. */ isolatedModules?: boolean; /** Support JSX in `.tsx` files: `"react"`, `"preserve"`, `"react-native"`. * Defaults to `"react"`. */ @@ -333,12 +333,12 @@ declare namespace Deno { /** Specify the JSX factory function to use when targeting react JSX emit, * e.g. `React.createElement` or `h`. Defaults to `React.createElement`. */ jsxFactory?: string; + /** Specify the JSX fragment factory function to use when targeting react + * JSX emit, e.g. `Fragment`. Defaults to `React.Fragment`. */ + jsxFragmentFactory?: string; /** Resolve keyof to string valued property names only (no numbers or * symbols). Defaults to `false`. */ keyofStringsOnly?: string; - /** Emit class fields with ECMAScript-standard semantics. Defaults to `false`. - */ - useDefineForClassFields?: boolean; /** List of library files to be included in the compilation. If omitted, * then the Deno main runtime libs are used. */ lib?: string[]; @@ -389,10 +389,6 @@ declare namespace Deno { noUnusedLocals?: boolean; /** Report errors on unused parameters. Defaults to `false`. */ noUnusedParameters?: boolean; - /** Redirect output structure to the directory. This only impacts - * `Deno.compile` and only changes the emitted file names. Defaults to - * `undefined`. */ - outDir?: string; /** List of path mapping entries for module names to locations relative to the * `baseUrl`. Defaults to `undefined`. */ paths?: Record; @@ -402,8 +398,6 @@ declare namespace Deno { /** Remove all comments except copy-right header comments beginning with * `/*!`. Defaults to `true`. */ removeComments?: boolean; - /** Include modules imported with `.json` extension. Defaults to `true`. */ - resolveJsonModule?: boolean; /** Specifies the root directory of input files. Only use to control the * output directory structure with `outDir`. Defaults to `undefined`. */ rootDir?: string; @@ -418,6 +412,8 @@ declare namespace Deno { * specified will be embedded in the sourceMap to direct the debugger where * the source files will be located. Defaults to `undefined`. */ sourceRoot?: string; + /** Skip type checking of all declaration files (`*.d.ts`). */ + skipLibCheck?: boolean; /** Enable all strict type checking options. Enabling `strict` enables * `noImplicitAny`, `noImplicitThis`, `alwaysStrict`, `strictBindCallApply`, * `strictNullChecks`, `strictFunctionTypes` and @@ -472,6 +468,9 @@ declare namespace Deno { * ``` */ types?: string[]; + /** Emit class fields with ECMAScript-standard semantics. Defaults to + * `false`. */ + useDefineForClassFields?: boolean; } /** **UNSTABLE**: new API, yet to be vetted. diff --git a/cli/main.rs b/cli/main.rs index 7d32467be30708..dc68546d58c8b6 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -346,21 +346,20 @@ async fn bundle_command( module_graph2::TypeLib::DenoWindow }; let graph = graph.clone(); - let (stats, diagnostics, maybe_ignored_options) = - graph.check(module_graph2::CheckOptions { - debug, - emit: false, - lib, - maybe_config_path: flags.config_path.clone(), - reload: flags.reload, - })?; - - debug!("{}", stats); - if let Some(ignored_options) = maybe_ignored_options { + let result_info = graph.check(module_graph2::CheckOptions { + debug, + emit: false, + lib, + maybe_config_path: flags.config_path.clone(), + reload: flags.reload, + })?; + + debug!("{}", result_info.stats); + if let Some(ignored_options) = result_info.maybe_ignored_options { eprintln!("{}", ignored_options); } - if !diagnostics.is_empty() { - return Err(generic_error(diagnostics.to_string())); + if !result_info.diagnostics.is_empty() { + return Err(generic_error(result_info.diagnostics.to_string())); } } diff --git a/cli/media_type.rs b/cli/media_type.rs index c837553eec7e9c..cb26bcff5b7d17 100644 --- a/cli/media_type.rs +++ b/cli/media_type.rs @@ -63,7 +63,17 @@ impl<'a> From<&'a String> for MediaType { impl<'a> From<&'a ModuleSpecifier> for MediaType { fn from(specifier: &'a ModuleSpecifier) -> Self { - MediaType::from_path(&specifier.to_path()) + let url = specifier.as_url(); + let path = if url.scheme() == "file" { + if let Ok(path) = url.to_file_path() { + path + } else { + PathBuf::from(url.path()) + } + } else { + PathBuf::from(url.path()) + }; + MediaType::from_path(&path) } } diff --git a/cli/module_graph2.rs b/cli/module_graph2.rs index 55c10a569478e6..6ac27906d0d030 100644 --- a/cli/module_graph2.rs +++ b/cli/module_graph2.rs @@ -22,8 +22,7 @@ use crate::specifier_handler::DependencyMap; use crate::specifier_handler::Emit; use crate::specifier_handler::FetchFuture; use crate::specifier_handler::SpecifierHandler; -use crate::tsc2::exec; -use crate::tsc2::Request; +use crate::tsc2; use crate::tsc_config::IgnoredCompilerOptions; use crate::tsc_config::TsConfig; use crate::version; @@ -71,16 +70,6 @@ lazy_static! { Regex::new(r#"(?i)\stypes\s*=\s*["']([^"']*)["']"#).unwrap(); } -type EmitResult = Result< - ( - HashMap, - Stats, - Diagnostics, - Option, - ), - AnyError, ->; - /// A group of errors that represent errors that can occur when interacting with /// a module graph. #[derive(Debug, Clone, Eq, PartialEq)] @@ -491,7 +480,7 @@ impl Module { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct Stats(pub Vec<(String, u128)>); impl<'de> Deserialize<'de> for Stats { @@ -515,6 +504,23 @@ impl fmt::Display for Stats { } } +/// A structure that provides information about a module graph result. +#[derive(Debug, Default)] +pub struct ResultInfo { + /// A structure which provides diagnostic information (usually from `tsc`) + /// about the code in the module graph. + pub diagnostics: Diagnostics, + /// Optionally ignored compiler options that represent any options that were + /// ignored if there was a user provided configuration. + pub maybe_ignored_options: Option, + /// A structure providing key metrics around the operation performed, in + /// milliseconds. + pub stats: Stats, +} + +/// Represents the "default" type library that should be used when type +/// checking the code in the module graph. Note that a user provided config +/// of `"lib"` would override this value. #[derive(Debug, Clone, Eq, PartialEq)] pub enum TypeLib { DenoWindow, @@ -550,7 +556,11 @@ impl Serialize for TypeLib { #[derive(Debug, Default)] pub struct BundleOptions { + /// If `true` then debug logging will be output from the isolate. pub debug: bool, + /// An optional string that points to a user supplied TypeScript configuration + /// file that augments the the default configuration passed to the TypeScript + /// compiler. pub maybe_config_path: Option, } @@ -698,11 +708,7 @@ impl Graph2 { } /// Type check the module graph, corresponding to the options provided. - pub fn check( - self, - options: CheckOptions, - ) -> Result<(Stats, Diagnostics, Option), AnyError> - { + pub fn check(self, options: CheckOptions) -> Result { let mut config = TsConfig::new(json!({ "allowJs": true, // TODO(@kitsonk) is this really needed? @@ -746,11 +752,10 @@ impl Graph2 { && (!options.reload || self.roots_dynamic)) { debug!("graph does not need to be checked or emitted."); - return Ok(( - Stats(Vec::new()), - Diagnostics::default(), + return Ok(ResultInfo { maybe_ignored_options, - )); + ..Default::default() + }); } // TODO(@kitsonk) not totally happy with this here, but this is the first @@ -767,9 +772,9 @@ impl Graph2 { vec![config.as_bytes(), version::DENO.as_bytes().to_owned()]; let graph = Rc::new(RefCell::new(self)); - let response = exec( + let response = tsc2::exec( js::compiler_isolate_init(), - Request { + tsc2::Request { config: config.clone(), debug: options.debug, graph: graph.clone(), @@ -827,7 +832,11 @@ impl Graph2 { } graph.flush()?; - Ok((response.stats, response.diagnostics, maybe_ignored_options)) + Ok(ResultInfo { + diagnostics: response.diagnostics, + maybe_ignored_options, + stats: response.stats, + }) } fn contains_module(&self, specifier: &ModuleSpecifier) -> bool { @@ -835,7 +844,14 @@ impl Graph2 { self.modules.contains_key(s) } - pub fn emit(self, options: EmitOptions) -> EmitResult { + /// Emit the module graph in a specific format. This is specifically designed + /// to be an "all-in-one" API for access by the runtime, allowing both + /// emitting single modules as well as bundles, using Deno module resolution + /// or supplied sources. + pub fn emit( + self, + options: EmitOptions, + ) -> Result<(HashMap, ResultInfo), AnyError> { let mut config = TsConfig::new(json!({ "allowJs": true, // TODO(@kitsonk) consider enabling this by default @@ -877,9 +893,9 @@ impl Graph2 { vec![config.as_bytes(), version::DENO.as_bytes().to_owned()]; let graph = Rc::new(RefCell::new(self)); - let response = exec( + let response = tsc2::exec( js::compiler_isolate_init(), - Request { + tsc2::Request { config: config.clone(), debug: options.debug, graph: graph.clone(), @@ -932,12 +948,15 @@ impl Graph2 { Ok(( emitted_files, - response.stats, - response.diagnostics, - maybe_ignored_options, + ResultInfo { + diagnostics: response.diagnostics, + maybe_ignored_options, + stats: response.stats, + }, )) } + /// Shared between `bundle()` and `emit()`. fn emit_bundle( &self, specifier: &ModuleSpecifier, @@ -1116,8 +1135,8 @@ impl Graph2 { self.modules.get_mut(s) } - /// Consume graph and return list of all module specifiers - /// contained in the graph. + /// Consume graph and return list of all module specifiers contained in the + /// graph. pub fn get_modules(&self) -> Vec { self.modules.keys().map(|s| s.to_owned()).collect() } @@ -1870,7 +1889,7 @@ pub mod tests { ModuleSpecifier::resolve_url_or_path("file:///tests/main.ts") .expect("could not resolve module"); let (graph, handler) = setup(specifier).await; - let (stats, diagnostics, maybe_ignored_options) = graph + let result_info = graph .check(CheckOptions { debug: false, emit: true, @@ -1879,9 +1898,9 @@ pub mod tests { reload: false, }) .expect("should have checked"); - assert!(maybe_ignored_options.is_none()); - assert_eq!(stats.0.len(), 12); - assert!(diagnostics.is_empty()); + assert!(result_info.maybe_ignored_options.is_none()); + assert_eq!(result_info.stats.0.len(), 12); + assert!(result_info.diagnostics.is_empty()); let h = handler.borrow(); assert_eq!(h.cache_calls.len(), 2); assert_eq!(h.tsbuildinfo_calls.len(), 1); @@ -1893,7 +1912,7 @@ pub mod tests { ModuleSpecifier::resolve_url_or_path("file:///tests/main.ts") .expect("could not resolve module"); let (graph, handler) = setup(specifier).await; - let (stats, diagnostics, maybe_ignored_options) = graph + let result_info = graph .check(CheckOptions { debug: false, emit: false, @@ -1902,9 +1921,9 @@ pub mod tests { reload: false, }) .expect("should have checked"); - assert!(maybe_ignored_options.is_none()); - assert_eq!(stats.0.len(), 12); - assert!(diagnostics.is_empty()); + assert!(result_info.maybe_ignored_options.is_none()); + assert_eq!(result_info.stats.0.len(), 12); + assert!(result_info.diagnostics.is_empty()); let h = handler.borrow(); assert_eq!(h.cache_calls.len(), 0); assert_eq!(h.tsbuildinfo_calls.len(), 1); @@ -1916,7 +1935,7 @@ pub mod tests { ModuleSpecifier::resolve_url_or_path("file:///tests/checkwithconfig.ts") .expect("could not resolve module"); let (graph, handler) = setup(specifier.clone()).await; - let (_, diagnostics, maybe_ignored_options) = graph + let result_info = graph .check(CheckOptions { debug: false, emit: true, @@ -1927,8 +1946,8 @@ pub mod tests { reload: true, }) .expect("should have checked"); - assert!(maybe_ignored_options.is_none()); - assert!(diagnostics.is_empty()); + assert!(result_info.maybe_ignored_options.is_none()); + assert!(result_info.diagnostics.is_empty()); let h = handler.borrow(); assert_eq!(h.version_calls.len(), 2); let ver0 = h.version_calls[0].1.clone(); @@ -1936,7 +1955,7 @@ pub mod tests { // let's do it all over again to ensure that the versions are determinstic let (graph, handler) = setup(specifier).await; - let (_, diagnostics, maybe_ignored_options) = graph + let result_info = graph .check(CheckOptions { debug: false, emit: true, @@ -1947,8 +1966,8 @@ pub mod tests { reload: true, }) .expect("should have checked"); - assert!(maybe_ignored_options.is_none()); - assert!(diagnostics.is_empty()); + assert!(result_info.maybe_ignored_options.is_none()); + assert!(result_info.diagnostics.is_empty()); let h = handler.borrow(); assert_eq!(h.version_calls.len(), 2); assert!(h.version_calls[0].1 == ver0 || h.version_calls[0].1 == ver1); @@ -1973,15 +1992,15 @@ pub mod tests { ), ) .await; - let (emitted_files, _, diagnostics, maybe_ignored_options) = graph + let (emitted_files, result_info) = graph .emit(EmitOptions { bundle_type: BundleType::None, debug: false, maybe_user_config: None, }) .expect("should have emitted"); - assert!(diagnostics.is_empty()); - assert!(maybe_ignored_options.is_none()); + assert!(result_info.diagnostics.is_empty()); + assert!(result_info.maybe_ignored_options.is_none()); assert_eq!(emitted_files.len(), 4); let out_a = emitted_files.get("file:///a.ts.js"); assert!(out_a.is_some()); @@ -2013,15 +2032,15 @@ pub mod tests { ), ) .await; - let (emitted_files, _, diagnostics, maybe_ignored_options) = graph + let (emitted_files, result_info) = graph .emit(EmitOptions { bundle_type: BundleType::Esm, debug: false, maybe_user_config: None, }) .expect("should have emitted"); - assert!(diagnostics.is_empty()); - assert!(maybe_ignored_options.is_none()); + assert!(result_info.diagnostics.is_empty()); + assert!(result_info.maybe_ignored_options.is_none()); assert_eq!(emitted_files.len(), 1); let actual = emitted_files.get("deno:///bundle.js"); assert!(actual.is_some()); diff --git a/cli/ops/runtime_compiler.rs b/cli/ops/runtime_compiler.rs index e4f7d2180d3fe7..02d09337549063 100644 --- a/cli/ops/runtime_compiler.rs +++ b/cli/ops/runtime_compiler.rs @@ -82,7 +82,7 @@ async fn op_compile( } else { None }; - let (emitted_files, _, diagnostics, _) = graph.emit(EmitOptions { + let (emitted_files, result_info) = graph.emit(EmitOptions { bundle_type, debug, maybe_user_config, @@ -90,7 +90,7 @@ async fn op_compile( Ok(json!({ "emittedFiles": emitted_files, - "diagnostics": diagnostics, + "diagnostics": result_info.diagnostics, })) } diff --git a/cli/program_state.rs b/cli/program_state.rs index 06e6622a001501..027bbc7926c693 100644 --- a/cli/program_state.rs +++ b/cli/program_state.rs @@ -148,21 +148,20 @@ impl ProgramState { eprintln!("{}", ignored_options); } } else { - let (stats, diagnostics, maybe_ignored_options) = - graph.check(CheckOptions { - debug, - emit: true, - lib, - maybe_config_path, - reload: self.flags.reload, - })?; + let result_info = graph.check(CheckOptions { + debug, + emit: true, + lib, + maybe_config_path, + reload: self.flags.reload, + })?; - debug!("{}", stats); - if let Some(ignored_options) = maybe_ignored_options { + debug!("{}", result_info.stats); + if let Some(ignored_options) = result_info.maybe_ignored_options { eprintln!("{}", ignored_options); } - if !diagnostics.is_empty() { - return Err(generic_error(diagnostics.to_string())); + if !result_info.diagnostics.is_empty() { + return Err(generic_error(result_info.diagnostics.to_string())); } }; diff --git a/cli/tsc_config.rs b/cli/tsc_config.rs index a798556cbf4203..92332cca6736fa 100644 --- a/cli/tsc_config.rs +++ b/cli/tsc_config.rs @@ -52,8 +52,10 @@ impl fmt::Display for IgnoredCompilerOptions { /// A static slice of all the compiler options that should be ignored that /// either have no effect on the compilation or would cause the emit to not work /// in Deno. -const IGNORED_COMPILER_OPTIONS: [&str; 20] = [ +const IGNORED_COMPILER_OPTIONS: &[&str] = &[ "allowSyntheticDefaultImports", + "allowUmdGlobalAccess", + "baseUrl", "declaration", "declarationMap", "downlevelIteration", @@ -66,23 +68,28 @@ const IGNORED_COMPILER_OPTIONS: [&str; 20] = [ "module", "noEmitHelpers", "noLib", + "noResolve", + "outDir", + "paths", "preserveConstEnums", "reactNamespace", - "skipDefaultLibCheck", + "rootDir", + "rootDirs", "skipLibCheck", "sourceMap", + "sourceRoot", "target", "types", "useDefineForClassFields", ]; -const IGNORED_RUNTIME_COMPILER_OPTIONS: [&str; 40] = [ - "allowUmdGlobalAccess", +const IGNORED_RUNTIME_COMPILER_OPTIONS: &[&str] = &[ "assumeChangesOnlyAffectDirectDependencies", - "baseUrl", "build", + "charset", "composite", "diagnostics", + "disableSizeLimit", "emitBOM", "extendedDiagnostics", "forceConsistentCasingInFileNames", @@ -98,19 +105,16 @@ const IGNORED_RUNTIME_COMPILER_OPTIONS: [&str; 40] = [ "newLine", "noEmit", "noEmitOnError", - "noResolve", "out", "outDir", "outFile", - "paths", "preserveSymlinks", "preserveWatchOutput", "pretty", + "project", "resolveJsonModule", - "rootDir", - "rootDirs", "showConfig", - "sourceRoot", + "skipDefaultLibCheck", "stripInternal", "traceResolution", "tsBuildInfoFile", diff --git a/core/module_specifier.rs b/core/module_specifier.rs index b8668263635b3d..82452c0677445b 100644 --- a/core/module_specifier.rs +++ b/core/module_specifier.rs @@ -65,18 +65,6 @@ impl ModuleSpecifier { self.0.as_str() } - pub fn to_path(&self) -> PathBuf { - if self.0.scheme() == "file" { - if let Ok(path) = self.0.to_file_path() { - path - } else { - PathBuf::from(self.0.path()) - } - } else { - PathBuf::from(self.0.path()) - } - } - /// Resolves module using this algorithm: /// https://html.spec.whatwg.org/multipage/webappapis.html#resolve-a-module-specifier pub fn resolve_import(