#![cfg(feature = "typescript")]
pub mod common;
use std::sync::Arc;
use facet::Facet;
use facet_generate::generation::{
CodeGeneratorConfig, SourceInstaller, bincode::BincodePlugin, plugin::EmitterPlugin, typescript,
};
use facet_generate::reflection::RegistryBuilder;
use serde_json::Value;
use std::{collections::BTreeMap, fs::File, path::Path};
use tempfile::tempdir;
fn test_typescript_code_generates_with_config(
dir_path: &Path,
config: &CodeGeneratorConfig,
plugins: Vec<Arc<dyn EmitterPlugin<typescript::TypeScript>>>,
) -> std::path::PathBuf {
let registry = common::get_registry();
std::fs::create_dir_all(dir_path.join("testing")).unwrap_or(());
let mut installer = typescript::Installer::new("testing", dir_path);
installer.install_serde_runtime().unwrap();
let source_path = dir_path.join("testing").join("test.ts");
let mut source = File::create(&source_path).unwrap();
let generator = typescript::TypeScriptCodeGenerator::new(config).with_plugins(plugins);
generator.output(&mut source, ®istry).unwrap();
dir_path.join("testing")
}
#[test]
fn test_typescript_code_generates_with_bincode() {
let dir = tempdir().unwrap();
let config = CodeGeneratorConfig::new("testing".to_string());
test_typescript_code_generates_with_config(dir.path(), &config, vec![Arc::new(BincodePlugin)]);
}
#[test]
fn test_typescript_code_generates_with_comments() {
#[derive(Facet)]
struct CommentedType {
value: String,
}
let dir = tempdir().unwrap();
let registry = RegistryBuilder::new()
.add_type::<CommentedType>()
.unwrap()
.build()
.unwrap();
let config = CodeGeneratorConfig::new("testing".to_string());
let source_path = dir.path().join("testing");
std::fs::create_dir_all(&source_path).unwrap();
let source_file = source_path.join("test.ts");
let mut file = File::create(&source_file).unwrap();
let generator = typescript::TypeScriptCodeGenerator::new(&config);
generator.output(&mut file, ®istry).unwrap();
let content = std::fs::read_to_string(&source_file).unwrap();
assert!(
content.contains("/// Some\n/// comments\n"),
"Doc comments should be present in output:\n{content}"
);
}
#[test]
fn test_typescript_code_generates_with_external_definitions() {
let dir = tempdir().unwrap();
std::fs::create_dir_all(dir.path().join("external")).unwrap_or(());
std::fs::write(
dir.path().join("external/index.ts"),
"export const CustomType = 5;",
)
.unwrap();
let mut external_definitions = BTreeMap::new();
external_definitions.insert(String::from("external"), vec![String::from("CustomType")]);
let config = CodeGeneratorConfig::new("testing".to_string())
.with_external_definitions(external_definitions);
test_typescript_code_generates_with_config(dir.path(), &config, vec![]);
}
#[test]
fn test_typescript_manifest_generation() {
let dir = tempdir().unwrap();
let installer = typescript::Installer::new("my-typescript-package", dir.path());
installer.install_manifest("my-typescript-package").unwrap();
let manifest_path = dir.path().join("package.json");
assert!(manifest_path.exists());
let manifest_content = std::fs::read_to_string(&manifest_path).unwrap();
let manifest: Value = serde_json::from_str(&manifest_content).unwrap();
assert_eq!(manifest["name"], "my-typescript-package");
assert_eq!(manifest["version"], "0.1.0");
assert_eq!(manifest["devDependencies"]["typescript"], "^5.8.3");
}
#[test]
fn test_typescript_code_generation_file_layout() {
let dir = tempdir().unwrap();
let registry = common::get_registry();
let config = CodeGeneratorConfig::new("testing".to_string());
let mut installer = typescript::Installer::new("testing", dir.path()).plugin(BincodePlugin);
installer.install_module(&config, ®istry).unwrap();
installer.install_serde_runtime().unwrap();
installer.install_bincode_runtime().unwrap();
let module_path = dir.path().join("testing.ts");
assert!(module_path.exists());
let content = std::fs::read_to_string(&module_path).unwrap();
assert!(content.contains(r#"from "./serde""#));
assert!(!content.contains(r#"from "./serde/mod.ts""#));
let serde_index = dir.path().join("serde").join("index.ts");
assert!(serde_index.exists());
let serde_content = std::fs::read_to_string(&serde_index).unwrap();
assert!(serde_content.contains("from \"./types\""));
assert!(!serde_content.contains("from \"./types.ts\""));
let binary_deserializer = dir.path().join("serde").join("binaryDeserializer.ts");
assert!(binary_deserializer.exists());
let binary_deserializer_content = std::fs::read_to_string(&binary_deserializer).unwrap();
assert!(binary_deserializer_content.contains("from \"./deserializer\""));
assert!(!binary_deserializer_content.contains("from \"./deserializer.ts\""));
}