pub(crate) mod contribution;
pub(crate) mod listener;
pub(crate) mod observer;
pub(crate) mod plugin;
pub(crate) mod restart;
use syn::{Error, LitStr};
pub(crate) fn validate_id(id: &LitStr) -> Result<(), Error> {
let value = id.value();
let valid = !value.is_empty()
&& value.starts_with(|first: char| first.is_ascii_lowercase())
&& value.bytes().all(|byte| byte.is_ascii_lowercase() || byte.is_ascii_digit() || matches!(byte, b'-' | b'.' | b'_'));
valid.then_some(()).ok_or_else(|| {
Error::new(
id.span(),
"an artifact id is lowercase ASCII letters, digits, dots, hyphens, and underscores, \
starting with a letter",
)
})
}
pub(crate) fn set_once<T>(place: &mut Option<T>, value: T, span: proc_macro2::Span, name: &str) -> Result<(), Error> {
if place.replace(value).is_some() {
return Err(Error::new(span, format!("`{name}` is declared only once")));
}
Ok(())
}
pub(crate) fn symbol(value: &str) -> String {
value.chars().map(|character| if character.is_ascii_alphanumeric() { character.to_ascii_uppercase() } else { '_' }).collect()
}
pub(crate) fn description(argument: Option<LitStr>, attributes: &[syn::Attribute]) -> String {
argument.map(|written| written.value()).unwrap_or_else(|| documentation(attributes))
}
pub(crate) fn documentation(attributes: &[syn::Attribute]) -> String {
let mut paragraphs: Vec<String> = Vec::new();
let mut paragraph = String::new();
for line in attributes.iter().filter_map(documented) {
let line = line.trim();
if line.is_empty() {
if !paragraph.is_empty() {
paragraphs.push(std::mem::take(&mut paragraph));
}
continue;
}
if !paragraph.is_empty() {
paragraph.push(' ');
}
paragraph.push_str(line);
}
if !paragraph.is_empty() {
paragraphs.push(paragraph);
}
paragraphs.join("\n")
}
fn documented(attribute: &syn::Attribute) -> Option<String> {
let syn::Meta::NameValue(named) = &attribute.meta else {
return None;
};
if !named.path.is_ident("doc") {
return None;
}
let syn::Expr::Lit(literal) = &named.value else {
return None;
};
let syn::Lit::Str(text) = &literal.lit else {
return None;
};
Some(text.value())
}
fn version_argument(span: proc_macro2::Span) -> Error {
Error::new(span, "remove `version`: executable versions come from Cargo package.version")
}