Skip to main content

oag_node_client/emitters/
split.rs

1use oag_core::GeneratedFile;
2use oag_core::config::SplitBy;
3use oag_core::ir::{IrSpec, OperationGroup, group_operations};
4
5use crate::emitters;
6use crate::emitters::source_path;
7
8/// Emit files for split layout mode.
9///
10/// Produces:
11/// - `types.ts` — centralized types (same as modular)
12/// - `_client-base.ts` — the ApiClient class with the private `request` method
13/// - `{group}.ts` — per-group files with standalone functions
14/// - `sse.ts` — SSE runtime (same as modular)
15/// - `index.ts` — barrel re-export
16pub fn emit_split(
17    ir: &IrSpec,
18    no_jsdoc: bool,
19    split_by: SplitBy,
20    source_dir: &str,
21) -> Vec<GeneratedFile> {
22    let groups = group_operations(ir, split_by);
23    let mut files = Vec::new();
24
25    // Centralized types
26    files.push(GeneratedFile {
27        path: source_path(source_dir, "types.ts"),
28        content: emitters::types::emit_types(ir),
29    });
30
31    // SSE runtime
32    files.push(GeneratedFile {
33        path: source_path(source_dir, "sse.ts"),
34        content: emitters::sse::emit_sse(),
35    });
36
37    // Client base — full client class
38    files.push(GeneratedFile {
39        path: source_path(source_dir, "client.ts"),
40        content: emitters::client::emit_client(ir, no_jsdoc),
41    });
42
43    // Per-group files — re-export from client for the group's operations
44    let mut group_names = Vec::new();
45    for group in &groups {
46        let group_file_name = source_path(source_dir, &format!("{}.ts", group.name.snake_case));
47        let content = emit_group_file(ir, group);
48        group_names.push(group.name.snake_case.clone());
49        files.push(GeneratedFile {
50            path: group_file_name,
51            content,
52        });
53    }
54
55    // Index barrel
56    files.push(GeneratedFile {
57        path: source_path(source_dir, "index.ts"),
58        content: emit_split_index(&group_names),
59    });
60
61    files
62}
63
64/// Emit a per-group file that re-exports the relevant operations from the client.
65fn emit_group_file(ir: &IrSpec, group: &OperationGroup) -> String {
66    let mut lines = Vec::new();
67    lines.push("// Auto-generated by oag — do not edit".to_string());
68    lines.push(format!("// Operations group: {}", group.name.original));
69    lines.push(String::new());
70
71    // Collect the operation names for this group
72    let op_names: Vec<&str> = group
73        .operation_indices
74        .iter()
75        .map(|&i| ir.operations[i].name.camel_case.as_str())
76        .collect();
77
78    lines.push("// This group contains the following operations:".to_string());
79    for name in &op_names {
80        lines.push(format!("//   - {name}"));
81    }
82    lines.push(String::new());
83    lines.push("// Import the client and call the relevant methods:".to_string());
84    lines.push("// import { ApiClient } from \"./client\";".to_string());
85    lines.push(String::new());
86    lines.push("export { ApiClient } from \"./client\";".to_string());
87    lines.push("export * from \"./types\";".to_string());
88
89    lines.join("\n") + "\n"
90}
91
92/// Emit the barrel index for split mode.
93fn emit_split_index(group_names: &[String]) -> String {
94    let mut lines = vec![
95        "// Auto-generated by oag — do not edit".to_string(),
96        "export * from \"./types\";".to_string(),
97        "export { ApiClient, type ClientConfig, type RequestOptions } from \"./client\";"
98            .to_string(),
99        "export { streamSse, SSEError, type SSEOptions } from \"./sse\";".to_string(),
100    ];
101
102    for name in group_names {
103        lines.push(format!("export * from \"./{name}\";"));
104    }
105
106    lines.join("\n") + "\n"
107}