facet_macros_impl/lib.rs
1#![warn(missing_docs)]
2#![allow(uncommon_codepoints)]
3#![doc = include_str!("../README.md")]
4
5// ============================================================================
6// RE-EXPORTS FROM FACET-MACRO-TYPES (grammar) AND FACET-MACRO-PARSE (parsed types)
7// ============================================================================
8
9// Re-export everything from facet-macro-types (includes unsynn, grammar, RenameRule)
10pub use facet_macro_types::*;
11
12// Re-export everything from facet-macro-parse (includes parsed types like PStruct, PEnum, etc.)
13pub use facet_macro_parse::*;
14
15// ============================================================================
16// FUNCTION PARSING (optional feature)
17// ============================================================================
18
19/// Parse function signature shape
20#[cfg(feature = "function")]
21pub mod function;
22
23// ============================================================================
24// CODE EMISSION
25// ============================================================================
26
27mod process_enum;
28mod process_struct;
29
30// ============================================================================
31// DOC STRIPPING DETECTION
32// ============================================================================
33
34/// Returns true if doc strings should be stripped from generated shapes.
35///
36/// Controlled by `--cfg facet_no_doc`. Set via rustflags in .cargo/config.toml,
37/// Cargo.toml profile, or RUSTFLAGS env var. The cfg is evaluated when the
38/// proc-macro is compiled.
39#[cfg(all(feature = "doc", facet_no_doc))]
40pub const fn is_no_doc() -> bool {
41 true
42}
43
44/// Returns true if doc strings should be stripped from generated shapes.
45#[cfg(all(feature = "doc", not(facet_no_doc)))]
46pub const fn is_no_doc() -> bool {
47 false
48}
49
50mod derive;
51pub use derive::*;
52
53mod plugin;
54pub use plugin::*;
55
56mod extension;
57pub use extension::*;
58
59mod on_error;
60pub use on_error::*;
61
62/// Attribute grammar infrastructure for extension crates
63pub mod attr_grammar;
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68 use quote::quote;
69
70 #[test]
71 fn test_struct_with_field_doc_comments() {
72 let input = quote! {
73 #[derive(Facet)]
74 pub struct User {
75 #[doc = " The user's unique identifier"]
76 pub id: u64,
77 }
78 };
79
80 let mut it = input.to_token_iter();
81 let parsed = it.parse::<Struct>().expect("Failed to parse struct");
82
83 // Check that we parsed the struct correctly
84 assert_eq!(parsed.name.to_string(), "User");
85
86 // Extract fields from the struct
87 if let StructKind::Struct { fields, .. } = &parsed.kind {
88 assert_eq!(fields.content.len(), 1);
89
90 // Check first field (id)
91 let id_field = &fields.content[0].value;
92 assert_eq!(id_field.name.to_string(), "id");
93
94 // Extract doc comments from id field
95 let mut doc_found = false;
96 for attr in &id_field.attributes {
97 match &attr.body.content {
98 AttributeInner::Doc(doc_inner) => {
99 // This should work with LiteralString
100 assert_eq!(doc_inner.value, " The user's unique identifier");
101 doc_found = true;
102 }
103 _ => {
104 // Skip non-doc attributes
105 }
106 }
107 }
108 assert!(doc_found, "Should have found a doc comment");
109 } else {
110 panic!("Expected a regular struct with named fields");
111 }
112 }
113}