zerodds_dlrl_codegen/
ts.rs1use alloc::format;
7use alloc::string::String;
8
9use crate::DlrlTypeInfo;
10
11#[allow(clippy::format_collect)]
13#[must_use]
14pub fn generate_ts_interface(info: &DlrlTypeInfo) -> String {
15 let cls = simple_name(&info.name);
16 let key_lines: String = info
17 .keys
18 .iter()
19 .map(|k| format!(" /** DLRL key field. */ {k}: number;\n"))
20 .collect();
21 let rel_lines: String = info
22 .relations
23 .iter()
24 .map(|(rel, target)| {
25 let t = simple_name(target);
26 format!(" /** DLRL relation → {t} */ {rel}: ReadonlyArray<{t}>;\n")
27 })
28 .collect();
29 format!(
30 "// Generated DLRL Interface — Spec §B.6 (TS PSM)\n\
31export interface {cls} {{\n{key_lines}{rel_lines}}}\n"
32 )
33}
34
35#[allow(clippy::format_collect)]
37#[must_use]
38pub fn generate_ts_class(info: &DlrlTypeInfo) -> String {
39 let cls = simple_name(&info.name);
40 let key_lines: String = info
41 .keys
42 .iter()
43 .map(|k| format!(" {k}: number = 0;\n"))
44 .collect();
45 let rel_lines: String = info
46 .relations
47 .iter()
48 .map(|(rel, target)| {
49 let t = simple_name(target);
50 format!(" {rel}: {t}[] = [];\n")
51 })
52 .collect();
53 format!(
54 "// Generated DLRL Class — Spec §B.6 (TS PSM)\n\
55export class {cls}Impl implements {cls} {{\n{key_lines}{rel_lines}}}\n\n\
56export class {cls}Home {{\n create(): {cls}Impl {{ return new {cls}Impl(); }}\n destroy(_obj: {cls}Impl): void {{}}\n}}\n"
57 )
58}
59
60fn simple_name(scoped: &str) -> &str {
61 scoped.rsplit("::").next().unwrap_or(scoped)
62}
63
64#[cfg(test)]
65#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
66mod tests {
67 use super::*;
68
69 fn trade_info() -> DlrlTypeInfo {
70 DlrlTypeInfo {
71 name: "demo::Trade".into(),
72 keys: alloc::vec!["symbol".into()],
73 relations: alloc::vec![("quotes".into(), "demo::Quote".into())],
74 }
75 }
76
77 #[test]
78 fn ts_interface_emits_keys_and_relations() {
79 let s = generate_ts_interface(&trade_info());
80 assert!(s.contains("export interface Trade"));
81 assert!(s.contains("symbol: number;"));
82 assert!(s.contains("quotes: ReadonlyArray<Quote>;"));
83 }
84
85 #[test]
86 fn ts_class_emits_impl_and_home() {
87 let s = generate_ts_class(&trade_info());
88 assert!(s.contains("class TradeImpl implements Trade"));
89 assert!(s.contains("symbol: number = 0;"));
90 assert!(s.contains("quotes: Quote[] = [];"));
91 assert!(s.contains("class TradeHome"));
92 assert!(s.contains("create(): TradeImpl"));
93 assert!(s.contains("destroy(_obj: TradeImpl): void"));
94 }
95}