mod change_coupling_types;
mod threshold_input;
mod types;
pub use change_coupling_types::{ChangeCouplingConfigInput, CoChangeEventInput};
pub use edge_weight::{edge_weight_key, split_edge_weight_key};
pub use threshold_input::{ThresholdOverrideInput, ThresholdsInput};
pub use types::{
BoundaryDefInput, BoundarySpecInput, DependencyGraphInput, EdgeInput, LeidenConfigInput,
NodeInput, NormalizeNode, PatternInstanceInput, PatternLocationInput, PriorPartition,
QualityFunctionInput,
};
mod edge_weight;
use crate::error::AnalysisError;
pub fn validate_node_id(s: &str) -> Result<(), AnalysisError> {
if s.is_empty() {
return Err(AnalysisError::InvalidNodeId {
id: s.to_string(),
reason: "must not be empty".to_string(),
});
}
if s.contains('\\') {
return Err(AnalysisError::InvalidNodeId {
id: s.to_string(),
reason: "must use forward slashes only".to_string(),
});
}
if s.starts_with("./") {
return Err(AnalysisError::InvalidNodeId {
id: s.to_string(),
reason: "must not start with './'".to_string(),
});
}
if s.ends_with('/') {
return Err(AnalysisError::InvalidNodeId {
id: s.to_string(),
reason: "must not end with '/'".to_string(),
});
}
if s.starts_with('/') {
return Err(AnalysisError::InvalidNodeId {
id: s.to_string(),
reason: "must not be an absolute path".to_string(),
});
}
for component in s.split('/') {
if component == ".." {
return Err(AnalysisError::InvalidNodeId {
id: s.to_string(),
reason: "must not contain '..' components".to_string(),
});
}
}
Ok(())
}