iriq 0.35.0

IRI/URL extraction, normalization, and shape clustering.
Documentation
use crate::classifier::SegmentClassifier;
use crate::hints::derive_hints;
use crate::identifier::Identifier;
use crate::shape::{Shape, ShapeRenderOptions};

pub struct ClusterKey {
    pub key: String,
    pub host: String,
    pub scheme: String,
    pub shape: String,
}

pub fn cluster_key_for_host(
    iri: &Identifier,
    c: &SegmentClassifier,
    shape: Option<String>,
    host_override: String,
) -> ClusterKey {
    if iri.is_urn() {
        let (ns, value) = match iri.nss.split_once(':') {
            Some((ns, val)) => (ns.to_string(), val.to_string()),
            None => (iri.nss.clone(), String::new()),
        };
        let mut final_shape = String::new();
        if !value.is_empty() {
            final_shape = urn_value_shape(&ns, &value, c);
        }
        let key = format!("{}:{}:{}", iri.scheme, ns, final_shape);
        return ClusterKey {
            key: key.clone(),
            host: String::new(),
            scheme: iri.scheme.clone(),
            shape: key,
        };
    }
    let shape = shape.unwrap_or_else(|| {
        Shape::from_segments(&iri.path_segments, Some(c)).render(ShapeRenderOptions::default())
    });
    let key = format!("{}://{}{}", iri.scheme, host_override, shape);
    ClusterKey {
        key,
        host: host_override,
        scheme: iri.scheme.clone(),
        shape,
    }
}

fn urn_value_shape(ns: &str, value: &str, c: &SegmentClassifier) -> String {
    let parts = vec![ns.to_string(), value.to_string()];
    let entries = derive_hints(&parts, c);
    let entry = entries.last().unwrap();
    if !entry.variable {
        return entry.value.clone();
    }
    if !entry.hint.is_empty() {
        return format!("{{{}}}", entry.hint);
    }
    format!("{{{}}}", entry.ty.as_str())
}