Introduce n3 #11

Merged
jsheunis merged 4 commits from n3 into main 2025-05-20 20:28:19 +00:00
13 changed files with 178 additions and 572 deletions

410
package-lock.json generated
View file

@ -1,16 +1,16 @@
{ {
"name": "shacl-tulip", "name": "shacl-tulip",
"version": "0.0.1", "version": "0.0.2",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "shacl-tulip", "name": "shacl-tulip",
"version": "0.0.1", "version": "0.0.2",
"dependencies": { "dependencies": {
"@rdfjs/fetch-lite": "^3.3.0", "@rdfjs/fetch-lite": "^3.3.0",
"@rdfjs/formats-common": "^3.1.0", "@rdfjs/formats-common": "^3.1.0",
"rdf-ext": "^2.5.2" "n3": "^1.25.2"
}, },
"devDependencies": { "devDependencies": {
"happy-dom": "^17.2.2", "happy-dom": "^17.2.2",
@ -82,20 +82,6 @@
"buffer": "^6.0.3" "buffer": "^6.0.3"
} }
}, },
"node_modules/@digitalbazaar/http-client": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/@digitalbazaar/http-client/-/http-client-3.4.1.tgz",
"integrity": "sha512-Ahk1N+s7urkgj7WvvUND5f8GiWEPfUw0D41hdElaqLgu8wZScI8gdI0q+qWw5N1d35x7GCRH2uk9mi+Uzo9M3g==",
"license": "BSD-3-Clause",
"dependencies": {
"ky": "^0.33.3",
"ky-universal": "^0.11.0",
"undici": "^5.21.2"
},
"engines": {
"node": ">=14.0"
}
},
"node_modules/@esbuild/aix-ppc64": { "node_modules/@esbuild/aix-ppc64": {
"version": "0.25.2", "version": "0.25.2",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz",
@ -521,15 +507,6 @@
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/@fastify/busboy": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz",
"integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
"license": "MIT",
"engines": {
"node": ">=14"
}
},
"node_modules/@jridgewell/sourcemap-codec": { "node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.0", "version": "1.5.0",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
@ -559,21 +536,6 @@
"rdfjs-data-model-test": "bin/test.js" "rdfjs-data-model-test": "bin/test.js"
} }
}, },
"node_modules/@rdfjs/dataset": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@rdfjs/dataset/-/dataset-2.0.2.tgz",
"integrity": "sha512-6YJx+5n5Uxzq9dd9I0GGcIo6eopZOPfcsAfxSGX5d+YBzDgVa1cbtEBFnaPyPKiQsOm4+Cr3nwypjpg02YKPlA==",
"license": "MIT",
"bin": {
"rdfjs-dataset-test": "bin/test.js"
}
},
"node_modules/@rdfjs/environment": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@rdfjs/environment/-/environment-1.0.0.tgz",
"integrity": "sha512-+S5YjSvfoQR5r7YQCRCCVHvIEyrWia7FJv2gqM3s5EDfotoAQmFeBagApa9c/eQFi5EiNhmBECE5nB8LIxTaHg==",
"license": "MIT"
},
"node_modules/@rdfjs/fetch-lite": { "node_modules/@rdfjs/fetch-lite": {
"version": "3.3.0", "version": "3.3.0",
"resolved": "https://registry.npmjs.org/@rdfjs/fetch-lite/-/fetch-lite-3.3.0.tgz", "resolved": "https://registry.npmjs.org/@rdfjs/fetch-lite/-/fetch-lite-3.3.0.tgz",
@ -585,22 +547,6 @@
"readable-stream": "^4.5.2" "readable-stream": "^4.5.2"
} }
}, },
"node_modules/@rdfjs/formats": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@rdfjs/formats/-/formats-4.0.1.tgz",
"integrity": "sha512-Rg53vP+x1bnGAqJNKgEzJEUPDhj+tCpzb6wdmfLoVFq4XoZ589+cg2ScFDUMMyAVsgKXvSWjDhQ9f9ab254ZxA==",
"license": "MIT",
"dependencies": {
"@rdfjs/parser-jsonld": "^2.1.0",
"@rdfjs/parser-n3": "^2.0.1",
"@rdfjs/serializer-jsonld": "^2.0.0",
"@rdfjs/serializer-jsonld-ext": "^4.0.0",
"@rdfjs/serializer-ntriples": "^2.0.0",
"@rdfjs/serializer-turtle": "^1.1.1",
"@rdfjs/sink-map": "^2.0.0",
"rdfxml-streaming-parser": "^3.0.1"
}
},
"node_modules/@rdfjs/formats-common": { "node_modules/@rdfjs/formats-common": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/@rdfjs/formats-common/-/formats-common-3.1.0.tgz", "resolved": "https://registry.npmjs.org/@rdfjs/formats-common/-/formats-common-3.1.0.tgz",
@ -615,54 +561,6 @@
"rdfxml-streaming-parser": "^2.2.0" "rdfxml-streaming-parser": "^2.2.0"
} }
}, },
"node_modules/@rdfjs/formats/node_modules/rdfxml-streaming-parser": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/rdfxml-streaming-parser/-/rdfxml-streaming-parser-3.0.1.tgz",
"integrity": "sha512-lJtJ85xEJHc5BXohOPtxjYMEbGK3uiRxROwJLVNGanjuKLT9BWJluoNr3RzS9vQNmjkQwhhYmrbIftw1WUOj7Q==",
"license": "MIT",
"dependencies": {
"@rubensworks/saxes": "^6.0.1",
"@types/readable-stream": "^4.0.18",
"buffer": "^6.0.3",
"rdf-data-factory": "^2.0.0",
"readable-stream": "^4.4.2",
"relative-to-absolute-iri": "^1.0.0",
"validate-iri": "^1.0.0"
},
"funding": {
"type": "individual",
"url": "https://github.com/sponsors/rubensworks/"
}
},
"node_modules/@rdfjs/io": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@rdfjs/io/-/io-1.2.0.tgz",
"integrity": "sha512-wGScmcUW7YAcoQk0bTRDBZqdPL/Y58Fuz7F0nXKThBnWPTIUct8CWKzbkT1ym8X/nW46yBw5+nmasVauSN7yIw==",
"license": "MIT",
"dependencies": {
"duplex-to": "^2.0.0",
"readable-stream": "^4.4.2",
"stream-chunks": "^1.0.0"
}
},
"node_modules/@rdfjs/namespace": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@rdfjs/namespace/-/namespace-2.0.1.tgz",
"integrity": "sha512-U85NWVGnL3gWvOZ4eXwUcv3/bom7PAcutSBQqmVWvOaslPy+kDzAJCH1WYBLpdQd4yMmJ+bpJcDl9rcHtXeixg==",
"license": "MIT",
"dependencies": {
"@rdfjs/data-model": "^2.0.1"
}
},
"node_modules/@rdfjs/normalize": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@rdfjs/normalize/-/normalize-2.0.3.tgz",
"integrity": "sha512-Zklg33Uc2R0wYiYw/OAe7IA3548h/EmN7Pf/RAj6gxkx5juRqbkMmjXYoYlFrV1ug4z1qC4RLgr69juA81kTGA==",
"license": "MIT",
"dependencies": {
"rdf-canonize": "^4.0.1"
}
},
"node_modules/@rdfjs/parser-jsonld": { "node_modules/@rdfjs/parser-jsonld": {
"version": "2.1.3", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/@rdfjs/parser-jsonld/-/parser-jsonld-2.1.3.tgz", "resolved": "https://registry.npmjs.org/@rdfjs/parser-jsonld/-/parser-jsonld-2.1.3.tgz",
@ -689,27 +587,6 @@
"readable-stream": "^4.5.2" "readable-stream": "^4.5.2"
} }
}, },
"node_modules/@rdfjs/prefix-map": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/@rdfjs/prefix-map/-/prefix-map-0.1.2.tgz",
"integrity": "sha512-qapFYVPYyYepg0sFy7T512667iZsN9a3RNcyNBTBV+O8wrU3v/URQZOipCTNrEm1BXzZ7KCK1Yi8HrE1y+uRuQ==",
"license": "MIT",
"dependencies": {
"readable-stream": "^4.3.0"
}
},
"node_modules/@rdfjs/score": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/@rdfjs/score/-/score-0.1.2.tgz",
"integrity": "sha512-HKiC6q6sCsEPYVf9B4k/R0Hd+9e0QsjKr4zRdfuv6V4VPiPyzHfAsSUiFfRdi8UvNfpdKmoSWX8PM/ZIPwvq1g==",
"license": "MIT",
"dependencies": {
"@rdfjs/data-model": "^2.0.2",
"@rdfjs/term-map": "^2.0.1",
"@rdfjs/term-set": "^2.0.2",
"@rdfjs/to-ntriples": "^3.0.1"
}
},
"node_modules/@rdfjs/serializer-jsonld": { "node_modules/@rdfjs/serializer-jsonld": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/@rdfjs/serializer-jsonld/-/serializer-jsonld-2.0.1.tgz", "resolved": "https://registry.npmjs.org/@rdfjs/serializer-jsonld/-/serializer-jsonld-2.0.1.tgz",
@ -720,18 +597,6 @@
"readable-stream": "^4.5.2" "readable-stream": "^4.5.2"
} }
}, },
"node_modules/@rdfjs/serializer-jsonld-ext": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@rdfjs/serializer-jsonld-ext/-/serializer-jsonld-ext-4.0.1.tgz",
"integrity": "sha512-eGNAdhsV8wkmCadyIN+PBfsN+BIiqplAd5VMc++wf5McsVi/vPNrWcBINdrNnlegml8nLUy0rlKztCQ/4pxW8w==",
"license": "MIT",
"dependencies": {
"@rdfjs/sink": "^2.0.1",
"jsonld": "^8.3.3",
"readable-stream": "^4.7.0",
"stream-chunks": "^1.0.0"
}
},
"node_modules/@rdfjs/serializer-ntriples": { "node_modules/@rdfjs/serializer-ntriples": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/@rdfjs/serializer-ntriples/-/serializer-ntriples-2.0.1.tgz", "resolved": "https://registry.npmjs.org/@rdfjs/serializer-ntriples/-/serializer-ntriples-2.0.1.tgz",
@ -744,23 +609,6 @@
"readable-stream": "^4.5.2" "readable-stream": "^4.5.2"
} }
}, },
"node_modules/@rdfjs/serializer-turtle": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/@rdfjs/serializer-turtle/-/serializer-turtle-1.1.5.tgz",
"integrity": "sha512-uvIFUOuMuk8JrJnng/tWKIQ+8XI6YLEms75YdvZ49LtIyyfbDqKz76EybgnD/zZYfMhVVkguKtheBC9h08g1PQ==",
"license": "MIT",
"dependencies": {
"@rdfjs/data-model": "^2.0.1",
"@rdfjs/namespace": "^2.0.0",
"@rdfjs/prefix-map": "^0.1.1",
"@rdfjs/sink": "^2.0.0",
"@rdfjs/term-map": "^2.0.0",
"@rdfjs/to-ntriples": "^3.0.1",
"@rdfjs/tree": "^0.2.1",
"readable-stream": "^4.3.0",
"stream-chunks": "^1.0.0"
}
},
"node_modules/@rdfjs/sink": { "node_modules/@rdfjs/sink": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/@rdfjs/sink/-/sink-2.0.1.tgz", "resolved": "https://registry.npmjs.org/@rdfjs/sink/-/sink-2.0.1.tgz",
@ -773,50 +621,12 @@
"integrity": "sha512-BwCTTsMN/tfQl6QzD2oHn9A08e4af+hlzAz/d5XXrlOkYMEDUAqFuh2Odj9EbayhAEeN4wA743Mj2yC0/s69rg==", "integrity": "sha512-BwCTTsMN/tfQl6QzD2oHn9A08e4af+hlzAz/d5XXrlOkYMEDUAqFuh2Odj9EbayhAEeN4wA743Mj2yC0/s69rg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@rdfjs/term-map": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@rdfjs/term-map/-/term-map-2.0.2.tgz",
"integrity": "sha512-EJ2FmmdEUsSR/tU1nrizRLWzH24YzhuvesrbUWxC3Fs0ilYNdtTbg0RaFJDUnJF3HkbNBQe8Zrt/uvU/hcKnHg==",
"license": "MIT",
"dependencies": {
"@rdfjs/to-ntriples": "^3.0.1"
}
},
"node_modules/@rdfjs/term-set": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@rdfjs/term-set/-/term-set-2.0.3.tgz",
"integrity": "sha512-DyXrKWEx+mtAFUZVU7bc3Va6/KZ8PsIp0RVdyWT9jfDgI/HCvNisZaBtAcm+SYTC45o+7WLkbudkk1bfaKVB0A==",
"license": "MIT",
"dependencies": {
"@rdfjs/to-ntriples": "^3.0.1"
}
},
"node_modules/@rdfjs/to-ntriples": { "node_modules/@rdfjs/to-ntriples": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/@rdfjs/to-ntriples/-/to-ntriples-3.0.1.tgz", "resolved": "https://registry.npmjs.org/@rdfjs/to-ntriples/-/to-ntriples-3.0.1.tgz",
"integrity": "sha512-gjoPAvh4j7AbGMjcDn/8R4cW+d/FPtbfbMM0uQXkyfBFtNUW2iVgrqsgJ65roLc54Y9A2TTFaeeTGSvY9a0HCQ==", "integrity": "sha512-gjoPAvh4j7AbGMjcDn/8R4cW+d/FPtbfbMM0uQXkyfBFtNUW2iVgrqsgJ65roLc54Y9A2TTFaeeTGSvY9a0HCQ==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@rdfjs/traverser": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/@rdfjs/traverser/-/traverser-0.1.4.tgz",
"integrity": "sha512-53QYlxiQIxH8k4jutjet1EjdZfyKCDSsfqnj2YejAJ1X8mLDMSOsneMM5savBwBR0ROfAhKVtZVb+pego+JLiw==",
"license": "MIT",
"dependencies": {
"@rdfjs/to-ntriples": "^3.0.1"
}
},
"node_modules/@rdfjs/tree": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/@rdfjs/tree/-/tree-0.2.1.tgz",
"integrity": "sha512-J70CQ7R8Ivfs1FFUxtFN7ADb5wTMgbhn0O558NXSXQHItmSavT6cXmQlIokbmboU+grhu56iR/8Bl9do8LCq+w==",
"license": "MIT",
"dependencies": {
"@rdfjs/namespace": "^2.0.0",
"@rdfjs/term-map": "^2.0.0",
"@rdfjs/term-set": "^2.0.1"
}
},
"node_modules/@rdfjs/types": { "node_modules/@rdfjs/types": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/@rdfjs/types/-/types-2.0.1.tgz", "resolved": "https://registry.npmjs.org/@rdfjs/types/-/types-2.0.1.tgz",
@ -1771,17 +1581,6 @@
"node": "^12.20 || >= 14.13" "node": "^12.20 || >= 14.13"
} }
}, },
"node_modules/file-fetch": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/file-fetch/-/file-fetch-2.0.1.tgz",
"integrity": "sha512-jN4OveNyFdDIscQgaKL3vpPN5i4WnoQdWs1VQgT+3+SxsOW4+mQQzgOPQa4BjbKSkjeMv4xi+wLAMUKcL3CFtg==",
"license": "MIT",
"dependencies": {
"mime-types": "^3.0.1",
"readable-stream": "^4.4.2",
"stream-chunks": "^1.0.0"
}
},
"node_modules/follow-redirects": { "node_modules/follow-redirects": {
"version": "1.15.9", "version": "1.15.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
@ -1899,16 +1698,6 @@
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
"node_modules/grapoi": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/grapoi/-/grapoi-1.1.3.tgz",
"integrity": "sha512-3Qi6hJG6P+m6YhOkpe2N60z0a7/nHW7FCcx1PqzBMydpsoQ0gerba5hLTnN4bDz+5rLtIK0LbBQzWdYLBQ39ug==",
"license": "MIT",
"dependencies": {
"@rdfjs/namespace": "^2.0.0",
"@rdfjs/term-set": "^2.0.0"
}
},
"node_modules/happy-dom": { "node_modules/happy-dom": {
"version": "17.4.4", "version": "17.4.4",
"resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-17.4.4.tgz", "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-17.4.4.tgz",
@ -2119,21 +1908,6 @@
"node": ">=12.0.0" "node": ">=12.0.0"
} }
}, },
"node_modules/jsonld": {
"version": "8.3.3",
"resolved": "https://registry.npmjs.org/jsonld/-/jsonld-8.3.3.tgz",
"integrity": "sha512-9YcilrF+dLfg9NTEof/mJLMtbdX1RJ8dbWtJgE00cMOIohb1lIyJl710vFiTaiHTl6ZYODJuBd32xFvUhmv3kg==",
"license": "BSD-3-Clause",
"dependencies": {
"@digitalbazaar/http-client": "^3.4.1",
"canonicalize": "^1.0.1",
"lru-cache": "^6.0.0",
"rdf-canonize": "^3.4.0"
},
"engines": {
"node": ">=14"
}
},
"node_modules/jsonld-context-parser": { "node_modules/jsonld-context-parser": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/jsonld-context-parser/-/jsonld-context-parser-3.0.0.tgz", "resolved": "https://registry.npmjs.org/jsonld-context-parser/-/jsonld-context-parser-3.0.0.tgz",
@ -2185,18 +1959,6 @@
"url": "https://github.com/sponsors/rubensworks/" "url": "https://github.com/sponsors/rubensworks/"
} }
}, },
"node_modules/jsonld/node_modules/rdf-canonize": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/rdf-canonize/-/rdf-canonize-3.4.0.tgz",
"integrity": "sha512-fUeWjrkOO0t1rg7B2fdyDTvngj+9RlUyL92vOdiB7c0FPguWVsniIMjEtHH+meLBO9rzkUlUzBVXgWrjI8P9LA==",
"license": "BSD-3-Clause",
"dependencies": {
"setimmediate": "^1.0.5"
},
"engines": {
"node": ">=12"
}
},
"node_modules/klaw": { "node_modules/klaw": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz",
@ -2207,43 +1969,6 @@
"graceful-fs": "^4.1.9" "graceful-fs": "^4.1.9"
} }
}, },
"node_modules/ky": {
"version": "0.33.3",
"resolved": "https://registry.npmjs.org/ky/-/ky-0.33.3.tgz",
"integrity": "sha512-CasD9OCEQSFIam2U8efFK81Yeg8vNMTBUqtMOHlrcWQHqUX3HeCl9Dr31u4toV7emlH8Mymk5+9p0lL6mKb/Xw==",
"license": "MIT",
"engines": {
"node": ">=14.16"
},
"funding": {
"url": "https://github.com/sindresorhus/ky?sponsor=1"
}
},
"node_modules/ky-universal": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/ky-universal/-/ky-universal-0.11.0.tgz",
"integrity": "sha512-65KyweaWvk+uKKkCrfAf+xqN2/epw1IJDtlyCPxYffFCMR8u1sp2U65NtWpnozYfZxQ6IUzIlvUcw+hQ82U2Xw==",
"license": "MIT",
"dependencies": {
"abort-controller": "^3.0.0",
"node-fetch": "^3.2.10"
},
"engines": {
"node": ">=14.16"
},
"funding": {
"url": "https://github.com/sindresorhus/ky-universal?sponsor=1"
},
"peerDependencies": {
"ky": ">=0.31.4",
"web-streams-polyfill": ">=3.2.1"
},
"peerDependenciesMeta": {
"web-streams-polyfill": {
"optional": true
}
}
},
"node_modules/linkify-it": { "node_modules/linkify-it": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
@ -2267,18 +1992,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"license": "ISC",
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/magic-string": { "node_modules/magic-string": {
"version": "0.30.17", "version": "0.30.17",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
@ -2361,27 +2074,6 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/mime-db": {
"version": "1.54.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
"integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
"license": "MIT",
"dependencies": {
"mime-db": "^1.54.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/minimist": { "node_modules/minimist": {
"version": "1.2.8", "version": "1.2.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
@ -2413,13 +2105,12 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/n3": { "node_modules/n3": {
"version": "1.24.2", "version": "1.25.2",
"resolved": "https://registry.npmjs.org/n3/-/n3-1.24.2.tgz", "resolved": "https://registry.npmjs.org/n3/-/n3-1.25.2.tgz",
"integrity": "sha512-j/3PKmK0MA3tAohDCl9y1JDaNxp8wCnhTtrOOgZ1O17JVtWLkzHsp2jZ8YhY2uS4FWQAm6mExcXvl7C8lwXyaw==", "integrity": "sha512-ZBPnAgOw4sze/hnyoydNA5Ts9wbwiG+BXssTkdBKD6IkQZcg1IfQdo5AMU9JhsIu/RGtRD1QD0gphEhk/6ZnWA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"buffer": "^6.0.3", "buffer": "^6.0.3",
"queue-microtask": "^1.1.2",
"readable-stream": "^4.0.0" "readable-stream": "^4.0.0"
}, },
"engines": { "engines": {
@ -2593,12 +2284,6 @@
"node": ">= 0.6.0" "node": ">= 0.6.0"
} }
}, },
"node_modules/proto-fetch": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/proto-fetch/-/proto-fetch-2.0.0.tgz",
"integrity": "sha512-QuhQVYN9WxCbJmfp/s3HLofEaDr/Jkq873++mo126XB2h+TFcKIGCIxeORH5ww9MOi2uP1SfWy4EgQH5PuBfdQ==",
"license": "MIT"
},
"node_modules/punycode.js": { "node_modules/punycode.js": {
"version": "2.3.1", "version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
@ -2625,38 +2310,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
},
"node_modules/rdf-canonize": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/rdf-canonize/-/rdf-canonize-4.0.1.tgz",
"integrity": "sha512-B5ynHt4sasbUafzrvYI2GFARgeFcD8Sx9yXPbg7gEyT2EH76rlCv84kyO6tnxzVbxUN/uJDbK1S/MXh+DsnuTA==",
"license": "BSD-3-Clause",
"dependencies": {
"setimmediate": "^1.0.5"
},
"engines": {
"node": ">=18"
}
},
"node_modules/rdf-data-factory": { "node_modules/rdf-data-factory": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/rdf-data-factory/-/rdf-data-factory-2.0.2.tgz", "resolved": "https://registry.npmjs.org/rdf-data-factory/-/rdf-data-factory-2.0.2.tgz",
@ -2670,33 +2323,6 @@
"url": "https://github.com/sponsors/rubensworks/" "url": "https://github.com/sponsors/rubensworks/"
} }
}, },
"node_modules/rdf-ext": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/rdf-ext/-/rdf-ext-2.5.2.tgz",
"integrity": "sha512-xndLCbnxcPUZ2CxdQX/BdHjAUsZuFuA4Uw2ddDZnX3vhLKoTIaXunWyp1r9yfX66Nxv0mEkzm71YIi19ex/pEg==",
"license": "MIT",
"dependencies": {
"@rdfjs/data-model": "^2.0.1",
"@rdfjs/dataset": "^2.0.1",
"@rdfjs/environment": "^1.0.0",
"@rdfjs/fetch-lite": "^3.2.1",
"@rdfjs/formats": "^4.0.0",
"@rdfjs/io": "^1.0.0",
"@rdfjs/namespace": "^2.0.0",
"@rdfjs/normalize": "^2.0.0",
"@rdfjs/prefix-map": "^0.1.1",
"@rdfjs/score": "^0.1.1",
"@rdfjs/term-map": "^2.0.0",
"@rdfjs/term-set": "^2.0.1",
"@rdfjs/to-ntriples": "^3.0.1",
"@rdfjs/traverser": "^0.1.1",
"file-fetch": "^2.0.0",
"grapoi": "^1.0.2",
"nodeify-fetch": "^3.1.0",
"proto-fetch": "^2.0.0",
"readable-stream": "^4.3.0"
}
},
"node_modules/rdfxml-streaming-parser": { "node_modules/rdfxml-streaming-parser": {
"version": "2.4.0", "version": "2.4.0",
"resolved": "https://registry.npmjs.org/rdfxml-streaming-parser/-/rdfxml-streaming-parser-2.4.0.tgz", "resolved": "https://registry.npmjs.org/rdfxml-streaming-parser/-/rdfxml-streaming-parser-2.4.0.tgz",
@ -2840,12 +2466,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/setimmediate": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
"integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
"license": "MIT"
},
"node_modules/side-channel": { "node_modules/side-channel": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
@ -3076,18 +2696,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/undici": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz",
"integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==",
"license": "MIT",
"dependencies": {
"@fastify/busboy": "^2.0.0"
},
"engines": {
"node": ">=14.0"
}
},
"node_modules/undici-types": { "node_modules/undici-types": {
"version": "6.21.0", "version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
@ -3355,12 +2963,6 @@
"integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==",
"dev": true, "dev": true,
"license": "Apache-2.0" "license": "Apache-2.0"
},
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"license": "ISC"
} }
} }
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "shacl-tulip", "name": "shacl-tulip",
"version": "0.0.2", "version": "0.0.3",
"type": "module", "type": "module",
"main": "./src/index.js", "main": "./src/index.js",
"module": "./src/index.js", "module": "./src/index.js",
@ -24,6 +24,6 @@
"dependencies": { "dependencies": {
"@rdfjs/fetch-lite": "^3.3.0", "@rdfjs/fetch-lite": "^3.3.0",
"@rdfjs/formats-common": "^3.1.0", "@rdfjs/formats-common": "^3.1.0",
"rdf-ext": "^2.5.2" "n3": "^1.25.2"
} }
} }

View file

@ -15,8 +15,8 @@ export class ClassDataset extends RdfDataset {
if (quad.predicate.value === RDFS.subClassOf.value && if (quad.predicate.value === RDFS.subClassOf.value &&
quad.subject.termType !== 'BlankNode' && quad.subject.termType !== 'BlankNode' &&
quad.object.termType !== 'BlankNode' ) { quad.object.termType !== 'BlankNode' ) {
this.addQuad(quad) this.addQuad(quad)
this.dispatchEvent(new CustomEvent('quad', { detail: quad })); this.dispatchEvent(new CustomEvent('quad', { detail: quad }));
} }
} }
} }

View file

@ -2,9 +2,10 @@
* *
*/ */
import rdf from 'rdf-ext';
import { RDF } from '../modules/namespaces'; import { RDF } from '../modules/namespaces';
import { isEmptyObject, toIRI} from '../modules/utils'; import { isEmptyObject, toIRI} from '../modules/utils';
import { DataFactory } from 'n3';
const { namedNode, blankNode, quad } = DataFactory;
export class FormBase { export class FormBase {
@ -140,7 +141,7 @@ export class FormBase {
// Identify the record's subject (named or blank node) // Identify the record's subject (named or blank node)
var subject = this._getRecordSubjectTerm(subject_uri, this.content[class_uri][subject_uri]) var subject = this._getRecordSubjectTerm(subject_uri, this.content[class_uri][subject_uri])
// Add the triple stating the subject is of type class // Add the triple stating the subject is of type class
let firstQuad = rdf.quad(subject, rdf.namedNode(RDF.type.value), rdf.namedNode(class_uri)) let firstQuad = quad(subject, namedNode(RDF.type.value), namedNode(class_uri))
quadArray.push(firstQuad) quadArray.push(firstQuad)
// Now we need to add all triples relating to the properties of the record. // Now we need to add all triples relating to the properties of the record.
for (var triple_predicate of Object.keys(this.content[class_uri][subject_uri])) { for (var triple_predicate of Object.keys(this.content[class_uri][subject_uri])) {
@ -161,7 +162,7 @@ export class FormBase {
continue continue
} }
// now set the predicate as a named node // now set the predicate as a named node
var predicate = rdf.namedNode(triple_predicate) var predicate = namedNode(triple_predicate)
// In order to set the node type of the object, we first need to figure it out // In order to set the node type of the object, we first need to figure it out
var [nodeFunc, dt] = shapesDS.getPropertyNodeKind(class_uri, triple_predicate, this.ID_IRI) var [nodeFunc, dt] = shapesDS.getPropertyNodeKind(class_uri, triple_predicate, this.ID_IRI)
// Now we can create the object nodes for each property // Now we can create the object nodes for each property
@ -169,13 +170,13 @@ export class FormBase {
// val: all values of a given property of an identifiable object // val: all values of a given property of an identifiable object
let triple_object let triple_object
if (dt) { if (dt) {
triple_object = nodeFunc(val, rdf.namedNode(dt)) triple_object = nodeFunc(val, namedNode(dt))
} else { } else {
triple_object = nodeFunc(val) triple_object = nodeFunc(val)
} }
// and finally we can add the quads to the store // and finally we can add the quads to the store
let quad = rdf.quad(subject, predicate, triple_object) let q = quad(subject, predicate, triple_object)
quadArray.push(quad) quadArray.push(q)
} }
} }
return quadArray return quadArray
@ -202,9 +203,9 @@ export class FormBase {
var subject var subject
if (Object.keys(record).indexOf(this.ID_IRI) >= 0) { if (Object.keys(record).indexOf(this.ID_IRI) >= 0) {
var subject_iri = record[this.ID_IRI][0] var subject_iri = record[this.ID_IRI][0]
subject = rdf.namedNode(subject_iri) subject = namedNode(subject_iri)
} else { } else {
subject = rdf.blankNode(record_id) subject = blankNode(record_id)
} }
return subject return subject
} }
@ -258,7 +259,7 @@ export class FormBase {
if (this.content[class_uri]) { if (this.content[class_uri]) {
// If we are in edit mode, the first step is to delete existing quads from graphData // If we are in edit mode, the first step is to delete existing quads from graphData
if (editMode) { if (editMode) {
RdfDS.data.graph.deleteMatches(rdf.namedNode(node_uri), null, null, null) RdfDS.data.graph.deleteMatches(namedNode(node_uri), null, null, null)
} }
// Then we generate the quads // Then we generate the quads
@ -285,9 +286,9 @@ export class FormBase {
// - for each triple in oldTriples: create a new one with same subject and predicate // - for each triple in oldTriples: create a new one with same subject and predicate
// and with new IRI as object, then delete the old triple // and with new IRI as object, then delete the old triple
if (editMode && subject_iri !== null && subject_iri !== node_uri) { if (editMode && subject_iri !== null && subject_iri !== node_uri) {
var objectQuads = RdfDS.getObjectTriples(rdf.namedNode(node_uri)) var objectQuads = RdfDS.getObjectTriples(namedNode(node_uri))
objectQuads.forEach((quad) => { objectQuads.forEach((quad) => {
let new_quad = rdf.quad(quad.subject, quad.predicate, subject) let new_quad = quad(quad.subject, quad.predicate, subject)
RdfDS.data.graph.delete(quad) RdfDS.data.graph.delete(quad)
RdfDS.data.graph.add(new_quad) RdfDS.data.graph.add(new_quad)
}); });

View file

@ -1,8 +1,8 @@
import rdf from 'rdf-ext';
import { readRDF } from '../modules/io' import { readRDF } from '../modules/io'
import { RDF, XSD } from '../modules/namespaces'; import { RDF, XSD } from '../modules/namespaces';
import { toCURIE } from '../modules/utils'; import { toCURIE } from '../modules/utils';
import formatsPretty from '@rdfjs/formats/pretty.js' import { Store, Writer, DataFactory } from 'n3';
const { namedNode, literal } = DataFactory;
/** /**
* A class wrapping an RDF dataset (quad-store) from the `rdf-ext` library. * A class wrapping an RDF dataset (quad-store) from the `rdf-ext` library.
@ -13,8 +13,6 @@ export class RdfDataset {
*/ */
constructor(data = {}) { constructor(data = {}) {
this.data = data; this.data = data;
this.rdfPretty = rdf.clone();
this.rdfPretty.formats.import(formatsPretty);
this.data.prefixes = {}; this.data.prefixes = {};
this.data.serializedGraph = ''; this.data.serializedGraph = '';
this.data.graphLoaded = false; this.data.graphLoaded = false;
@ -37,11 +35,11 @@ export class RdfDataset {
/** /**
* Create a quad store compliant with the [RDF/JS dataset specification](https://rdf.js.org/dataset-spec/) * Create a quad store compliant with the [RDF/JS dataset specification](https://rdf.js.org/dataset-spec/)
* via the `rdf-ext` package * via the `n3` package
* @returns {import("rdf-ext").DatasetCore} The RDF dataset instance. * @returns {} The RDF dataset instance.
*/ */
createDataset() { createDataset() {
return rdf.dataset() return new Store();
} }
/** /**
* Loads RDF data from a given URL and processes prefixes and quads. * Loads RDF data from a given URL and processes prefixes and quads.
@ -60,16 +58,14 @@ export class RdfDataset {
// Load prefixes // Load prefixes
quadStream.on('prefix', (prefix, ns) => { quadStream.on('prefix', (prefix, ns) => {
this.onPrefixFn(prefix, ns) this.onPrefixFn(prefix, ns)
}).on('end', () => { }).on('data', quad => {
this.onPrefixEndFn()
})
// Load data
quadStream.on('data', quad => {
this.onDataFn(quad) this.onDataFn(quad)
}).on('end', async () => { }).on('end', () => {
await this.onDataEndFn() this.onDataEndFn()
this.onPrefixEndFn()
}).on('error', err => {
console.error('Error while processing quadStream:', err);
}); });
return result return result
} }
@ -83,7 +79,7 @@ export class RdfDataset {
/** /**
* Process an RDF prefix. * Process an RDF prefix.
* @param {string} prefix - The prefix string. * @param {string} prefix - The prefix string.
* @param {import("rdf-ext").NamedNode} ns - The namespace associated with the prefix. * @param {} ns - The namespace associated with the prefix.
*/ */
onPrefixFn(prefix, ns) { onPrefixFn(prefix, ns) {
this.data.prefixes[prefix] = ns.value; this.data.prefixes[prefix] = ns.value;
@ -96,29 +92,29 @@ export class RdfDataset {
/** /**
* Process an RDF quad * Process an RDF quad
* @param {import("rdf-ext").Quad} quad - The RDF quad. * @param {} quad - The RDF quad.
*/ */
onDataFn(quad) { onDataFn(quad) {
// The first following line, moved here from shacl-vue's graphdata composable, // 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. // 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 // 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 // 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.data.graph.removeMatches(quad.subject, quad.predicate, quad.object, null)
this.addQuad(quad) this.addQuad(quad)
this.dispatchEvent(new CustomEvent('quad', { detail: quad })); this.dispatchEvent(new CustomEvent('quad', { detail: quad }));
} }
async onDataEndFn() {
await this.updateSerializedGraph() onDataEndFn() {
this.data.graphLoaded = true this.data.graphLoaded = true
this.dispatchEvent(new CustomEvent('graphLoaded', { detail: this.data.graph })); this.dispatchEvent(new CustomEvent('graphLoaded', { detail: this.data.graph }));
} }
/** /**
* Add an RDF quad to the dataset * Add an RDF quad to the dataset
* @param {import("rdf-ext").Quad} quad - The RDF quad to add. * @param {} quad - The RDF quad to add.
*/ */
addQuad(quad) { addQuad(quad) {
this.data.graph.add(quad) this.data.graph.addQuad(quad)
} }
/** /**
@ -126,33 +122,35 @@ export class RdfDataset {
* @returns {Promise<string>} The serialized RDF graph in Turtle format. * @returns {Promise<string>} The serialized RDF graph in Turtle format.
*/ */
async serializeGraph() { async serializeGraph() {
return (await this.rdfPretty.io.dataset.toText('text/turtle', this.data.graph)).trim() // Using N3.Writer to serialize graph to Turtle
} return new Promise((resolve, reject) => {
const writer = new Writer({ prefixes: this.data.prefixes });
async updateSerializedGraph() { writer.addQuads(this.data.graph.getQuads(null, null, null, null));
this.data.serializedGraph = (await this.rdfPretty.io.dataset.toText('text/turtle', this.data.graph)).trim() writer.end((error, result) => {
if (error) reject(error);
else resolve(result.trim());
});
});
} }
/** /**
* Checks if a given RDF node represents an RDF list. * Checks if a given RDF node represents an RDF list.
* @param {import("rdf-ext").Term} node - The RDF node to check. * @param {} node - The RDF node to check.
* @returns {boolean} True if the node represents an RDF list, otherwise false. * @returns {boolean} True if the node represents an RDF list, otherwise false.
*/ */
isRdfList(node) { isRdfList(node) {
let hasFirst = false; let hasFirst = false;
let hasRest = false; let hasRest = false;
this.data.graph.forEach((quad) => { this.data.graph.getQuads(node, null, null, null).forEach((quad) => {
if (quad.subject.equals(node)) { if (quad.predicate.value === RDF.first.value) hasFirst = true;
if (quad.predicate.value === RDF.first.value) hasFirst = true; if (quad.predicate.value === RDF.rest.value) hasRest = true;
if (quad.predicate.value === RDF.rest.value) hasRest = true;
}
}); });
return hasFirst && hasRest; return hasFirst && hasRest;
}; };
/** /**
* Converts an RDF list to an array. * Converts an RDF list to an array.
* @param {import("rdf-ext").Term} startNode - The starting node of the RDF list. * @param {} startNode - The starting node of the RDF list.
* @returns {Array} The converted RDF list as an array. * @returns {Array} The converted RDF list as an array.
*/ */
rdfListToArray(startNode) { rdfListToArray(startNode) {
@ -161,53 +159,38 @@ export class RdfDataset {
while (currentNode && currentNode.value !== RDF.nil.value) { while (currentNode && currentNode.value !== RDF.nil.value) {
let listItem = null; let listItem = null;
// Get the first element in the RDF list // Get the first element in the RDF list
this.data.graph.forEach((quad) => { this.data.graph.getQuads(currentNode, RDF.first, null, null).forEach(quad => {
if (quad.subject.equals(currentNode) && quad.predicate.value === RDF.first.value) { if (quad.object.termType === 'BlankNode') {
// Resolve blank nodes recursively, but handle literals and IRIs separately if (this.isRdfList(quad.object)) {
if (quad.object.termType === "BlankNode") { listItem = this.rdfListToArray(quad.object);
listItem = this.resolveBlankNode(quad.object, this.data.graph); } else {
} else if (quad.object.termType === "Literal") { listItem = this.resolveBlankNode(quad.object);
listItem = quad.object.value; // Store literal value
} else if (quad.object.termType === "NamedNode") {
listItem = quad.object.value; // Store IRI as a string
} }
} else if (quad.object.termType === 'Literal' || quad.object.termType === 'NamedNode') {
listItem = quad.object.value;
} }
}); });
if (listItem !== null) { if (listItem !== null) {
listItems.push(listItem); listItems.push(listItem);
} }
// Move to the next item in the list (rdf:rest) // Move to the next item in the list (rdf:rest)
let nextNode = null; const restQuads = this.data.graph.getQuads(currentNode, RDF.rest, null, null);
this.data.graph.forEach((quad) => { currentNode = restQuads.length > 0 ? restQuads[0].object : null;
if (quad.subject.equals(currentNode) && quad.predicate.value === RDF.rest.value) {
nextNode = quad.object;
}
});
currentNode = nextNode;
} }
return listItems; return listItems;
}; };
resolveBlankNode(blankNode) { resolveBlankNode(blankNode) {
let resolvedObject = {}; let resolvedObject = {};
this.data.graph.forEach((quad) => { this.data.graph.getQuads(blankNode, null, null, null).forEach(({ predicate, object }) => {
if (quad.subject.equals(blankNode)) { if (object.termType === 'BlankNode') {
const predicate = quad.predicate.value; if (this.isRdfList(object)) {
const object = quad.object; resolvedObject[predicate.value] = this.rdfListToArray(object);
} else {
// If the object is a blank node, resolve it recursively resolvedObject[predicate.value] = this.resolveBlankNode(object);
if (object.termType === "BlankNode") {
// Check if it's an RDF list and convert it to an array
if (this.isRdfList(object)) {
resolvedObject[predicate] = this.rdfListToArray(object);
} else {
resolvedObject[predicate] = this.resolveBlankNode(object);
}
} else if (object.termType === "Literal") {
resolvedObject[predicate] = object.value; // Handle literal values
} else if (object.termType === "NamedNode") {
resolvedObject[predicate] = object.value; // Handle IRIs as strings
} }
} else if (object.termType === 'Literal' || object.termType === 'NamedNode') {
resolvedObject[predicate.value] = object.value;
} }
}); });
return resolvedObject; return resolvedObject;
@ -215,25 +198,16 @@ export class RdfDataset {
getLiteralAndNamedNodes(predicate, propertyClass, prefixes) { getLiteralAndNamedNodes(predicate, propertyClass, prefixes) {
var propClassCurie = toCURIE(propertyClass, prefixes) var propClassCurie = toCURIE(propertyClass, prefixes)
// a) use the literal node with xsd data type const literalQuads = this.data.graph.getQuads(null, predicate, literal(String(propClassCurie), XSD.anyURI), null)
const literalNodes = rdf.grapoi({ dataset: this.data.graph }) const uriQuads = this.data.graph.getQuads(null, predicate, namedNode(propertyClass), null)
.hasOut(predicate, rdf.literal(String(propClassCurie), XSD.anyURI)) return literalQuads.concat(uriQuads)
.quads();
// b) and the named node
const uriNodes = rdf.grapoi({ dataset: this.data.graph })
.hasOut(predicate, rdf.namedNode(propertyClass))
.quads();
// return as a concatenated array of quads
return Array.from(literalNodes).concat(Array.from(uriNodes))
} }
getSubjectTriples(someTerm) { getSubjectTriples(someTerm) {
const quads = rdf.grapoi({ dataset: this.data.graph, term: someTerm }).out().quads(); return this.data.graph.getQuads(someTerm, null, null, null);
return Array.from(quads)
} }
getObjectTriples(someTerm) { getObjectTriples(someTerm) {
const quads = rdf.grapoi({ dataset: this.data.graph, term: someTerm }).in().quads(); return this.data.graph.getQuads(null, null, someTerm, null);
return Array.from(quads)
} }
} }

View file

@ -4,7 +4,8 @@
import { RdfDataset } from './RdfDataset' import { RdfDataset } from './RdfDataset'
import { SHACL, RDF } from '../modules/namespaces'; import { SHACL, RDF } from '../modules/namespaces';
import rdf from 'rdf-ext'; import { DataFactory } from 'n3';
const { namedNode, literal, blankNode } = DataFactory;
import { toIRI} from '../modules/utils'; import { toIRI} from '../modules/utils';
export class ShapesDataset extends RdfDataset { export class ShapesDataset extends RdfDataset {
@ -102,17 +103,17 @@ export class ShapesDataset extends RdfDataset {
// if sh:nodeKind == sh:Literal // if sh:nodeKind == sh:Literal
if (propertyShape[SHACL.nodeKind.value] == SHACL.Literal.value) { if (propertyShape[SHACL.nodeKind.value] == SHACL.Literal.value) {
// sh:nodeKind == sh:Literal // sh:nodeKind == sh:Literal
nodeFunc = rdf.literal nodeFunc = literal
// sh:datatype exists // sh:datatype exists
if (propertyShape.hasOwnProperty(SHACL.datatype.value)) { if (propertyShape.hasOwnProperty(SHACL.datatype.value)) {
dt = propertyShape[SHACL.datatype.value] dt = propertyShape[SHACL.datatype.value]
} }
} else if (propertyShape[SHACL.nodeKind.value] == SHACL.IRI.value) { } else if (propertyShape[SHACL.nodeKind.value] == SHACL.IRI.value) {
// sh:nodeKind == sh:IRI // sh:nodeKind == sh:IRI
nodeFunc = rdf.namedNode nodeFunc = namedNode
} else if (propertyShape[SHACL.nodeKind.value] == SHACL.BlankNode.value) { } else if (propertyShape[SHACL.nodeKind.value] == SHACL.BlankNode.value) {
// sh:nodeKind == sh:BlankNode // sh:nodeKind == sh:BlankNode
nodeFunc = rdf.blankNode nodeFunc = blankNode
} else if (propertyShape[SHACL.nodeKind.value] == SHACL.BlankNodeOrIRI.value) { } else if (propertyShape[SHACL.nodeKind.value] == SHACL.BlankNodeOrIRI.value) {
// sh:nodeKind == sh:BlankNodeOrIRI // sh:nodeKind == sh:BlankNodeOrIRI
// If the same property shape has a sh:class field, and if that class // If the same property shape has a sh:class field, and if that class
@ -128,26 +129,26 @@ export class ShapesDataset extends RdfDataset {
var associatedNodeShape = this.data.nodeShapes[toIRI(shClass, this.data.prefixes)] var associatedNodeShape = this.data.nodeShapes[toIRI(shClass, this.data.prefixes)]
var hasIdField = associatedNodeShape.properties.find((prop) => prop[SHACL.path.value] == id_uri) var hasIdField = associatedNodeShape.properties.find((prop) => prop[SHACL.path.value] == id_uri)
if (hasIdField) { if (hasIdField) {
nodeFunc = rdf.namedNode nodeFunc = namedNode
} else { } else {
nodeFunc = rdf.blankNode nodeFunc = blankNode
} }
} else { } else {
nodeFunc = rdf.namedNode nodeFunc = namedNode
} }
} else { } else {
console.error(`\t- NodeKind not supported: ${propertyShape[SHACL.nodeKind.value]}\n\t\tAdding triple with literal object to graphData`) console.error(`\t- NodeKind not supported: ${propertyShape[SHACL.nodeKind.value]}\n\t\tAdding triple with literal object to graphData`)
nodeFunc = rdf.literal nodeFunc = literal
} }
} else if (propertyShape.hasOwnProperty(SHACL.in.value)) { } else if (propertyShape.hasOwnProperty(SHACL.in.value)) {
// This is a temporary workaround; should definitely not be permanent // This is a temporary workaround; should definitely not be permanent
// Assume Literal nodekind for any arrays // Assume Literal nodekind for any arrays
console.log(`\t- NodeKind not found for property shape: ${property_uri}; found 'sh:in'. Setting to default literal`) console.log(`\t- NodeKind not found for property shape: ${property_uri}; found 'sh:in'. Setting to default literal`)
nodeFunc = rdf.literal nodeFunc = literal
} }
else { else {
console.log(`\t- NodeKind not found for property shape: ${property_uri}. Setting to default literal`) console.log(`\t- NodeKind not found for property shape: ${property_uri}. Setting to default literal`)
nodeFunc = rdf.literal nodeFunc = literal
} }
return [nodeFunc, dt] return [nodeFunc, dt]
} }

View file

@ -2,6 +2,7 @@ export { ClassDataset } from './classes/ClassDataset';
export { FormBase } from './classes/FormBase'; export { FormBase } from './classes/FormBase';
export { RdfDataset } from './classes/RdfDataset'; export { RdfDataset } from './classes/RdfDataset';
export { ShapesDataset } from './classes/ShapesDataset'; export { ShapesDataset } from './classes/ShapesDataset';
export { namespace } from "./modules/namespaces.js";
export * from "./modules/io.js"; export * from "./modules/io.js";
export * from "./modules/namespaces.js"; export * from "./modules/namespaces.js";

View file

@ -9,8 +9,6 @@
import formats from '@rdfjs/formats-common' import formats from '@rdfjs/formats-common'
import fetch from '@rdfjs/fetch-lite' import fetch from '@rdfjs/fetch-lite'
import formatsPretty from '@rdfjs/formats/pretty.js'
import rdf from 'rdf-ext'
export async function readRDF(file_url, headers = { "Content-Type": "text/turtle" }) { export async function readRDF(file_url, headers = { "Content-Type": "text/turtle" }) {
const url = file_url; const url = file_url;

View file

@ -4,9 +4,20 @@
*/ */
import rdf from 'rdf-ext'; import { DataFactory } from 'n3';
export const SHACL = rdf.namespace('http://www.w3.org/ns/shacl#'); const { namedNode } = DataFactory;
export const RDF = rdf.namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#');
export const DASH = rdf.namespace('http://datashapes.org/dash#'); export function namespace(baseIRI) {
export const RDFS = rdf.namespace('http://www.w3.org/2000/01/rdf-schema#'); return new Proxy({}, {
export const XSD = rdf.namespace('http://www.w3.org/2001/XMLSchema#'); get(_, prop) {
// Return a NamedNode for every accessed property
return namedNode(baseIRI + prop);
}
});
}
export const SHACL = namespace('http://www.w3.org/ns/shacl#');
export const RDF = namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#');
export const DASH = namespace('http://datashapes.org/dash#');
export const RDFS = namespace('http://www.w3.org/2000/01/rdf-schema#');
export const XSD = namespace('http://www.w3.org/2001/XMLSchema#');

View file

@ -33,11 +33,11 @@ describe('ClassDataset', () => {
expect(dataset.data.graphLoaded).toBe(true); expect(dataset.data.graphLoaded).toBe(true);
expect(dataset.data.prefixesLoaded).toBe(true); expect(dataset.data.prefixesLoaded).toBe(true);
const serializedGraph = await dataset.serializeGraph(); const serializedGraph = await dataset.serializeGraph();
expect(serializedGraph).not.toContain('<http://example.com/subject>'); expect(serializedGraph).not.toContain('ex:subject');
expect(serializedGraph).not.toContain('<http://example.com/predicate>'); expect(serializedGraph).not.toContain('ex:predicate');
expect(serializedGraph).not.toContain('"example"'); expect(serializedGraph).not.toContain('"Test value"');
expect(serializedGraph).toContain('<https://concepts.datalad.org/s/things/v1/Property>'); expect(serializedGraph).toContain('dlthings:Property');
expect(serializedGraph).toContain('<https://concepts.datalad.org/s/things/v1/Thing>'); expect(serializedGraph).toContain('dlthings:Thing');
}); });
}); });

View file

@ -3,8 +3,9 @@ import { FormBase } from '@/classes/FormBase';
import { ShapesDataset } from '@/classes/ShapesDataset'; import { ShapesDataset } from '@/classes/ShapesDataset';
import { RdfDataset } from '@/classes/RdfDataset'; import { RdfDataset } from '@/classes/RdfDataset';
import { RDF } from '@/modules/namespaces' import { RDF } from '@/modules/namespaces'
import rdf from 'rdf-ext'
import httpServer from 'http-server'; import httpServer from 'http-server';
import { DataFactory } from 'n3';
const { namedNode } = DataFactory;
let server; let server;
const PORT = 8083; const PORT = 8083;
const HOST = 'localhost'; const HOST = 'localhost';
@ -82,7 +83,7 @@ describe('FormBase', () => {
it('should convert an RDF dataset correctly to form content, and save it back', () => { it('should convert an RDF dataset correctly to form content, and save it back', () => {
let class_uri = 'https://concepts.datalad.org/s/social/unreleased/Person' let class_uri = 'https://concepts.datalad.org/s/social/unreleased/Person'
let subject_uri = 'http://example.com/testPerson' let subject_uri = 'http://example.com/testPerson'
let subject_term = rdf.namedNode(subject_uri) let subject_term = namedNode(subject_uri)
let predicate_uri = 'https://concepts.datalad.org/s/social/unreleased/given_name' let predicate_uri = 'https://concepts.datalad.org/s/social/unreleased/given_name'
form.quadsToFormData(class_uri, subject_term, rdfDS) form.quadsToFormData(class_uri, subject_term, rdfDS)
expect(Object.keys(form.content)).toContain(class_uri) expect(Object.keys(form.content)).toContain(class_uri)

View file

@ -1,9 +1,9 @@
import { describe, it, expect, beforeEach, vi} from 'vitest'; import { describe, it, expect, beforeEach, vi} from 'vitest';
import rdf from 'rdf-ext'; import { DataFactory } from 'n3';
import { RDF, XSD } from '@/modules/namespaces'; import { RDF, XSD } from '@/modules/namespaces';
import { RdfDataset } from '@/classes/RdfDataset'; import { RdfDataset } from '@/classes/RdfDataset';
import httpServer from 'http-server'; import httpServer from 'http-server';
const { namedNode, literal, blankNode, quad } = DataFactory;
let server; let server;
const PORT = 8080; const PORT = 8080;
const HOST = 'localhost'; const HOST = 'localhost';
@ -25,27 +25,27 @@ describe('RdfDataset', () => {
it('should add a quad to the dataset', () => { it('should add a quad to the dataset', () => {
console.log(`Running RdfDataset Test ${i++}...`) console.log(`Running RdfDataset Test ${i++}...`)
const subject = rdf.namedNode('http://example.com/subject'); const subject = namedNode('http://example.com/subject');
const predicate = rdf.namedNode('http://example.com/predicate'); const predicate = namedNode('http://example.com/predicate');
const object = rdf.literal('example', XSD.string); const object = literal('example', XSD.string);
const quad = rdf.quad(subject, predicate, object); const q = quad(subject, predicate, object);
dataset.addQuad(quad); dataset.addQuad(q);
expect(dataset.data.graph.size).toBe(1); expect(dataset.data.graph.size).toBe(1);
expect(dataset.data.graph.has(quad)).toBe(true); expect(dataset.data.graph.has(q)).toBe(true);
}); });
it('should correctly detect an RDF list', () => { it('should correctly detect an RDF list', () => {
console.log(`Running RdfDataset Test ${i++}...`) console.log(`Running RdfDataset Test ${i++}...`)
const node1 = rdf.blankNode(); const node1 = blankNode();
const node2 = rdf.blankNode(); const node2 = blankNode();
const node3 = rdf.namedNode(RDF.nil.value); const node3 = namedNode(RDF.nil.value);
dataset.addQuad(rdf.quad(node1, RDF.first, rdf.literal("Item 1"))); dataset.addQuad(quad(node1, RDF.first, literal("Item 1")));
dataset.addQuad(rdf.quad(node1, RDF.rest, node2)); dataset.addQuad(quad(node1, RDF.rest, node2));
dataset.addQuad(rdf.quad(node2, RDF.first, rdf.literal("Item 2"))); dataset.addQuad(quad(node2, RDF.first, literal("Item 2")));
dataset.addQuad(rdf.quad(node2, RDF.rest, node3)); dataset.addQuad(quad(node2, RDF.rest, node3));
expect(dataset.isRdfList(node1)).toBe(true); expect(dataset.isRdfList(node1)).toBe(true);
expect(dataset.isRdfList(node2)).toBe(true); expect(dataset.isRdfList(node2)).toBe(true);
@ -54,14 +54,14 @@ describe('RdfDataset', () => {
it('should convert an RDF list to an array', () => { it('should convert an RDF list to an array', () => {
console.log(`Running RdfDataset Test ${i++}...`) console.log(`Running RdfDataset Test ${i++}...`)
const node1 = rdf.blankNode(); const node1 = blankNode();
const node2 = rdf.blankNode(); const node2 = blankNode();
const node3 = rdf.namedNode(RDF.nil.value); const node3 = namedNode(RDF.nil.value);
dataset.addQuad(rdf.quad(node1, RDF.first, rdf.literal("Item 1"))); dataset.addQuad(quad(node1, RDF.first, literal("Item 1")));
dataset.addQuad(rdf.quad(node1, RDF.rest, node2)); dataset.addQuad(quad(node1, RDF.rest, node2));
dataset.addQuad(rdf.quad(node2, RDF.first, rdf.literal("Item 2"))); dataset.addQuad(quad(node2, RDF.first, literal("Item 2")));
dataset.addQuad(rdf.quad(node2, RDF.rest, node3)); dataset.addQuad(quad(node2, RDF.rest, node3));
const result = dataset.rdfListToArray(node1); const result = dataset.rdfListToArray(node1);
expect(result).toEqual(["Item 1", "Item 2"]); expect(result).toEqual(["Item 1", "Item 2"]);
@ -69,12 +69,12 @@ describe('RdfDataset', () => {
it('should serialize the dataset to Turtle format', async () => { it('should serialize the dataset to Turtle format', async () => {
console.log(`Running RdfDataset Test ${i++}...`) console.log(`Running RdfDataset Test ${i++}...`)
const subject = rdf.namedNode('http://example.com/subject'); const subject = namedNode('http://example.com/subject');
const predicate = rdf.namedNode('http://example.com/predicate'); const predicate = namedNode('http://example.com/predicate');
const object = rdf.literal('example', XSD.string); const object = literal('example', XSD.string);
const quad = rdf.quad(subject, predicate, object); const q = quad(subject, predicate, object);
dataset.addQuad(quad); dataset.addQuad(q);
const serializedGraph = await dataset.serializeGraph(); const serializedGraph = await dataset.serializeGraph();
expect(serializedGraph).toContain('<http://example.com/subject>'); expect(serializedGraph).toContain('<http://example.com/subject>');
expect(serializedGraph).toContain('<http://example.com/predicate>'); expect(serializedGraph).toContain('<http://example.com/predicate>');
@ -91,15 +91,31 @@ describe('RdfDataset', () => {
expect(dataset.data.graphLoaded).toBe(false); expect(dataset.data.graphLoaded).toBe(false);
expect(dataset.data.prefixesLoaded).toBe(false); expect(dataset.data.prefixesLoaded).toBe(false);
const fileUrl = `http://${HOST}:${PORT}/tests/mockData.ttl` const fileUrl = `http://${HOST}:${PORT}/tests/mockData.ttl`
// const graphLoadedHandler = vi.fn();
// dataset.addEventListener('graphLoaded', graphLoadedHandler);
// await dataset.loadRDF(fileUrl);
// await new Promise(resolve => dataset.addEventListener('graphLoaded', resolve));
// Add listener to await graph load
const graphLoadedHandler = vi.fn(); const graphLoadedHandler = vi.fn();
dataset.addEventListener('graphLoaded', graphLoadedHandler); const graphLoadedPromise = new Promise(resolve => {
dataset.loadRDF(fileUrl); dataset.addEventListener('graphLoaded', event => {
await new Promise(resolve => dataset.addEventListener('graphLoaded', resolve)); graphLoadedHandler(event);
resolve();
});
});
await dataset.loadRDF(fileUrl);
await graphLoadedPromise;
expect(graphLoadedHandler).toHaveBeenCalledTimes(1); expect(graphLoadedHandler).toHaveBeenCalledTimes(1);
expect(dataset.data.graph.size).toBe(2);
expect(dataset.data.prefixes['ex']).toBe('http://example.com/'); expect(dataset.data.prefixes['ex']).toBe('http://example.com/');
expect(dataset.data.graphLoaded).toBe(true); expect(dataset.data.graphLoaded).toBe(true);
expect(dataset.data.prefixesLoaded).toBe(true); expect(dataset.data.prefixesLoaded).toBe(true);
expect(dataset.data.graph.size).toBe(2);
console.log('Quads in graph:', dataset.data.graph.getQuads(null, null, null, null));
console.log(`Closing server on http://${HOST}:${PORT}`); console.log(`Closing server on http://${HOST}:${PORT}`);
server.close(); server.close();
@ -110,30 +126,30 @@ describe('RdfDataset', () => {
console.log(`Running RdfDataset Test ${i++}...`) console.log(`Running RdfDataset Test ${i++}...`)
const prefixHandler = vi.fn(); const prefixHandler = vi.fn();
dataset.addEventListener('prefix', prefixHandler); dataset.addEventListener('prefix', prefixHandler);
dataset.onPrefixFn('ex', rdf.namedNode('http://example.com/')); dataset.onPrefixFn('ex', namedNode('http://example.com/'));
expect(prefixHandler).toHaveBeenCalledTimes(1); expect(prefixHandler).toHaveBeenCalledTimes(1);
expect(dataset.data.prefixes['ex']).toBe('http://example.com/'); expect(dataset.data.prefixes['ex']).toBe('http://example.com/');
}); });
it('should resolve blank nodes correctly', () => { it('should resolve blank nodes correctly', () => {
console.log(`Running RdfDataset Test ${i++}...`) console.log(`Running RdfDataset Test ${i++}...`)
const blankNode = rdf.blankNode(); const bn = blankNode();
const predicate = rdf.namedNode('http://example.com/predicate'); const predicate = namedNode('http://example.com/predicate');
const object = rdf.literal('value'); const object = literal('value');
dataset.addQuad(rdf.quad(blankNode, predicate, object)); dataset.addQuad(quad(bn, predicate, object));
const resolved = dataset.resolveBlankNode(blankNode); const resolved = dataset.resolveBlankNode(bn);
expect(resolved[predicate.value]).toBe('value'); expect(resolved[predicate.value]).toBe('value');
}); });
it('should retrieve subject triples', () => { it('should retrieve subject triples', () => {
console.log(`Running RdfDataset Test ${i++}...`) console.log(`Running RdfDataset Test ${i++}...`)
const subject = rdf.namedNode('http://example.com/subject'); const subject = namedNode('http://example.com/subject');
const predicate = rdf.namedNode('http://example.com/predicate'); const predicate = namedNode('http://example.com/predicate');
const object = rdf.literal('example'); const object = literal('example');
dataset.addQuad(rdf.quad(subject, predicate, object)); dataset.addQuad(quad(subject, predicate, object));
const triples = dataset.getSubjectTriples(subject); const triples = dataset.getSubjectTriples(subject);
expect(triples.length).toBe(1); expect(triples.length).toBe(1);
@ -142,11 +158,11 @@ describe('RdfDataset', () => {
it('should retrieve object triples', () => { it('should retrieve object triples', () => {
console.log(`Running RdfDataset Test ${i++}...`) console.log(`Running RdfDataset Test ${i++}...`)
const subject = rdf.namedNode('http://example.com/subject'); const subject = namedNode('http://example.com/subject');
const predicate = rdf.namedNode('http://example.com/predicate'); const predicate = namedNode('http://example.com/predicate');
const object = rdf.literal('example'); const object = literal('example');
dataset.addQuad(rdf.quad(subject, predicate, object)); dataset.addQuad(quad(subject, predicate, object));
const triples = dataset.getObjectTriples(object); const triples = dataset.getObjectTriples(object);
expect(triples.length).toBe(1); expect(triples.length).toBe(1);

View file

@ -1,6 +1,7 @@
import { describe, it, expect, beforeEach} from 'vitest'; import { describe, it, expect, beforeEach} from 'vitest';
import { ShapesDataset } from '@/classes/ShapesDataset'; import { ShapesDataset } from '@/classes/ShapesDataset';
import rdf from 'rdf-ext' import { DataFactory } from 'n3';
const { literal, blankNode } = DataFactory;
import httpServer from 'http-server'; import httpServer from 'http-server';
let server; let server;
const PORT = 8082; const PORT = 8082;
@ -84,14 +85,14 @@ describe('ShapesDataset', () => {
) )
expect(nk1[0]).toBeTypeOf('function') expect(nk1[0]).toBeTypeOf('function')
expect(nk1[0]).toEqual(rdf.literal) expect(nk1[0]).toEqual(literal)
var nk2 = dataset.getPropertyNodeKind( var nk2 = dataset.getPropertyNodeKind(
'https://concepts.datalad.org/s/social/unreleased/Person', 'https://concepts.datalad.org/s/social/unreleased/Person',
'https://concepts.datalad.org/s/things/v1/attributes', 'https://concepts.datalad.org/s/things/v1/attributes',
'https://concepts.datalad.org/s/things/v1/id' 'https://concepts.datalad.org/s/things/v1/id'
) )
expect(nk2[0]).toBeTypeOf('function') expect(nk2[0]).toBeTypeOf('function')
expect(nk2[0]).toEqual(rdf.blankNode) expect(nk2[0]).toEqual(blankNode)
server.close(); server.close();
}); });