diff --git a/codex-rs/app-server-protocol/src/export.rs b/codex-rs/app-server-protocol/src/export.rs index b89f23c666..8821477fd8 100644 --- a/codex-rs/app-server-protocol/src/export.rs +++ b/codex-rs/app-server-protocol/src/export.rs @@ -179,6 +179,12 @@ pub fn generate_ts_with_options( } } + if !ts_files.is_empty() { + for file in &ts_files { + normalize_typescript_whitespace_in_file(file)?; + } + } + Ok(()) } @@ -1907,6 +1913,32 @@ fn prepend_header_if_missing(path: &Path) -> Result<()> { Ok(()) } +fn normalize_typescript_whitespace_in_file(path: &Path) -> Result<()> { + let content = + fs::read_to_string(path).with_context(|| format!("Failed to read {}", path.display()))?; + let normalized = normalize_typescript_whitespace(&content); + if normalized == content { + return Ok(()); + } + + fs::write(path, normalized).with_context(|| format!("Failed to write {}", path.display()))?; + Ok(()) +} + +pub(crate) fn normalize_typescript_whitespace(content: &str) -> String { + let mut normalized = String::with_capacity(content.len()); + for line in content.lines() { + normalized.push_str(line.trim_end()); + normalized.push('\n'); + } + + if !content.ends_with('\n') { + normalized.pop(); + } + + normalized +} + fn ts_files_in(dir: &Path) -> Result> { let mut files = Vec::new(); for entry in diff --git a/codex-rs/app-server-protocol/src/schema_fixtures.rs b/codex-rs/app-server-protocol/src/schema_fixtures.rs index 56dcf33a4d..7319a0b414 100644 --- a/codex-rs/app-server-protocol/src/schema_fixtures.rs +++ b/codex-rs/app-server-protocol/src/schema_fixtures.rs @@ -5,6 +5,7 @@ use crate::ServerRequest; use crate::export::GENERATED_TS_HEADER; use crate::export::filter_experimental_ts_tree; use crate::export::generate_index_ts_tree; +use crate::export::normalize_typescript_whitespace; use crate::protocol::common::visit_client_response_types; use crate::protocol::common::visit_server_response_types; use anyhow::Context; @@ -140,7 +141,7 @@ fn read_file_bytes(path: &Path) -> Result> { .strip_prefix(GENERATED_TS_HEADER) .unwrap_or(&text) .to_string(); - return Ok(text.into_bytes()); + return Ok(normalize_typescript_whitespace(&text).into_bytes()); } Ok(bytes) } @@ -278,7 +279,7 @@ fn collect_typescript_fixture_file( let output_path = normalize_relative_fixture_path(&output_path); files.insert( output_path, - contents.replace("\r\n", "\n").replace('\r', "\n"), + normalize_typescript_whitespace(&contents.replace("\r\n", "\n").replace('\r', "\n")), ); let mut visitor = TypeScriptFixtureCollector {