1//! Analyze modules
2use std::path::Path;
3
4use anyhow::Result;
5use syn::parse_file;
6
7use crate::data_model::{Enum, Function, Module, Struct};
8
9use super::docstring_from_attrs;
10
11impl Module {
12 /// Fully qualified name of the variant
13 pub fn path_str(&self) -> String {
14 self.path.join("::")
15 }
16 /// Extract the relevant information from the AST
17 pub fn parse(
18 file: Option<&Path>,
19 path: &[&str],
20 content: &str,
21 ) -> Result<(Self, Vec<Struct>, Vec<Enum>, Vec<Function>)> {
22 let syntax = parse_file(content)?;
23 let mut mod_ = Self {
24 file: file.map(|f| f.to_string_lossy().to_string()), // TODO better way to serialize the path, also ?
25 path: path.iter().map(|s| s.to_string()).collect(),
26 docstring: docstring_from_attrs(&syntax.attrs),
27 declarations: vec![],
28 };
29
30 let mut structs = vec![];
31 let mut enums = vec![];
32 let mut functions = vec![];
33
34 for item in syntax.items {
35 // TODO traits, functions, impls, et
36 match &item {
37 syn::Item::Mod(mod_item) => {
38 if let syn::Visibility::Public(_) = mod_item.vis {
39 // TODO handle modules that are not just declarations
40 mod_.declarations.push(mod_item.ident.to_string());
41 }
42 }
43 syn::Item::Struct(struct_item) => {
44 if let syn::Visibility::Public(_) = struct_item.vis {
45 let struct_ = Struct::parse(path, struct_item);
46 structs.push(struct_);
47 }
48 }
49 syn::Item::Enum(enum_item) => {
50 if let syn::Visibility::Public(_) = enum_item.vis {
51 let enum_ = Enum::parse(path, enum_item);
52 enums.push(enum_);
53 }
54 }
55 syn::Item::Fn(fn_item) => {
56 if let syn::Visibility::Public(_) = fn_item.vis {
57 let function = Function::parse(path, fn_item);
58 functions.push(function);
59 }
60 }
61 _ => {}
62 }
63 }
64
65 Ok((mod_, structs, enums, functions))
66 }
67
68 pub fn to_json(&self) -> String {
69 serde_json::to_string(&self).unwrap()
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76 use insta::assert_yaml_snapshot;
77
78 #[test]
79 fn test_parse_module() {
80 let content = r###"
81//! Multi-line
82//! docstring
83
84pub enum MyEnum {
85 MyVariant1,
86}
87"###;
88 let mod_ = Module::parse(None, &["test"], content).unwrap();
89 assert_yaml_snapshot!(mod_, @r###"
90 ---
91 - file: ~
92 path:
93 - test
94 docstring: "Multi-line\ndocstring"
95 declarations: []
96 - []
97 - - path:
98 - test
99 - MyEnum
100 docstring: ""
101 variants:
102 - path:
103 - test
104 - MyEnum
105 - MyVariant1
106 docstring: ""
107 discriminant: ~
108 fields: []
109 - []
110 "###);
111 }
112}