-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtoSparql.ts
91 lines (73 loc) · 2.89 KB
/
toSparql.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import type { NamedNode } from '@rdfjs/types'
import { SparqlTemplateResult, sparql } from '@tpluscode/rdf-string'
import { MultiPointer } from 'clownface'
import { assertWellFormedPath, fromNode, NegatedPropertySet, PathVisitor, ShaclPropertyPath } from './path.js'
import * as Path from './path.js'
class ToSparqlPropertyPath extends PathVisitor<SparqlTemplateResult, { isRoot: boolean }> {
visitSequencePath({ paths }: Path.SequencePath, { isRoot = true } = {}): SparqlTemplateResult {
const sequence = paths.reduce(this.pathChain('/'), sparql``)
if (isRoot) {
return sequence
}
return sparql`(${sequence})`
}
visitInversePath({ path: inversed }: Path.InversePath): SparqlTemplateResult {
return sparql`^${inversed.accept(this, { isRoot: false })}`
}
visitAlternativePath({ paths }: Path.AlternativePath, { isRoot = true } = {}): SparqlTemplateResult {
const alternative = paths.reduce(this.pathChain('|'), sparql``)
if (isRoot) {
return alternative
}
return sparql`(${alternative})`
}
visitZeroOrMorePath({ path: inner }: Path.ZeroOrMorePath): SparqlTemplateResult {
return sparql`${inner.accept(this, { isRoot: false })}*`
}
visitOneOrMorePath({ path: inner }: Path.OneOrMorePath): SparqlTemplateResult {
return sparql`${inner.accept(this, { isRoot: false })}+`
}
visitZeroOrOnePath({ path: inner }: Path.ZeroOrOnePath): SparqlTemplateResult {
return sparql`${inner.accept(this, { isRoot: false })}?`
}
visitPredicatePath({ term: predicate }: Path.PredicatePath): SparqlTemplateResult {
return sparql`${predicate}`
}
visitNegatedPropertySet(path: NegatedPropertySet): SparqlTemplateResult {
return sparql`!(${path.paths.reduce(this.pathChain('|'), sparql``)})`
}
private pathChain(operator: string) {
return (previous: SparqlTemplateResult, current: Path.ShaclPropertyPath, index: number) => {
if (index === 0) {
return current.accept(this, { isRoot: false })
}
return sparql`${previous}${operator}${current.accept(this, { isRoot: false })}`
}
}
}
/**
* Creates a SPARQL template string which represents a SHACL path as Property Path
*
* @param pathOrNode SHACL Property Path
*/
export function toSparql(pathOrNode: MultiPointer | NamedNode | ShaclPropertyPath): SparqlTemplateResult {
const visitor = new ToSparqlPropertyPath()
const path = 'termType' in pathOrNode || '_context' in pathOrNode
? fromNode(pathOrNode)
: pathOrNode
return visitor.visit(path)
}
/**
* Splits a Sequence Path and returns an array of SPARQL template results.
* If the path is not a Sequence Path, returns an array with a single element
*
* @param path SHACL Property Path
*/
toSparql.sequence = (path: MultiPointer): SparqlTemplateResult[] => {
assertWellFormedPath(path)
const list = path.list()
if (list) {
return [...list].map(el => toSparql(el))
}
return [toSparql(path)]
}