/
lists.ts
121 lines (104 loc) · 4.69 KB
/
lists.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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/* Lists form conversion
*/
// import DataFactory from './factories/extended-term-factory'
// import jsonldParser from './jsonldparser'
// @ts-ignore is this injected?
import { Parser as N3jsParser } from 'n3' // @@ Goal: remove this dependency
// import N3Parser from './n3parser'
// import { parseRDFaDOM } from './rdfaparser'
// import RDFParser from './rdfxmlparser'
// import sparqlUpdateParser from './patch-parser'
// import * as Util from './utils-js'
import Node from './node-internal'
// import BlankNode from './blank-node'
// import NamedNode from './named-node'
import Collection from './collection'
import Statement from './statement'
// import Formula from './formula'
import Store from './store'
// import { ContentType, TurtleContentType, N3ContentType, RDFXMLContentType, XHTMLContentType, HTMLContentType, SPARQLUpdateContentType, SPARQLUpdateSingleMatchContentType, JSONLDContentType, NQuadsContentType, NQuadsAltContentType } from './types'
// import { Quad } from './tf-types'
import {BlankNode, NamedNode, Quad, Term,} from './tf-types'
import Namespace from './namespace'
const RDF = Namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#')
/* Replace a given node with another node throughout a given document
*
* we do the predicate as well for complenesss though we don't expect Collections to use it
*/
export function substituteInDoc (store:Store, x:Term, y:Term, doc?: NamedNode ) {
// console.log(`substituteInDoc put ${x} for ${y} in ${doc}}`)
for (const quad of store.statementsMatching(y as any, null, null, doc as any)) {
const newStatement = new Statement(x as any, quad.predicate, quad.object, doc as any)
store.remove(quad)
store.add(newStatement)
}
for (const quad of store.statementsMatching(null, y as any, null, doc) as any) {
store.remove(quad)
// console.log(` substituteInDoc predicate ${x} in ${quad}}`)
store.add(new Statement(quad.subject, x as any, quad.object, doc as any))
}
for (const quad of store.statementsMatching(null, null, y as any, doc) as any) {
store.remove(quad)
store.add(new Statement(quad.subject, quad.predicate, x as any, doc as any))
}
}
/* Change all lone rdf:nil nodes into empty Collections
*/
export function substituteNillsInDoc (store:Store, doc?: NamedNode) {
const x = RDF('nil')
for (const quad of store.statementsMatching(x as any, null, null, doc as any)) {
store.remove(quad)
const y = new Collection()
store.add(new Statement(y as any, quad.predicate, quad.object, doc as any))
}
for (const quad of store.statementsMatching(null, null, x as any, doc) as any) {
if (!quad.predicate.sameTerm(RDF('rest'))) { // If not a tail
store.remove(quad)
const y = new Collection()
store.add(new Statement(quad.subject, quad.predicate, y as any, doc as any))
}
}
}
/**
* Convert lists reified as rdf:first, rest
* Normal method is sync.
* Unfortunately jsdonld is currently written to need to be called async.
* Hence the mess below with executeCallback.
* @param store - The quadstore
* @param doc - The document in which the conversion is done
*/
export function convertFirstRestNil (
store: Store,
doc: NamedNode | undefined, // Do whole store?
) {
function preceding (ele:BlankNode, listSoFar: Node[], trash: Quad[]): undefined {
const rests = store.statementsMatching(ele, RDF('rest'), null, doc)
if (rests.length !== 1) throw new Error(`Bad list structure: no rest at ${ele}`)
const firsts = store.statementsMatching(ele, RDF('first'), null, doc)
if (firsts.length !== 1) throw new Error(`Bad list structure: rest but ${firsts.length} firsts at ${ele}`)
const value = firsts[0].object
const total = [value].concat(listSoFar as any)
// console.log(' List now is: ', total)
const totalTrash = trash.concat(rests).concat(firsts)
const pres = store.statementsMatching(null, RDF('rest'), ele, doc)
if (pres.length === 0) { // Head of the list
const newList = new Collection(total)
store.remove(totalTrash)
// Replace old list with new list:
substituteInDoc(store, newList, ele, doc)
return
}
if (pres.length !== 1) throw new Error(`Bad list structure: ${pres.length} pres at ${ele}`)
const pre = pres[0].subject
if (pre.termType !== 'BlankNode') throw new Error(`Bad list element node ${pre} type: ${pre.termType} `)
preceding(pre, total, totalTrash)
return
}
substituteNillsInDoc(store, doc) // lone ones only
const tails = store.statementsMatching(null, RDF('rest'), RDF('nil'), doc)
tails.forEach(tail => {
if (tail.subject.termType !== 'BlankNode')
throw new Error(`Bad list element node ${tail.subject} type: ${tail.subject.termType} `)
preceding(tail.subject, [], [])
})
}