1use super::*;
2
3fn conv(name: &str) -> String {
4 name.to_owned()
5}
6
7fn type_name(schema: &Schema) -> String {
8 match schema {
9 Schema::Bool => "boolean".to_owned(),
10 Schema::Int32 => "int32".to_owned(),
11 Schema::Int64 => "int64".to_owned(),
12 Schema::Float32 => "float32".to_owned(),
13 Schema::Float64 => "float64".to_owned(),
14 Schema::String => "string".to_owned(),
15 Schema::Option(inner) => format!("Option<{}>", type_name(inner)),
16 Schema::Struct(Struct { name, .. }) => name.camel_case(conv),
17 Schema::OneOf { base_name, .. } => base_name.camel_case(conv),
18 Schema::Vec(inner) => format!("[{}]", type_name(inner)),
19 Schema::Map(key_type, value_type) => {
20 format!("Map<{} -> {}>", type_name(key_type), type_name(value_type))
21 }
22 Schema::Enum { base_name, .. } => base_name.camel_case(conv),
23 }
24}
25
26#[derive(Debug, Serialize, Deserialize, Clone)]
27pub struct Options {
28 pub language: String,
29 pub require_docs: bool,
30}
31
32impl Options {
33 fn get_doc<'a>(&self, documentation: &'a Documentation, error_msg: &str) -> &'a str {
34 if let Some(text) = documentation.get(&self.language) {
35 text
36 } else if self.require_docs {
37 panic!("{}", error_msg);
38 } else {
39 "TODO: document"
40 }
41 }
42}
43
44impl Default for Options {
45 fn default() -> Self {
46 Self {
47 language: "en".to_owned(),
48 require_docs: false,
49 }
50 }
51}
52
53pub struct Generator {
54 parts: Vec<String>,
55 options: Options,
56}
57impl crate::Generator for Generator {
58 type Options = Options;
59 fn new(_name: &str, _version: &str, options: Options) -> Self {
60 Self {
61 parts: Vec::new(),
62 options,
63 }
64 }
65 fn result(self) -> GenResult {
66 GenResult {
67 files: vec![File {
68 path: "doc.md".to_owned(),
69 content: self.parts.join("\n"),
70 }],
71 }
72 }
73 fn add_only(&mut self, schema: &Schema) {
74 let language = &self.options.language;
75 match schema {
76 Schema::Struct(Struct {
77 documentation,
78 name,
79 fields,
80 magic: _,
81 }) => {
82 let mut content = Writer::new();
83 {
84 let content = &mut content;
85 writeln!(content, "## `{}`", name.camel_case(conv)).unwrap();
86 writeln!(content).unwrap();
87 writeln!(
88 content,
89 "{}",
90 self.options.get_doc(
91 documentation,
92 &format!("{:?} not documented in {:?}", name, language)
93 )
94 )
95 .unwrap();
96 writeln!(content).unwrap();
97 writeln!(
98 content,
99 "{}",
100 match language.as_str() {
101 "ru" => "Поля:",
102 "en" | _ => "Fields:",
103 }
104 )
105 .unwrap();
106 writeln!(content).unwrap();
107 for field in fields {
108 writeln!(
109 content,
110 "- `{}`: `{}` - {}",
111 field.name.snake_case(conv),
112 type_name(&field.schema),
113 self.options.get_doc(
114 &field.documentation,
115 &format!(
116 "{:?}::{:?} not documented in {:?}",
117 name, field.name, language
118 )
119 ),
120 )
121 .unwrap();
122 }
123 }
124 self.parts.push(content.get());
125 }
126 Schema::OneOf {
127 documentation,
128 base_name,
129 variants,
130 } => {
131 let mut content = Writer::new();
132 {
133 let content = &mut content;
134 writeln!(content, "## `{}`", base_name.camel_case(conv)).unwrap();
135 writeln!(content).unwrap();
136 writeln!(
137 content,
138 "{}",
139 self.options.get_doc(
140 documentation,
141 &format!("{:?} not documented in {:?}", base_name, language)
142 )
143 )
144 .unwrap();
145 writeln!(content).unwrap();
146 writeln!(
147 content,
148 "{}",
149 match language.as_str() {
150 "ru" => "Варианты:",
151 "en" | _ => "One of:",
152 }
153 )
154 .unwrap();
155 writeln!(content).unwrap();
156 for variant in variants {
157 writeln!(
158 content,
159 "- `{}` - {}",
160 variant.name.camel_case(conv),
161 self.options.get_doc(
162 &variant.documentation,
163 &format!(
164 "{:?}::{:?} not documented in {:?}",
165 base_name, variant.name, language
166 )
167 ),
168 )
169 .unwrap();
170 writeln!(content).unwrap();
171 content.inc_ident();
172 if variant.fields.is_empty() {
173 writeln!(
174 content,
175 "{}",
176 match language.as_str() {
177 "ru" => "Нет полей",
178 "en" | _ => "No fields",
179 }
180 )
181 .unwrap();
182 } else {
183 writeln!(
184 content,
185 "{}",
186 match language.as_str() {
187 "ru" => "Поля:",
188 "en" | _ => "Fields:",
189 }
190 )
191 .unwrap();
192 }
193 writeln!(content).unwrap();
194 for field in &variant.fields {
195 writeln!(
196 content,
197 "- `{}`: `{}` - {}",
198 field.name.snake_case(conv),
199 type_name(&field.schema),
200 self.options.get_doc(
201 &field.documentation,
202 &format!(
203 "{:?}::{:?}::{:?} not documented in {:?}",
204 base_name, variant.name, field.name, language
205 )
206 ),
207 )
208 .unwrap();
209 }
210 content.dec_ident();
211 }
212 }
213 self.parts.push(content.get());
214 }
215 Schema::Enum {
216 documentation,
217 base_name,
218 variants,
219 } => {
220 let mut content = Writer::new();
221 {
222 let content = &mut content;
223 writeln!(content, "## `{}`", base_name.camel_case(conv)).unwrap();
224 writeln!(content).unwrap();
225 writeln!(
226 content,
227 "{}",
228 self.options.get_doc(
229 documentation,
230 &format!("{:?} not documented in {:?}", base_name, language)
231 ),
232 )
233 .unwrap();
234 writeln!(content).unwrap();
235 writeln!(
236 content,
237 "{}",
238 match language.as_str() {
239 "ru" => "Варианты:",
240 "en" | _ => "Variants:",
241 }
242 )
243 .unwrap();
244 writeln!(content).unwrap();
245 for variant in variants {
246 writeln!(
247 content,
248 "- `{}` - {}",
249 variant.name.camel_case(conv),
250 self.options.get_doc(
251 &variant.documentation,
252 &format!(
253 "{:?}::{:?} not documented in {:?}",
254 base_name, variant.name, language
255 )
256 ),
257 )
258 .unwrap();
259 }
260 }
261 self.parts.push(content.get());
262 }
263 Schema::Bool
264 | Schema::Int32
265 | Schema::Int64
266 | Schema::Float32
267 | Schema::Float64
268 | Schema::String
269 | Schema::Option(_)
270 | Schema::Vec(_)
271 | Schema::Map(_, _) => {}
272 }
273 }
274}