annotate_build/lib.rs
1use std::path::PathBuf;
2
3pub use config::{BuildConfig, ModuleDeriveBuilder};
4
5pub const SCHEMA_VERSION: u32 = 1;
6
7pub(crate) use function::*;
8pub(crate) use module::*;
9pub(crate) use path::*;
10pub(crate) use render::*;
11
12mod builder;
13mod config;
14mod environment;
15mod function;
16mod module;
17mod parser;
18mod path;
19mod render;
20mod visitor;
21
22/// Scan the current crate for `#[pragma(...)]` annotations and export the generated environment.
23pub fn build() {
24 build_with(|_| {});
25}
26
27/// Scan the current crate and export the generated environment from multiple JSON configuration
28/// specs.
29///
30/// Each spec must be a JSON string with the following shape:
31///
32/// ```json
33/// {
34/// "schema_version": 1,
35/// "functions": [
36/// { "pragma": "command" }
37/// ],
38/// "modules": [
39/// {
40/// "pragma": "plugin",
41/// "derives": [
42/// {
43/// "name": "logging",
44/// "functions": [
45/// "info",
46/// "warn",
47/// "error"
48/// ],
49/// "modules": [
50/// {
51/// "name": "http",
52/// "functions": [
53/// "request_started",
54/// "request_finished"
55/// ],
56/// "modules": []
57/// }
58/// ]
59/// }
60/// ]
61/// }
62/// ]
63/// }
64/// ```
65///
66/// Fields:
67/// - `schema_version`: Must match [`SCHEMA_VERSION`]. This makes format changes explicit and lets
68/// builds fail early on incompatible config.
69/// - `functions`: Additional attribute names that should be treated like `#[pragma(...)]` on
70/// functions.
71/// - `modules`: Additional attribute names that should be treated like `#[pragma(...)]` on
72/// modules, together with optional nested derive configuration.
73/// - `derives[*].name`: Optional derive/module name.
74/// - `derives[*].functions`: Function names to expose under that derive node.
75/// - `derives[*].modules`: Nested derive modules with the same structure.
76pub fn build_with_specs(specs: impl IntoIterator<Item: AsRef<str>>) {
77 let mut config = BuildConfig::default();
78
79 for spec in specs {
80 let spec_config = config::build_config_from_json_spec(spec.as_ref())
81 .expect("config spec string must be valid JSON with a supported schema version");
82 config.merge(spec_config);
83 }
84
85 build_from_config(config);
86}
87
88/// Scan the current crate and export the generated environment using a small configuration DSL.
89pub fn build_with(configure: impl FnOnce(&mut BuildConfig)) {
90 let mut config = BuildConfig::default();
91 configure(&mut config);
92
93 build_from_config(config);
94}
95
96fn build_from_config(config: BuildConfig) {
97 let manifest_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
98
99 builder::build_manifest(
100 config.pragmas,
101 &config.derives,
102 config.module_derives,
103 manifest_dir.join("Cargo.toml"),
104 manifest_dir.file_name().unwrap(),
105 )
106}