Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 70 additions & 12 deletions relay-conventions/build/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,30 +161,88 @@ 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();

out
}

/// Formats an attribute as a function that interpolates a value for
/// the `<key>` placeholder.
pub fn format_interpolating_fn(attribute: &Attribute) -> Option<String> {
let Attribute {
key,
brief: _,
pii: _,
deprecation,
alias: _,
} = attribute;

let needle = "<key>";
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("<key>", "foobar");

writeln!(
&mut out,
r#"/// Instantiates the `<key>` placeholder in the attribute
/// [`{constant_name}`](crate::consts::{constant_name}) (`{key}`) with a concrete value.
/// # Example
/// ```
/// use relay_conventions::interpolate::{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}`](crate::consts::{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.
Expand Down
14 changes: 12 additions & 2 deletions relay-conventions/build/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,18 @@ 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 =
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();
Expand All @@ -55,6 +60,11 @@ fn write_attribute_rs(crate_dir: &Path) {
attribute_replacement_map.insert(old, new);
}

// Write interpolating function, if applicable
if let Some(fun) = format_interpolating_fn(&attr) {
writeln!(&mut interpolation_fns_file, "{}\n", fun).unwrap();
}

// Put attribute info in the hierarchical map
let info = format_attribute_info(&attr);

Expand Down
7 changes: 7 additions & 0 deletions relay-conventions/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
//! ### 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)]
include!(concat!(env!("OUT_DIR"), "/attribute_consts.rs"));
Expand All @@ -72,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"));
Expand Down
Loading