1use std::fs;
7use std::path::Path;
8
9const OTTER_TYPES: &str = include_str!("types/otter.d.ts");
11
12const NODE_BUFFER_TYPES: &str = include_str!("types/node/buffer.d.ts");
14
15const NODE_FS_TYPES: &str = include_str!("types/node/fs.d.ts");
17
18const NODE_PATH_TYPES: &str = include_str!("types/node/path.d.ts");
20
21const NODE_TEST_TYPES: &str = include_str!("types/node/test.d.ts");
23
24pub fn install_bundled_types(node_modules: &Path) -> Result<(), TypesError> {
26 install_otter_types(node_modules)?;
28
29 install_node_types(node_modules)?;
31
32 Ok(())
33}
34
35fn install_otter_types(node_modules: &Path) -> Result<(), TypesError> {
37 let types_dir = node_modules.join("@types").join("otter");
38 fs::create_dir_all(&types_dir).map_err(|e| TypesError::Io(e.to_string()))?;
39
40 fs::write(types_dir.join("index.d.ts"), OTTER_TYPES)
42 .map_err(|e| TypesError::Io(e.to_string()))?;
43
44 let package_json = r#"{
46 "name": "@types/otter",
47 "version": "0.1.0",
48 "description": "TypeScript definitions for Otter runtime",
49 "types": "index.d.ts",
50 "license": "MIT"
51}"#;
52 fs::write(types_dir.join("package.json"), package_json)
53 .map_err(|e| TypesError::Io(e.to_string()))?;
54
55 Ok(())
56}
57
58fn install_node_types(node_modules: &Path) -> Result<(), TypesError> {
60 let types_dir = node_modules.join("@types").join("node");
61 fs::create_dir_all(&types_dir).map_err(|e| TypesError::Io(e.to_string()))?;
62
63 fs::write(types_dir.join("buffer.d.ts"), NODE_BUFFER_TYPES)
65 .map_err(|e| TypesError::Io(e.to_string()))?;
66
67 fs::write(types_dir.join("fs.d.ts"), NODE_FS_TYPES)
68 .map_err(|e| TypesError::Io(e.to_string()))?;
69
70 fs::write(types_dir.join("path.d.ts"), NODE_PATH_TYPES)
71 .map_err(|e| TypesError::Io(e.to_string()))?;
72
73 fs::write(types_dir.join("test.d.ts"), NODE_TEST_TYPES)
74 .map_err(|e| TypesError::Io(e.to_string()))?;
75
76 let index_dts = r#"/// <reference path="buffer.d.ts" />
78/// <reference path="fs.d.ts" />
79/// <reference path="path.d.ts" />
80/// <reference path="test.d.ts" />
81
82// Re-export modules for direct imports
83export * from "node:buffer";
84export * from "node:fs";
85export * from "node:path";
86export * from "node:test";
87"#;
88 fs::write(types_dir.join("index.d.ts"), index_dts)
89 .map_err(|e| TypesError::Io(e.to_string()))?;
90
91 let package_json = r#"{
93 "name": "@types/node",
94 "version": "0.1.0",
95 "description": "TypeScript definitions for Otter's Node.js compatibility layer",
96 "types": "index.d.ts",
97 "license": "MIT"
98}"#;
99 fs::write(types_dir.join("package.json"), package_json)
100 .map_err(|e| TypesError::Io(e.to_string()))?;
101
102 Ok(())
103}
104
105#[derive(Debug, thiserror::Error)]
106pub enum TypesError {
107 #[error("IO error: {0}")]
108 Io(String),
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114
115 #[test]
116 fn test_bundled_types_not_empty() {
117 assert!(!OTTER_TYPES.is_empty());
118 assert!(!NODE_BUFFER_TYPES.is_empty());
119 assert!(!NODE_FS_TYPES.is_empty());
120 assert!(!NODE_PATH_TYPES.is_empty());
121 }
122
123 #[test]
124 fn test_install_bundled_types() {
125 let temp_dir = std::env::temp_dir().join("otter-types-test");
126 let node_modules = temp_dir.join("node_modules");
127
128 let _ = fs::remove_dir_all(&temp_dir);
130 fs::create_dir_all(&node_modules).unwrap();
131
132 install_bundled_types(&node_modules).unwrap();
134
135 assert!(node_modules.join("@types/otter/index.d.ts").exists());
137 assert!(node_modules.join("@types/otter/package.json").exists());
138
139 assert!(node_modules.join("@types/node/index.d.ts").exists());
141 assert!(node_modules.join("@types/node/fs.d.ts").exists());
142 assert!(node_modules.join("@types/node/buffer.d.ts").exists());
143 assert!(node_modules.join("@types/node/path.d.ts").exists());
144
145 let _ = fs::remove_dir_all(&temp_dir);
147 }
148}