Skip to main content

swls_lang_turtle/
prefix.rs

1use std::{borrow::Cow, collections::HashMap};
2
3use swls_core::{lsp_types::Url, prelude::*, util::fs::File};
4
5use swls_lang_rdf_base::traits::{NamedNodeExt, Turtle, TurtleExt};
6
7/// Finds a resource.
8/// If the location starts with http, it is a remote resource.
9/// If the location fails to parse as a url, it is a file path to read.
10pub async fn find(location: &str, fs: &Fs, client: &impl Client) -> Option<Vec<(String, Url)>> {
11    if location.starts_with("http") {
12        let url = Url::parse(location).ok()?;
13        let content = client
14            .fetch(
15                &location,
16                &HashMap::from([(String::from("Accept"), String::from("text/turtle"))]),
17            )
18            .await
19            .ok()?
20            .body;
21        Some(vec![(content, url)])
22    } else {
23        if let Ok(url) = Url::parse(&location) {
24            let content = fs.0.read_file(&url).await?;
25            Some(vec![(content, url)])
26        } else {
27            let files = fs.0.glob_read(&location).await?;
28            Some(
29                files
30                    .into_iter()
31                    .flat_map(|File { content, name }| {
32                        file_name_to_url(&name).map(|url| (content, url))
33                    })
34                    .collect(),
35            )
36        }
37    }
38}
39
40#[cfg(not(target_arch = "wasm32"))]
41pub fn file_name_to_url(name: &str) -> Option<Url> {
42    swls_core::lsp_types::Url::from_file_path(name).ok()
43}
44
45#[cfg(target_arch = "wasm32")]
46pub fn file_name_to_url(_name: &str) -> Option<Url> {
47    None
48}
49
50pub fn prefix_from_url(url: &Url) -> Option<(Cow<'static, str>, Cow<'static, str>)> {
51    let segments = url.path_segments()?;
52    let last = segments.last()?;
53
54    let prefix = last.rsplit_once('.').map(|(x, _)| x).unwrap_or(last);
55    let prefix: Cow<'static, str> = Cow::Owned(prefix.to_string());
56
57    let url = Cow::Owned(url.to_string());
58
59    Some((prefix, url))
60}
61
62pub fn prefix_from_declaration(
63    turtle: &Triples2<'_>,
64) -> Option<(Cow<'static, str>, Cow<'static, str>)> {
65    let subject = turtle
66        .iter()
67        .find(|t| {
68            t.predicate.as_str() == "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
69                && t.object.as_str() == "http://www.w3.org/2002/07/owl#Ontology"
70        })?
71        .subject
72        .to_owned();
73
74    let prefix = turtle
75        .iter()
76        .find(|t| {
77            t.subject.eq(&subject)
78                && t.predicate.as_str() == "http://purl.org/vocab/vann/preferredNamespacePrefix"
79        })?
80        .object
81        .as_str();
82    let prefix = Cow::Owned(String::from(prefix));
83
84    let url = turtle
85        .iter()
86        .find(|t| {
87            t.subject.eq(&subject)
88                && t.predicate.as_str() == "http://purl.org/vocab/vann/preferredNamespaceUri"
89        })?
90        .object
91        .as_str();
92    let url = Cow::Owned(String::from(url));
93
94    Some((prefix, url))
95}
96
97pub fn prefix_from_prefixes(
98    model: &Turtle,
99    turtle: &Triples2<'_>,
100) -> Option<(Cow<'static, str>, Cow<'static, str>)> {
101    let shortened: Vec<_> = turtle
102        .iter()
103        .filter(|x| x.predicate.as_str() == "http://www.w3.org/1999/02/22-rdf-syntax-ns#type")
104        .flat_map(|t| model.shorten(t.subject.as_str()))
105        .collect();
106
107    let mut counts = HashMap::new();
108    for short in &shortened {
109        if let Some((prefix, _)) = short.split_once(':') {
110            let key: &mut usize = counts.entry(prefix).or_default();
111            *key += 1;
112        }
113    }
114
115    let (prefix, _) = counts.into_iter().max_by_key(|(_, e)| *e)?;
116
117    let prefix = model
118        .prefixes
119        .iter()
120        .find(|p| p.prefix.as_str() == prefix)?;
121
122    Some((
123        Cow::Owned(String::from(prefix.prefix.as_str())),
124        Cow::Owned(prefix.value.0.expand(model)?),
125    ))
126}
127
128pub fn prefix_from_source(
129    url: &Url,
130    source: &str,
131) -> Option<(Cow<'static, str>, Cow<'static, str>)> {
132    use crate::lang::parser::parse_new;
133    let (turtle, _, _, _, _) = parse_new(source, url.as_str(), None);
134
135    let triples = turtle.get_simple_triples().ok()?;
136
137    prefix_from_declaration(&triples).or_else(|| prefix_from_prefixes(&turtle, &triples))
138}