diff --git a/src/deno_json/mod.rs b/src/deno_json/mod.rs index 8ac2d5f..bd772f4 100644 --- a/src/deno_json/mod.rs +++ b/src/deno_json/mod.rs @@ -594,6 +594,7 @@ impl NodeModulesDirMode { #[serde(rename_all = "camelCase")] pub struct ConfigFileJson { pub compiler_options: Option, + pub runtime: Option>, pub import_map: Option, pub imports: Option, pub scopes: Option, @@ -914,16 +915,76 @@ impl ConfigFile { /// Parse `compilerOptions` and return a serde `Value`. /// The result also contains any options that were ignored. pub fn to_compiler_options(&self) -> Result { - if let Some(compiler_options) = self.json.compiler_options.clone() { - let options: serde_json::Map = - serde_json::from_value(compiler_options) - .context("compilerOptions should be an object")?; + let compiler_options_exists = self.json.compiler_options.is_some(); + let runtime_exists = self.json.runtime.is_some(); + + if compiler_options_exists || runtime_exists { + let mut options: serde_json::Map = + if let Some(compiler_options) = self.json.compiler_options.clone() { + serde_json::from_value(compiler_options) + .context("compilerOptions should be an object")? + } else { + serde_json::Map::new() + }; + + if runtime_exists { + self.resolve_runtime_libs(&mut options); + } + parse_compiler_options(options, Some(&self.specifier)) } else { Ok(Default::default()) } } + /// Resolves and updates the `lib` field in `compilerOptions` based on the `runtime` configuration. + fn resolve_runtime_libs(&self, options: &mut serde_json::Map) { + if let Some(runtime) = self.json.runtime.clone() { + let contains_deno = runtime.contains(&"deno".to_string()); + let contains_browser = runtime.contains(&"browser".to_string()); + + if contains_deno && contains_browser { + self.insert_libs( + options, + vec![ + "deno.ns".to_string(), + "esnext".to_string(), + "dom".to_string(), + "dom.iterable".to_string(), + ], + ); + } else if contains_deno { + self.insert_libs(options, vec!["deno.ns".to_string()]); + } else if contains_browser { + self.insert_libs( + options, + vec![ + "esnext".to_string(), + "dom".to_string(), + "dom.iterable".to_string(), + ], + ); + } + } + } + + /// Inserts the values into the `lib` field of `compilerOptions`. + fn insert_libs( + &self, + options: &mut serde_json::Map, + libs: Vec, + ) { + let lib_array = options + .entry("lib".to_string()) + .or_insert(Value::Array(Vec::new())) // Ensure "lib" key exists as an array + .as_array_mut() + .unwrap(); + + for lib in libs { + lib_array.push(Value::String(lib)); + } + } + pub fn to_import_map_path(&self) -> Result, AnyError> { let Some(value) = self.json.import_map.as_ref() else { return Ok(None); @@ -1705,6 +1766,7 @@ mod tests { // comments are allowed "strict": true }, + "runtime": ["deno", "browser"], "lint": { "include": ["src/"], "exclude": ["src/testdata/"], @@ -1741,7 +1803,8 @@ mod tests { maybe_ignored, } = config_file.to_compiler_options().unwrap(); assert!(options.contains_key("strict")); - assert_eq!(options.len(), 1); + assert!(options.contains_key("lib")); + assert_eq!(options.len(), 2); assert_eq!( maybe_ignored, Some(IgnoredCompilerOptions {