Update shacl-tulip for shacl-vue integration #5

Merged
jsheunis merged 4 commits from integrate-sv into main 2025-04-10 07:50:03 +00:00
3 changed files with 30 additions and 18 deletions

View file

@ -10,11 +10,6 @@ export class FormBase {
constructor(id_iri = null, content = {}) {
if (!id_iri) {
var msg = "id_iri is a required argument"
console.error(msg)
throw new Error(msg)
}
this.ID_IRI = id_iri
this.content = content
this.ignoredProperties = [
@ -33,6 +28,14 @@ export class FormBase {
// }
}
_checkIDiri(mthd) {
if (!this.ID_IRI) {
var msg = `Instance property 'ID_IRI' is required in order to use instance method: ${mthd}.`
console.error(msg)
throw new Error(msg)
}
}
addSubject(class_uri, subject_uri, setVal_class={}, setVal_subject={}) {
// add_empty_node
// if the RDF:type IRI does not exist in FormBase.content yet, add it
@ -130,6 +133,7 @@ export class FormBase {
}
formNodeToQuads(class_uri, subject_uri, shapesDS) {
this._checkIDiri('formNodeToQuads')
// Node = subject_uri = a specific identifiable object that was edited
// Empty array to store quads
var quadArray = []
@ -206,6 +210,7 @@ export class FormBase {
}
quadsToFormData(class_uri, subject_term, RdfDS) {
this._checkIDiri('quadsToFormData')
// Subject term should be namedNode or blankNode
var subject_uri = subject_term.value
this.addSubject(class_uri, subject_uri)
@ -246,7 +251,7 @@ export class FormBase {
}
}
saveNode(class_uri, node_uri, shapesDS, RdfDS, editMode) {
saveNode(class_uri, node_uri, shapesDS, RdfDS, editMode, cloneFunc = structuredClone) {
var changeNodeIdx = false
var subject_iri = null
// Check if the node exists beforehand
@ -289,7 +294,7 @@ export class FormBase {
}
// Change formdata node_uri to the actual id, if this was present:
if (changeNodeIdx && subject_iri !== node_uri) {
this.content[class_uri][subject_iri] = structuredClone(this.content[class_uri][node_uri])
this.content[class_uri][subject_iri] = cloneFunc(this.content[class_uri][node_uri])
delete this.content[class_uri][node_uri]
}
return {
@ -297,8 +302,7 @@ export class FormBase {
node_iri: subject_iri || node_uri
}
// at the end, what to do with current data in formdata?
// we keep it there because this keeps track of changes during
// the session, so that we know what to submit back to the service.
// we keep it there because this keeps track of changes during the session
} else {
console.error(`\t- Node ${class_uri} does not exist`)
}

View file

@ -12,17 +12,14 @@ export class RdfDataset {
* Create a wrapper object for an RDF dataset a.k.a. quad-store
*/
constructor(data = {}) {
this.data = data;
this.rdfPretty = rdf.clone();
this.rdfPretty.formats.import(formatsPretty);
this.data.prefixes = {};
this.data.serializedGraph = '';
this.data.graphLoaded = false;
this.data.prefixesLoaded = false;
this.data.graph = this.createDataset();
this._eventTarget = new EventTarget();
}
@ -50,9 +47,9 @@ export class RdfDataset {
* Loads RDF data from a given URL and processes prefixes and quads.
* @param {string} url - The URL of the RDF document.
*/
async loadRDF(url) {
async loadRDF(url, headers = {}) {
this.beforeLoadFn()
readRDF(url)
readRDF(url, headers)
.then(quadStream => {
// Load prefixes
quadStream.on('prefix', (prefix, ns) => {
@ -99,11 +96,16 @@ export class RdfDataset {
* @param {import("rdf-ext").Quad} quad - The RDF quad.
*/
onDataFn(quad) {
// The first following line, moved here from shacl-vue's graphdata composable,
// was an attempt to solve https://hub.datalad.org/datalink/annotate-trr379-demo/issues/32.
// But it was a faulty attempt, since the object was different. Still, leaving it here since
// deleting matches would prospectively solve the duplication of named node or literal objects
this.data.graph.deleteMatches(quad.subject, quad.predicate, quad.object, null)
this.addQuad(quad)
this.dispatchEvent(new CustomEvent('quad', { detail: quad }));
}
async onDataEndFn() {
this.data.serializedGraph = await this.serializeGraph()
await this.updateSerializedGraph()
this.data.graphLoaded = true
this.dispatchEvent(new CustomEvent('graphLoaded', { detail: this.data.graph }));
}
@ -124,6 +126,10 @@ export class RdfDataset {
return (await this.rdfPretty.io.dataset.toText('text/turtle', this.data.graph)).trim()
}
async updateSerializedGraph() {
this.data.serializedGraph = (await this.rdfPretty.io.dataset.toText('text/turtle', this.data.graph)).trim()
}
/**
* Checks if a given RDF node represents an RDF list.
* @param {import("rdf-ext").Term} node - The RDF node to check.

View file

@ -12,7 +12,7 @@ const HOST = 'localhost';
// Test the FormBase class
describe('FormBase', () => {
let form;
let id_iri = 'https://concepts.datalad.org/s/things/v1/id'
let id_iri = 'https://concepts.datalad.org/s/things/v1/pid'
let shapesDS = new ShapesDataset();
let rdfDS = new RdfDataset();
@ -20,8 +20,10 @@ describe('FormBase', () => {
form = new FormBase(id_iri);
});
it('should throw an error if the required constructor argument is missing', () => {
expect(() => new FormBase()).toThrowError()
it('should throw an error if the required ID_IRI argument is missing for specific functions', () => {
var f = new FormBase();
expect(() => f.formNodeToQuads(null, null, null)).toThrowError()
expect(() => f.quadsToFormData(null, null, null)).toThrowError()
});
it('should handle all form functionality correctly', async () => {