Compare commits

...

4 Commits

Author SHA1 Message Date
Keyan Zhang
2c0e68a98b update 2026-03-11 13:02:37 -07:00
Keyan Zhang
49986a1679 schema 2026-03-11 13:02:37 -07:00
Keyan Zhang
69f6adec3b script 2026-03-11 13:02:37 -07:00
Keyan Zhang
56b60a1790 add TS codegen 2026-03-11 13:02:37 -07:00
4 changed files with 8531 additions and 1 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,104 @@
use std::any::TypeId;
use std::collections::BTreeMap;
use std::collections::HashSet;
use std::error::Error;
use std::path::Path;
use std::path::PathBuf;
use codex_protocol::protocol::RolloutLine;
use ts_rs::TS;
use ts_rs::TypeVisitor;
const GENERATED_TS_HEADER: &str = "// GENERATED CODE! DO NOT MODIFY BY HAND!\n\n";
const TS_RS_NOTE: &str = "// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.\n";
const JSON_SCHEMA_FILENAME: &str = "rollout-line.schema.json";
const TYPESCRIPT_FILENAME: &str = "rollout-line.schema.ts";
fn main() -> Result<(), Box<dyn Error>> {
let out_dir = std::env::args_os()
.nth(1)
.map(PathBuf::from)
.unwrap_or_else(|| PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("generated"));
write_rollout_line_artifacts(&out_dir)
}
fn write_rollout_line_artifacts(out_dir: &Path) -> Result<(), Box<dyn Error>> {
std::fs::create_dir_all(&out_dir)?;
let schema_path = out_dir.join(JSON_SCHEMA_FILENAME);
let schema = schemars::schema_for!(RolloutLine);
let schema_json = serde_json::to_vec_pretty(&schema)?;
std::fs::write(&schema_path, schema_json)?;
let typescript_path = out_dir.join(TYPESCRIPT_FILENAME);
let typescript = generate_typescript_bundle::<RolloutLine>()?;
std::fs::write(&typescript_path, typescript)?;
println!("wrote {}", schema_path.display());
println!("wrote {}", typescript_path.display());
Ok(())
}
fn generate_typescript_bundle<T: TS + 'static + ?Sized>() -> Result<String, Box<dyn Error>> {
let mut declarations = BTreeMap::new();
let mut seen = HashSet::new();
collect_typescript_declarations::<T>(&mut declarations, &mut seen)?;
let body = declarations
.into_values()
.collect::<Vec<_>>()
.join("\n\n")
.replace("\r\n", "\n")
.replace('\r', "\n");
Ok(format!("{GENERATED_TS_HEADER}{TS_RS_NOTE}\n{body}\n"))
}
fn collect_typescript_declarations<T: TS + 'static + ?Sized>(
declarations: &mut BTreeMap<PathBuf, String>,
seen: &mut HashSet<TypeId>,
) -> Result<(), Box<dyn Error>> {
let Some(output_path) = T::output_path() else {
return Ok(());
};
if !seen.insert(TypeId::of::<T>()) {
return Ok(());
}
let mut declaration = String::new();
if let Some(docs) = T::docs() {
declaration.push_str(&docs.replace("\r\n", "\n").replace('\r', "\n"));
}
declaration.push_str("export ");
declaration.push_str(&T::decl().replace("\r\n", "\n").replace('\r', "\n"));
declarations.insert(output_path.components().collect(), declaration);
let mut visitor = TypeScriptDeclarationCollector {
declarations,
seen,
error: None,
};
T::visit_dependencies(&mut visitor);
if let Some(error) = visitor.error {
return Err(error);
}
Ok(())
}
struct TypeScriptDeclarationCollector<'a> {
declarations: &'a mut BTreeMap<PathBuf, String>,
seen: &'a mut HashSet<TypeId>,
error: Option<Box<dyn Error>>,
}
impl TypeVisitor for TypeScriptDeclarationCollector<'_> {
fn visit<T: TS + 'static + ?Sized>(&mut self) {
if self.error.is_some() {
return;
}
self.error = collect_typescript_declarations::<T>(self.declarations, self.seen).err();
}
}

View File

@@ -2423,7 +2423,7 @@ pub enum TruncationPolicy {
Tokens(usize),
}
#[derive(Serialize, Deserialize, Clone, JsonSchema)]
#[derive(Serialize, Deserialize, Clone, JsonSchema, TS)]
pub struct RolloutLine {
pub timestamp: String,
#[serde(flatten)]