From a981f82be348a7c0f67c6e4c07ecaf9733c36fcd Mon Sep 17 00:00:00 2001 From: Sebastian Zivota Date: Tue, 5 May 2026 16:30:49 +0200 Subject: [PATCH 1/2] feat(conventions): Add functions for attributes --- relay-conventions/build/attributes.rs | 82 +++++++++++++++++++++++---- relay-conventions/build/build.rs | 9 ++- relay-conventions/src/lib.rs | 1 + 3 files changed, 78 insertions(+), 14 deletions(-) diff --git a/relay-conventions/build/attributes.rs b/relay-conventions/build/attributes.rs index 9c8e9b91b77..7644728761f 100644 --- a/relay-conventions/build/attributes.rs +++ b/relay-conventions/build/attributes.rs @@ -161,17 +161,7 @@ pub fn format_constant(attr: &Attribute) -> String { } if let Some(deprecation) = deprecation { - write!(&mut out, "#[deprecated").unwrap(); - - if let Some(ref replacement) = deprecation.replacement { - let replacement_name = name_constant(replacement); - write!( - &mut out, - r#"(note="Use [`{replacement_name}`] (`{replacement}`) instead.")"# - ) - .unwrap(); - } - writeln!(&mut out, "]").unwrap(); + write_deprecation_annotation(&mut out, deprecation); } writeln!(&mut out, r#"pub const {name}: &str = "{key}";"#).unwrap(); @@ -179,12 +169,80 @@ pub fn format_constant(attr: &Attribute) -> String { out } +/// Formats an attribute as a function that interpolates a value for +/// the `` placeholder. +pub fn format_interpolating_fn(attribute: &Attribute) -> Option { + let Attribute { + key, + brief: _, + pii: _, + deprecation, + alias: _, + } = attribute; + + let needle = ""; + let placeholder_start = key.find(needle)?; + let placeholder_end = placeholder_start + needle.len(); + let before_placeholder = key.get(..placeholder_start).unwrap_or_default(); + let after_placeholder = key.get(placeholder_end..).unwrap_or_default(); + + let constant_name = name_constant(key); + let fn_name = name_fn(key); + + let mut out = String::new(); + + let example_value = key.replace("", "foobar"); + + writeln!( + &mut out, + r#"/// Instantiates the `` placeholder in the attribute +/// [`{constant_name}`] (`{key}`) with a concrete value. +/// # Example +/// ``` +/// use relay_conventions::consts::{fn_name}; +/// assert_eq!({fn_name}("foobar"), "{example_value} +/// ```"# + ) + .unwrap(); + + if let Some(deprecation) = deprecation { + write_deprecation_annotation(&mut out, deprecation); + } + + writeln!( + &mut out, + r#"pub fn {fn_name}(value: &str) -> String {{ + format!("{before_placeholder}{{value}}{after_placeholder}") +}}"# + ) + .unwrap(); + + Some(out) +} + +fn write_deprecation_annotation(out: &mut impl Write, deprecation: &Deprecation) { + write!(out, "#[deprecated").unwrap(); + + if let Some(ref replacement) = deprecation.replacement { + let replacement_name = name_constant(replacement); + write!( + out, + r#"(note="Use [`{replacement_name}`] (`{replacement}`) instead.")"# + ) + .unwrap(); + } + writeln!(out, "]").unwrap(); +} + /// Formats an attributes name as a constant identifier. fn name_constant(name: &str) -> String { + name_fn(name).to_ascii_uppercase() +} + +fn name_fn(name: &str) -> String { name.replace(['<', '>'], "") .replace('.', "__") .replace('-', "_") - .to_ascii_uppercase() } /// Parse a path-like attribute key into individual segments. diff --git a/relay-conventions/build/build.rs b/relay-conventions/build/build.rs index c0dfe1af0fd..5ca54703c6e 100644 --- a/relay-conventions/build/build.rs +++ b/relay-conventions/build/build.rs @@ -27,8 +27,8 @@ fn main() { fn write_attribute_rs(crate_dir: &Path) { use attributes::{ - Attribute, RawNode, constant_pair, format_attribute_info, format_constant, parse_segments, - write_canonical_fn, + Attribute, RawNode, constant_pair, format_attribute_info, format_constant, + format_interpolating_fn, parse_segments, write_canonical_fn, }; let attribute_consts_path = @@ -55,6 +55,11 @@ fn write_attribute_rs(crate_dir: &Path) { attribute_replacement_map.insert(old, new); } + // Write placeholder function, if applicable + if let Some(fun) = format_interpolating_fn(&attr) { + writeln!(&mut attribute_consts_file, "{}\n", fun).unwrap(); + } + // Put attribute info in the hierarchical map let info = format_attribute_info(&attr); diff --git a/relay-conventions/src/lib.rs b/relay-conventions/src/lib.rs index 79fce6134a1..8dc309ef59a 100644 --- a/relay-conventions/src/lib.rs +++ b/relay-conventions/src/lib.rs @@ -56,6 +56,7 @@ pub mod consts { #![allow(rustdoc::bare_urls)] #![allow(non_upper_case_globals)] + #![allow(non_snake_case)] include!(concat!(env!("OUT_DIR"), "/attribute_consts.rs")); mod not_yet_defined { From ee012ab9c5a1b181d8d9156484e38fd5b38b6f59 Mon Sep 17 00:00:00 2001 From: Sebastian Zivota Date: Wed, 6 May 2026 18:45:59 +0200 Subject: [PATCH 2/2] Add module --- relay-conventions/build/attributes.rs | 8 ++++---- relay-conventions/build/build.rs | 9 +++++++-- relay-conventions/src/lib.rs | 8 +++++++- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/relay-conventions/build/attributes.rs b/relay-conventions/build/attributes.rs index 7644728761f..7f6c56333f3 100644 --- a/relay-conventions/build/attributes.rs +++ b/relay-conventions/build/attributes.rs @@ -196,11 +196,11 @@ pub fn format_interpolating_fn(attribute: &Attribute) -> Option { writeln!( &mut out, r#"/// Instantiates the `` placeholder in the attribute -/// [`{constant_name}`] (`{key}`) with a concrete value. +/// [`{constant_name}`](crate::consts::{constant_name}) (`{key}`) with a concrete value. /// # Example /// ``` -/// use relay_conventions::consts::{fn_name}; -/// assert_eq!({fn_name}("foobar"), "{example_value} +/// use relay_conventions::interpolate::{fn_name}; +/// assert_eq!({fn_name}("foobar"), "{example_value}"); /// ```"# ) .unwrap(); @@ -227,7 +227,7 @@ fn write_deprecation_annotation(out: &mut impl Write, deprecation: &Deprecation) let replacement_name = name_constant(replacement); write!( out, - r#"(note="Use [`{replacement_name}`] (`{replacement}`) instead.")"# + r#"(note="Use [`{replacement_name}`](crate::consts::{replacement_name}) (`{replacement}`) instead.")"# ) .unwrap(); } diff --git a/relay-conventions/build/build.rs b/relay-conventions/build/build.rs index 5ca54703c6e..9d85cd61fc3 100644 --- a/relay-conventions/build/build.rs +++ b/relay-conventions/build/build.rs @@ -34,6 +34,11 @@ fn write_attribute_rs(crate_dir: &Path) { let attribute_consts_path = Path::new(&env::var("OUT_DIR").unwrap()).join("attribute_consts.rs"); let mut attribute_consts_file = BufWriter::new(File::create(&attribute_consts_path).unwrap()); + + let interpolation_fns_path = + Path::new(&env::var("OUT_DIR").unwrap()).join("interpolation_fns.rs"); + let mut interpolation_fns_file = BufWriter::new(File::create(&interpolation_fns_path).unwrap()); + let mut attribute_replacement_map = BTreeMap::new(); let mut root = RawNode::default(); @@ -55,9 +60,9 @@ fn write_attribute_rs(crate_dir: &Path) { attribute_replacement_map.insert(old, new); } - // Write placeholder function, if applicable + // Write interpolating function, if applicable if let Some(fun) = format_interpolating_fn(&attr) { - writeln!(&mut attribute_consts_file, "{}\n", fun).unwrap(); + writeln!(&mut interpolation_fns_file, "{}\n", fun).unwrap(); } // Put attribute info in the hierarchical map diff --git a/relay-conventions/src/lib.rs b/relay-conventions/src/lib.rs index 8dc309ef59a..96e5b403c9a 100644 --- a/relay-conventions/src/lib.rs +++ b/relay-conventions/src/lib.rs @@ -54,9 +54,9 @@ //! ### I want to reference an attribute in Relay but it's not defined in `sentry-conventions`, what should I do? //! **Always** define it in `sentry-conventions` before using it in Relay. This makes sure we have proper pub mod consts { + //! Attribute constant definitions. #![allow(rustdoc::bare_urls)] #![allow(non_upper_case_globals)] - #![allow(non_snake_case)] include!(concat!(env!("OUT_DIR"), "/attribute_consts.rs")); mod not_yet_defined { @@ -73,6 +73,12 @@ pub mod consts { pub use self::not_yet_defined::*; } +pub mod interpolate { + //! Functions for interpolating attribute keys with placeholders. + #![allow(non_snake_case)] + include!(concat!(env!("OUT_DIR"), "/interpolation_fns.rs")); +} + include!(concat!(env!("OUT_DIR"), "/attribute_map.rs")); include!(concat!(env!("OUT_DIR"), "/canonical_fn.rs")); include!(concat!(env!("OUT_DIR"), "/name_fn.rs"));