diff --git a/.changeset/breezy-flies-add.md b/.changeset/breezy-flies-add.md new file mode 100644 index 0000000..ae5e10c --- /dev/null +++ b/.changeset/breezy-flies-add.md @@ -0,0 +1,6 @@ +--- +'@rdfjs-elements/formats-pretty': patch +'@rdfjs-elements/rdf-editor': patch +--- + +Parsing n3 rules would fail. Using the package [n3](https://npm.im/n3) to support them. diff --git a/package-lock.json b/package-lock.json index d699868..333a02f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4689,10 +4689,11 @@ } }, "node_modules/@zazuko/env-node": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@zazuko/env-node/-/env-node-2.1.2.tgz", - "integrity": "sha512-w3qNtSh5ekm+gthXGPA+vZ6zP49vAHWwT1xaO83vqTNs63CMOsYnV3OtZavuyg882S+SBTj/mu7RNSUb5zO0ag==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@zazuko/env-node/-/env-node-2.1.4.tgz", + "integrity": "sha512-D3pw3T3SpC6lI3D5Akio/63lWaI9VKWazVGcjWP0gC598JQ60V7T+4QSCUcxT0ZGTDOkNdT3loYR9P+JK96KeQ==", "dev": true, + "license": "MIT", "dependencies": { "@rdfjs/fetch-lite": "^3.2.2", "@rdfjs/formats": "^4.0.0", @@ -4700,7 +4701,8 @@ "@zazuko/rdf-utils-fs": "^3.3.0" }, "peerDependencies": { - "@types/rdfjs__fetch-lite": "^3.0.6" + "@types/rdfjs__fetch-lite": "^3.0.6", + "@types/rdfjs__formats": "^4" } }, "node_modules/@zazuko/env/node_modules/get-stream": { @@ -11881,11 +11883,12 @@ "license": "MIT" }, "node_modules/n3": { - "version": "1.16.4", - "resolved": "https://registry.npmjs.org/n3/-/n3-1.16.4.tgz", - "integrity": "sha512-jtC53efM5/q4BYC3qBnegn1MJDKXHH9PEd6gVDNpIicbgXS6gkANz4DdI0jt4aLvza1xSjCcni33riXWvfoEdw==", + "version": "1.23.1", + "resolved": "https://registry.npmjs.org/n3/-/n3-1.23.1.tgz", + "integrity": "sha512-3f0IYJo+6+lXypothmlwPzm3wJNffsxUwnfONeFv2QqWq7RjTvyCMtkRXDUXW6XrZoOzaQX8xTTSYNlGjXcGtw==", "license": "MIT", "dependencies": { + "buffer": "^6.0.3", "queue-microtask": "^1.1.2", "readable-stream": "^4.0.0" }, @@ -15898,6 +15901,7 @@ "@tpluscode/rdf-ns-builders": ">=3.0.2", "@zazuko/formats-lazy": "^1.0.1", "@zazuko/prefixes": "^2.0.0", + "n3": "^1.23.1", "readable-stream": ">=3.6.0" }, "devDependencies": { @@ -15907,7 +15911,7 @@ "@types/rdfjs__formats": "^4", "@types/rdfjs__term-map": "^2", "@types/rdfjs__term-set": "^2", - "@zazuko/env-node": "^2.1.1", + "@zazuko/env-node": "^2.1.4", "@zazuko/prefixes": "^2.0.0", "@zazuko/rdf-utils-fs": "^3.3.1", "chai": "^4.3.4", @@ -15953,6 +15957,7 @@ "@rdfjs/environment": "^1", "@rdfjs/formats": "^4", "@tpluscode/rdf-ns-builders": ">=3.0.2", + "@zazuko/formats-lazy": "^1.0.1", "readable-stream": "^3", "string-to-stream": "^3.0.1" }, diff --git a/packages/formats/index.js b/packages/formats/index.js index dcb6587..adff3bb 100644 --- a/packages/formats/index.js +++ b/packages/formats/index.js @@ -7,6 +7,7 @@ import { } from './serializers/graphy.js' import { TrigParser, NQuadsParser } from './parsers/graphy.js' import JsonLdSerializer from './serializers/jsonld.js' +import { N3Parser } from './parsers/n3.js' const formats = new Formats({}) formats.import(formatsCommon) @@ -32,7 +33,7 @@ formats.serializers.set(mediaTypes.turtle, new TurtleSerializer()) formats.serializers.set(mediaTypes.trig, new TrigSerializer()) formats.serializers.set(mediaTypes.rdfXml, new RdfXmlSerializer()) -formats.parsers.set(mediaTypes.notation3, new TrigParser()) +formats.parsers.set(mediaTypes.notation3, new N3Parser()) formats.parsers.set(mediaTypes.turtle, new TrigParser()) formats.parsers.set(mediaTypes.trig, new TrigParser()) formats.parsers.set(mediaTypes.ntriples, new NQuadsParser()) diff --git a/packages/formats/package.json b/packages/formats/package.json index a59ae59..6db7f42 100644 --- a/packages/formats/package.json +++ b/packages/formats/package.json @@ -36,6 +36,7 @@ "@tpluscode/rdf-ns-builders": ">=3.0.2", "@zazuko/formats-lazy": "^1.0.1", "@zazuko/prefixes": "^2.0.0", + "n3": "^1.23.1", "readable-stream": ">=3.6.0" }, "devDependencies": { @@ -45,7 +46,7 @@ "@types/rdfjs__formats": "^4", "@types/rdfjs__term-map": "^2", "@types/rdfjs__term-set": "^2", - "@zazuko/env-node": "^2.1.1", + "@zazuko/env-node": "^2.1.4", "@zazuko/prefixes": "^2.0.0", "@zazuko/rdf-utils-fs": "^3.3.1", "chai": "^4.3.4", diff --git a/packages/formats/parsers/n3.js b/packages/formats/parsers/n3.js new file mode 100644 index 0000000..f6f58c4 --- /dev/null +++ b/packages/formats/parsers/n3.js @@ -0,0 +1,13 @@ +import { lazySink } from '@zazuko/formats-lazy/LazySink.js' + +export const N3Parser = lazySink(async () => { + const n3 = await import('n3') + return class { + // eslint-disable-next-line class-methods-use-this + import(quadStream, options) { + return new n3.StreamParser({ format: 'text/n3' }).import(quadStream, { + ...options, + }) + } + } +}) diff --git a/packages/formats/test/index.test.js b/packages/formats/test/index.test.js index 112f0b7..4b8335d 100644 --- a/packages/formats/test/index.test.js +++ b/packages/formats/test/index.test.js @@ -6,6 +6,7 @@ import * as ns from '@tpluscode/rdf-ns-builders' import getStream from 'get-stream' import { join, dirname } from 'path' import { fileURLToPath } from 'url' +import { Transform } from 'readable-stream' import formats, { mediaTypes } from '../index.js' const { parsers, serializers } = formats @@ -40,6 +41,25 @@ describe('@rdfjs-elements/formats-pretty', () => { ) }) }) + + describe('n3', () => { + it('parses a N3 document with rules', async () => { + // given + const input = `{ + ?s a ?o . + ?o ?o2 . +} => { + ?s a ?o2 . +} .` + + // when + const quads = parsers.import(mediaTypes.notation3, toStream(input)) + const dataset = await $rdf.dataset().import(quads) + + // then + expect(dataset.size).to.eq(4) + }) + }) }) describe('serializers', () => { @@ -68,20 +88,28 @@ describe('@rdfjs-elements/formats-pretty', () => { for (const format of Object.values(mediaTypes)) { it(`graph ${file} in format ${format}`, async () => { // given - const graph = await $rdf + const data = await $rdf .dataset() .import($rdf.fromFile(join(__dirname, `graphs/${file}`))) // when const serialized = await getStream( - serializers.import(format, graph.toStream()) + serializers.import(format, data.toStream()) ) - const roundTrip = await $rdf - .dataset() - .import(parsers.import(format, toStream(serialized))) + const parserStream = parsers + .import(format, toStream(serialized)) + .pipe( + new Transform({ + objectMode: true, + transform({ subject, predicate, object, graph }, _, callback) { + callback(null, $rdf.quad(subject, predicate, object, graph)) + }, + }) + ) + const roundTrip = await $rdf.dataset().import(parserStream) // then - expect(roundTrip.toCanonical()).to.eq(graph.toCanonical()) + expect(roundTrip.toCanonical()).to.eq(data.toCanonical()) }) } }