1//! Extract AT Protocol lexicon schemas from compiled Rust types via inventory
2//!
3//! This example discovers types with `#[derive(LexiconSchema)]` via inventory
4//! and generates lexicon JSON files. This approach requires types to be linked
5//! into the binary at compile time.
6//!
7//! For workspace-wide schema extraction without linking requirements,
8//! use the `extract-schemas` binary or `WorkspaceDiscovery` API instead.
9
10use clap::Parser;
11use jacquard_lexgen::schema_extraction::{self, ExtractOptions, SchemaExtractor};
12use miette::Result;
13
14/// Extract lexicon schemas from compiled Rust types via inventory
15#[derive(Parser, Debug)]
16#[command(name = "extract-inventory")]
17#[command(about = "Extract AT Protocol lexicon schemas from linked Rust types")]
18#[command(long_about = r#"
19Discovers types implementing LexiconSchema via inventory and generates
20lexicon JSON files. The binary only discovers types that are linked,
21so you need to import your schema types in this binary or a custom one.
22
23For workspace-wide extraction, use the extract-schemas binary instead.
24
25See: https://docs.rs/jacquard-lexgen/latest/jacquard_lexgen/schema_extraction/
26"#)]
27struct Args {
28 /// Output directory for generated schema files
29 #[arg(short, long, default_value = "lexicons")]
30 output: String,
31
32 /// Verbose output
33 #[arg(short, long)]
34 verbose: bool,
35
36 /// Filter by NSID prefix (e.g., "app.bsky")
37 #[arg(short, long)]
38 filter: Option<String>,
39
40 /// Validate schemas before writing
41 #[arg(short = 'V', long, default_value = "true")]
42 validate: bool,
43
44 /// Pretty-print JSON output
45 #[arg(short, long, default_value = "true")]
46 pretty: bool,
47
48 /// Watch mode - regenerate on changes
49 #[arg(short, long)]
50 watch: bool,
51}
52
53fn main() -> Result<()> {
54 let args = Args::parse();
55
56 // Simple case: use convenience function
57 if !args.watch && args.filter.is_none() && args.validate && args.pretty {
58 return schema_extraction::run(&args.output, args.verbose);
59 }
60
61 // Advanced case: use full options
62 let options = ExtractOptions {
63 output_dir: args.output.into(),
64 verbose: args.verbose,
65 filter: args.filter,
66 validate: args.validate,
67 pretty: args.pretty,
68 };
69
70 let extractor = SchemaExtractor::new(options);
71
72 if args.watch {
73 extractor.watch()?;
74 } else {
75 extractor.extract_all()?;
76 }
77
78 Ok(())
79}