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