1
use json_ld::{
2
    expansion::Policy, syntax::Value, NoLoader, RemoteDocument, RemoteDocumentReference,
3
};
4
use sophia::{
5
    api::{
6
        graph::CollectibleGraph,
7
        parser::QuadParser,
8
        serializer::{Stringifier, TripleSerializer},
9
        source::QuadSource,
10
    },
11
    inmem::graph::LightGraph,
12
    jsonld::{
13
        loader_factory::{DefaultLoaderFactory, LoaderFactory},
14
        vocabulary::ArcIri,
15
        ContextRef, JsonLdOptions, JsonLdParser,
16
    },
17
    turtle::serializer::turtle::{TurtleConfig, TurtleSerializer},
18
};
19
use std::sync::Arc;
20

            
21
2
fn main() -> Result<(), Box<dyn std::error::Error>> {
22
2
    let mut args = std::env::args();
23
2
    let json_ld_path = args.nth(1).expect("Missing jsonld file.");
24
2
    let context_path = args.next();
25
2
    if let Some(context_path) = &context_path {
26
2
        println!(
27
2
            "Loading {} with @context from {}",
28
2
            json_ld_path, context_path
29
2
        );
30
2
    } else {
31
        println!("Loading {}", json_ld_path);
32
    }
33
2
    let json_str = std::fs::read_to_string(&json_ld_path)
34
2
        .unwrap_or_else(|e| panic!("Could not read file {}: {}", json_ld_path, e));
35
2
    let mut options = JsonLdOptions::<DefaultLoaderFactory<NoLoader<_, _, _>>>::default()
36
2
        .with_expansion_policy(Policy::Standard);
37
2
    if let Some(context_path) = context_path {
38
2
        let context_str = std::fs::read_to_string(&context_path)
39
2
            .map_err(|e| format!("Could not read file {}: {}", context_path, e))?;
40
2
        let iri = ArcIri::new(Arc::from(format!("file:{}", &context_path)))?;
41
2
        let context = parse_context(iri, &context_str)?;
42
2
        options = options.with_expand_context::<()>(context);
43
    }
44
2
    let parser = JsonLdParser::new_with_options(options);
45
2
    let turtle = to_turtle(&json_str, parser)?;
46
2
    println!("{}", turtle.as_str());
47
2
    Ok(())
48
2
}
49

            
50
2
fn parse_context(iri: ArcIri, context_str: &str) -> Result<ContextRef, Box<dyn std::error::Error>> {
51
    use json_ld::syntax::Parse;
52
86
    let doc = Value::parse_str(context_str, |span| {
53
86
        locspan::Location::new(iri.clone(), span)
54
86
    })?;
55
    use json_ld::ExtractContext;
56
2
    let context =
57
2
        Value::extract_context(doc).map_err(|e| format!("Could not extract @context: {}", e))?;
58
2
    let rdoc = RemoteDocument::new(Some(iri), None, context);
59
2
    Ok(RemoteDocumentReference::Loaded(rdoc))
60
2
}
61

            
62
2
fn to_turtle<LF: LoaderFactory>(
63
2
    json_str: &str,
64
2
    parser: JsonLdParser<LF>,
65
2
) -> Result<impl Stringifier, Box<dyn std::error::Error>> {
66
2
    let graph = LightGraph::from_triple_source(parser.parse_str(json_str).to_triples())?;
67
2
    let mut stringifier =
68
2
        TurtleSerializer::new_stringifier_with_config(TurtleConfig::new().with_pretty(true));
69
2
    stringifier.serialize_graph(&graph)?;
70
2
    Ok(stringifier)
71
2
}