lincd
Version:
LINCD is a JavaScript library for building user interfaces with linked data (also known as 'structured data', or RDF)
158 lines • 5.86 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.List = void 0;
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
const NodeSet_1 = require("../collections/NodeSet");
const rdf_1 = require("../ontologies/rdf");
const models_1 = require("../models");
const Shape_1 = require("./Shape");
/**
* Class to work with rdf Lists
* A list is a way to store an ORDERED array in RDF (so in the graph with triples)
* For example:
* person.location = ["Portugal","Bali"]
* If the order of these 2 items matters then it can be stored as a list in the graph like this:
* _:somePerson _:location _:list1
* _:list1 rdf:first "Portugal"
* _:list1 rdf:rest _:list2 <-- continuation of the list can be found here
* _:list2 rdf:first "Bali"
* _:list2 rdf:rest rdf:nil <-- end of the list
*
*/
class List extends Shape_1.Shape {
constructor(blanknode = new models_1.BlankNode()) {
super(blanknode);
if (!blanknode.hasProperty(rdf_1.rdf.first) && !blanknode.has(rdf_1.rdf.rest, rdf_1.rdf.nil)) {
//starting a NEW empty list is a bit difficult. Because officially the only empty list is rdf:nil.
//But then how do we later add things to that list? We would need to switch out the node of this instance, which is not ideal in case the consumer of this class had saved/used that node already
//So instead we're using a blanknode with rdf:type rdf:List
blanknode.set(rdf_1.rdf.type, rdf_1.rdf.List);
}
}
getContents() {
return List.getContents(this.namedNode);
}
isEmpty() {
return !this.hasProperty(rdf_1.rdf.first);
}
addItem(item) {
//we need to check if the list is empty when adding items one by one
//we keep this out of _append for performance reasons
if (this.isEmpty()) {
this.set(rdf_1.rdf.first, item);
this.set(rdf_1.rdf.rest, rdf_1.rdf.nil);
}
else {
List._append(item, List.getLastListItem(this.namedNode));
}
}
static getFirstItem(items) {
if (items instanceof NodeSet_1.NodeSet) {
let firstItem = items.first();
items.delete(firstItem);
return firstItem;
}
else {
return items.shift();
}
}
addItems(items) {
let endPoint;
if (this.isEmpty()) {
endPoint = this.node;
let firstItem = List.getFirstItem(items);
this.set(rdf_1.rdf.first, firstItem);
}
else {
endPoint = List.getLastListItem(this.namedNode);
}
//add all items to the end of the list
List.appendItems(endPoint, items);
}
static appendItems(endPoint, items) {
items.forEach((item) => {
let rest = List._createListEntry(item);
endPoint.set(rdf_1.rdf.rest, rest);
endPoint = rest;
});
//close the list
endPoint.set(rdf_1.rdf.rest, rdf_1.rdf.nil);
return endPoint;
}
//TODO: not working, needs to be fixed
//see example here: http://www.snee.com/bobdc.blog/2014/04/rdf-lists-and-sparql.html
// removeItem(item: Node): boolean {
// return this._removeItem(this.namedNode, item);
// }
// private _removeItem(list: NamedNode, item: Node): boolean {
// if (list.has(rdf.first, item)) {
// let prev = list.getOneInverse(rdf.rest);
// prev.overwrite(rdf.rest, list.getOne(rdf.rest));
// list.remove();
// return true;
// } else if (!list.has(rdf.rest, rdf.nil)) {
// return this._removeItem(list.getOne(rdf.rest) as NamedNode, item);
// }
// }
static getLastListItem(list) {
let last;
while (list && !list.has(rdf_1.rdf.rest, rdf_1.rdf.nil)) {
last = list;
list = list.getOne(rdf_1.rdf.rest);
}
return list || last;
}
static _createListEntry(item) {
let list = models_1.BlankNode.create();
list.set(rdf_1.rdf.first, item);
list.set(rdf_1.rdf.rest, rdf_1.rdf.nil);
return list;
}
static _append(item, last) {
let next = this._createListEntry(item);
last.overwrite(rdf_1.rdf.rest, next);
return next;
}
/**
* Create a new list from a given set of nodes
* Most performant way to create a new list if you already have the items in the list
* @param items
*/
static createFrom(items) {
//NOTE: this method exists because new List(nodes) will not work because all shapes require a node as first parameter, hence a static method
let firstItem = this.getFirstItem(items);
//create the list and the first entry manually
let list = models_1.BlankNode.create();
list.set(rdf_1.rdf.type, rdf_1.rdf.List);
list.set(rdf_1.rdf.first, firstItem);
//add all the other items
List.appendItems(list, items);
return List.getOf(list);
}
/**
* Returns the contents of a rdf.List
* Will return an empty set if the given node is not a list
* @param list
* @param result
* @private
*/
static getContents(list, result = new NodeSet_1.NodeSet()) {
if (list.hasProperty(rdf_1.rdf.first)) {
result.add(list.getOne(rdf_1.rdf.first));
}
if (list.hasProperty(rdf_1.rdf.rest)) {
let rest = list.getOne(rdf_1.rdf.rest);
if (rest !== rdf_1.rdf.nil) {
return List.getContents(rest, result);
}
}
return result;
}
}
exports.List = List;
List.targetClass = rdf_1.rdf.List;
//# sourceMappingURL=List.js.map