Skip to main content

oxihuman_export/
raml_export.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3#![allow(dead_code)]
4
5//! RAML API spec stub export (YAML-based).
6
7/// A RAML resource (endpoint).
8#[allow(dead_code)]
9#[derive(Debug, Clone)]
10pub struct RamlResource {
11    pub path: String,
12    pub description: String,
13    pub methods: Vec<RamlMethod>,
14}
15
16/// A RAML HTTP method.
17#[allow(dead_code)]
18#[derive(Debug, Clone)]
19pub struct RamlMethod {
20    pub method: String,
21    pub description: String,
22    pub responses: Vec<(u16, String)>,
23}
24
25/// A RAML document.
26#[allow(dead_code)]
27#[derive(Debug, Clone)]
28pub struct RamlDoc {
29    pub title: String,
30    pub version: String,
31    pub base_uri: String,
32    pub resources: Vec<RamlResource>,
33}
34
35/// Create a new RAML document.
36#[allow(dead_code)]
37pub fn new_raml_doc(title: &str, version: &str, base_uri: &str) -> RamlDoc {
38    RamlDoc {
39        title: title.to_string(),
40        version: version.to_string(),
41        base_uri: base_uri.to_string(),
42        resources: Vec::new(),
43    }
44}
45
46/// Add a resource.
47#[allow(dead_code)]
48pub fn add_resource(doc: &mut RamlDoc, path: &str, description: &str) -> usize {
49    doc.resources.push(RamlResource {
50        path: path.to_string(),
51        description: description.to_string(),
52        methods: Vec::new(),
53    });
54    doc.resources.len() - 1
55}
56
57/// Add a method to a resource.
58#[allow(dead_code)]
59pub fn add_method(doc: &mut RamlDoc, res_idx: usize, method: &str, desc: &str) {
60    if res_idx < doc.resources.len() {
61        doc.resources[res_idx].methods.push(RamlMethod {
62            method: method.to_string(),
63            description: desc.to_string(),
64            responses: vec![(200, "application/json".to_string())],
65        });
66    }
67}
68
69/// Export to RAML YAML text.
70#[allow(dead_code)]
71pub fn export_raml(doc: &RamlDoc) -> String {
72    let mut out = format!(
73        "#%RAML 1.0\ntitle: {}\nversion: {}\nbaseUri: {}\n",
74        doc.title, doc.version, doc.base_uri
75    );
76    for res in &doc.resources {
77        out.push_str(&format!(
78            "{}:\n  description: {}\n",
79            res.path, res.description
80        ));
81        for m in &res.methods {
82            out.push_str(&format!(
83                "  {}:\n    description: {}\n    responses:\n",
84                m.method, m.description
85            ));
86            for (code, mime) in &m.responses {
87                out.push_str(&format!(
88                    "      {}:\n        body:\n          {}: {{}}\n",
89                    code, mime
90                ));
91            }
92        }
93    }
94    out
95}
96
97/// Resource count.
98#[allow(dead_code)]
99pub fn resource_count(doc: &RamlDoc) -> usize {
100    doc.resources.len()
101}
102
103#[cfg(test)]
104mod tests {
105    use super::*;
106
107    #[test]
108    fn new_doc_title() {
109        let doc = new_raml_doc("My API", "v1", "https://example.com/api");
110        assert_eq!(doc.title, "My API");
111    }
112
113    #[test]
114    fn add_resource_count() {
115        let mut doc = new_raml_doc("API", "v1", "https://x.com");
116        add_resource(&mut doc, "/users", "User resource");
117        assert_eq!(resource_count(&doc), 1);
118    }
119
120    #[test]
121    fn export_starts_with_raml_header() {
122        let doc = new_raml_doc("API", "v1", "https://x.com");
123        let s = export_raml(&doc);
124        assert!(s.starts_with("#%RAML 1.0"));
125    }
126
127    #[test]
128    fn export_contains_title() {
129        let doc = new_raml_doc("My API", "v1", "https://x.com");
130        let s = export_raml(&doc);
131        assert!(s.contains("My API"));
132    }
133
134    #[test]
135    fn export_contains_base_uri() {
136        let doc = new_raml_doc("API", "v1", "https://api.example.com");
137        let s = export_raml(&doc);
138        assert!(s.contains("https://api.example.com"));
139    }
140
141    #[test]
142    fn export_contains_resource_path() {
143        let mut doc = new_raml_doc("API", "v1", "https://x.com");
144        add_resource(&mut doc, "/users", "Users");
145        let s = export_raml(&doc);
146        assert!(s.contains("/users"));
147    }
148
149    #[test]
150    fn add_method_stored() {
151        let mut doc = new_raml_doc("API", "v1", "https://x.com");
152        let idx = add_resource(&mut doc, "/users", "Users");
153        add_method(&mut doc, idx, "get", "Get users");
154        assert_eq!(doc.resources[0].methods.len(), 1);
155    }
156
157    #[test]
158    fn method_in_export() {
159        let mut doc = new_raml_doc("API", "v1", "https://x.com");
160        let idx = add_resource(&mut doc, "/users", "Users");
161        add_method(&mut doc, idx, "get", "Get users");
162        let s = export_raml(&doc);
163        assert!(s.contains("get:"));
164    }
165
166    #[test]
167    fn invalid_res_idx_safe() {
168        let mut doc = new_raml_doc("API", "v1", "https://x.com");
169        add_method(&mut doc, 99, "get", "Safe");
170        assert_eq!(resource_count(&doc), 0);
171    }
172
173    #[test]
174    fn export_contains_version() {
175        let doc = new_raml_doc("API", "v2", "https://x.com");
176        let s = export_raml(&doc);
177        assert!(s.contains("v2"));
178    }
179}