// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. use std::collections::HashSet; use deno_config::deno_json::TsConfigForEmit; use deno_core::serde_json; use deno_semver::jsr::JsrDepPackageReq; use deno_semver::jsr::JsrPackageReqReference; use deno_semver::npm::NpmPackageReqReference; #[cfg(test)] // happens to only be used by the tests at the moment pub struct DenoConfigFsAdapter<'a>( pub &'a dyn deno_runtime::deno_fs::FileSystem, ); #[cfg(test)] impl<'a> deno_config::fs::DenoConfigFs for DenoConfigFsAdapter<'a> { fn read_to_string_lossy( &self, path: &std::path::Path, ) -> Result, std::io::Error> { self .0 .read_text_file_lossy_sync(path, None) .map_err(|err| err.into_io_error()) } fn stat_sync( &self, path: &std::path::Path, ) -> Result { self .0 .stat_sync(path) .map(|stat| deno_config::fs::FsMetadata { is_file: stat.is_file, is_directory: stat.is_directory, is_symlink: stat.is_symlink, }) .map_err(|err| err.into_io_error()) } fn read_dir( &self, path: &std::path::Path, ) -> Result, std::io::Error> { self .0 .read_dir_sync(path) .map_err(|err| err.into_io_error()) .map(|entries| { entries .into_iter() .map(|e| deno_config::fs::FsDirEntry { path: path.join(e.name), metadata: deno_config::fs::FsMetadata { is_file: e.is_file, is_directory: e.is_directory, is_symlink: e.is_symlink, }, }) .collect() }) } } pub fn deno_json_deps( config: &deno_config::deno_json::ConfigFile, ) -> HashSet { let values = imports_values(config.json.imports.as_ref()) .into_iter() .chain(scope_values(config.json.scopes.as_ref())); let mut set = values_to_set(values); if let Some(serde_json::Value::Object(compiler_options)) = &config.json.compiler_options { // add jsxImportSource if let Some(serde_json::Value::String(value)) = compiler_options.get("jsxImportSource") { if let Some(dep_req) = value_to_dep_req(value) { set.insert(dep_req); } } // add jsxImportSourceTypes if let Some(serde_json::Value::String(value)) = compiler_options.get("jsxImportSourceTypes") { if let Some(dep_req) = value_to_dep_req(value) { set.insert(dep_req); } } // add the dependencies in the types array if let Some(serde_json::Value::Array(types)) = compiler_options.get("types") { for value in types { if let serde_json::Value::String(value) = value { if let Some(dep_req) = value_to_dep_req(value) { set.insert(dep_req); } } } } } set } fn imports_values(value: Option<&serde_json::Value>) -> Vec<&String> { let Some(obj) = value.and_then(|v| v.as_object()) else { return Vec::new(); }; let mut items = Vec::with_capacity(obj.len()); for value in obj.values() { if let serde_json::Value::String(value) = value { items.push(value); } } items } fn scope_values(value: Option<&serde_json::Value>) -> Vec<&String> { let Some(obj) = value.and_then(|v| v.as_object()) else { return Vec::new(); }; obj.values().flat_map(|v| imports_values(Some(v))).collect() } fn values_to_set<'a>( values: impl Iterator, ) -> HashSet { let mut entries = HashSet::new(); for value in values { if let Some(dep_req) = value_to_dep_req(value) { entries.insert(dep_req); } } entries } fn value_to_dep_req(value: &str) -> Option { if let Ok(req_ref) = JsrPackageReqReference::from_str(value) { Some(JsrDepPackageReq::jsr(req_ref.into_inner().req)) } else if let Ok(req_ref) = NpmPackageReqReference::from_str(value) { Some(JsrDepPackageReq::npm(req_ref.into_inner().req)) } else { None } } pub fn check_warn_tsconfig(ts_config: &TsConfigForEmit) { if let Some(ignored_options) = &ts_config.maybe_ignored_options { log::warn!("{}", ignored_options); } let serde_json::Value::Object(obj) = &ts_config.ts_config.0 else { return; }; if obj.get("experimentalDecorators") == Some(&serde_json::Value::Bool(true)) { log::warn!( "{} experimentalDecorators compiler option is deprecated and may be removed at any time", deno_runtime::colors::yellow("Warning"), ); } }