Skip to content

Commit

Permalink
feat: set mime type of incoming data
Browse files Browse the repository at this point in the history
  • Loading branch information
jenspots committed Apr 7, 2024
1 parent 634b681 commit 33ca58f
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 25 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ Validate an incoming data stream using SHACL. If the incoming data is valid, it
- `outgoing`: channel into which valid data is written.
- `report`: an optional channel into which the SHACL reports of invalid input data is written. (default: `null`)
- `validationIsFatal`: throw a fatal error if validation fails. (default: `false`)
- `mime`: the internet media type of the incoming data used to initialize the parser. (default: `text/turtle`)

## Limitations

At the time of writing, all files are read and serialized in the Turtle format. Additional options may be available in the future.
The file type of the incoming data must be known beforehand and be set using the `mime` parameter in order to initialize the parser. Type agnostic parsers may be available in the feature, making this setting redundant.

Turtle prefixes are hard coded for the time being. Ideally, these should be based on the prefixes used in the input data, or omitted at the user's request.
SHACL reports are outputted in Turtle using humanized formatting. Prefixes are hard coded for the time being. Ideally, these should be based on the prefixes used in the input data, or omitted at the user's request. Other file types should be made available as well.

```ts
const prefixes = new PrefixMapFactory().prefixMap();
Expand Down
24 changes: 12 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions processors.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ js:Validate a js:JsProcess;
sh:path js:validationIsFatal;
sh:name "validationIsFatal";
sh:maxCount 1;
], [
sh:datatype xsd:string;
sh:path js:mime;
sh:name "MIME type";
sh:maxCount 1;
].

[ ] a sh:NodeShape;
Expand Down
14 changes: 12 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,27 @@ type ValidateArguments = {
incoming: Stream<string>;
outgoing: Writer<string>;
report?: Writer<string>;
mime?: string;
validationIsFatal?: boolean;
};

export async function validate(args: ValidateArguments): Promise<() => void> {
const { shaclPath, incoming, outgoing, report, validationIsFatal } = args;
const { shaclPath, incoming, outgoing, report } = args;

// Default arguments.
const mime = args.mime ?? "text/turtle";
const validationIsFatal = args.validationIsFatal ?? false;

// Initialize the shared serializer.
const prefixes = new PrefixMapFactory().prefixMap();
prefixes.set("sh", rdf.namedNode("http://www.w3.org/ns/shacl#"));
const serializer = new Serializer({ prefixes });
const parser = rdf.formats.parsers.get("text/turtle")!;

// Initialize the data parser.
const parser = rdf.formats.parsers.get(mime);
if (!parser) {
throw ShaclError.invalidRdfFormat();
}

// Extend formatting with pretty formats.
rdf.formats.import(formatsPretty);
Expand Down
1 change: 1 addition & 0 deletions tests/data/valid.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"@id":"http://example.org#Point"},{"@id":"http://example.org#ValidPoint","@type":["http://example.org#Point"],"http://example.org#x":[{"@value":1}],"http://example.org#y":[{"@value":2}]}]
3 changes: 3 additions & 0 deletions tests/data/valid.nt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<http://example.org#ValidPoint> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org#Point> .
<http://example.org#ValidPoint> <http://example.org#x> "1"^^<http://www.w3.org/2001/XMLSchema#integer> .
<http://example.org#ValidPoint> <http://example.org#y> "2"^^<http://www.w3.org/2001/XMLSchema#integer> .
34 changes: 34 additions & 0 deletions tests/error.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,19 @@ describe("errors", () => {
expect(func()).rejects.toThrow(ShaclError.fileSystemError());
});

test("invalid data rdf format", async () => {
expect.assertions(1);

const func = validate({
shaclPath,
incoming: new SimpleStream<string>(),
outgoing: new SimpleStream<string>(),
mime: "text/invalid",
});

expect(func).rejects.toThrowError(ShaclError.invalidRdfFormat());
});

test("invalid shacl rdf format", async () => {
expect.assertions(1);

Expand Down Expand Up @@ -74,4 +87,25 @@ describe("errors", () => {

await incoming.end();
});

test("incorrect mime", async () => {
expect.assertions(1);

const validJsonLd = fs
.readFileSync("./tests/data/valid.jsonld")
.toString();
const incoming = new SimpleStream<string>();

const func = await validate({
shaclPath,
incoming,
outgoing: new SimpleStream<string>(),
mime: "text/turtle",
});
func();

expect(async () => {
await incoming.push(validJsonLd);
}).rejects.toThrow(ShaclError.invalidRdfFormat());
});
});
43 changes: 34 additions & 9 deletions tests/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { validate } from "../src";
import { SimpleStream } from "@ajuvercr/js-runner";
import { describe, test, expect, beforeEach } from "vitest";
import * as fs from "fs";
import { ShaclError } from "../src/error";

// Channel which streams incoming RDF.
let incoming: SimpleStream<string>;
Expand All @@ -16,6 +17,7 @@ let reportData: string;

// Valid point.
const validRdfData = fs.readFileSync("./tests/data/valid.ttl").toString();
const validNTriples = fs.readFileSync("./tests/data/valid.nt").toString();

// Invalid point.
const invalidRdfData = fs.readFileSync("./tests/data/invalid.ttl").toString();
Expand Down Expand Up @@ -53,18 +55,20 @@ beforeEach(async () => {
report.on("data", (data) => {
reportData += data;
});

// Restart the processor, which is the same for each test.
const func = await validate({
shaclPath,
incoming,
outgoing,
report,
});
func();
});

describe("shacl", () => {
beforeEach(async () => {
// Restart the processor, which is the same for each test.
const func = await validate({
shaclPath,
incoming,
outgoing,
report,
});
func();
});

test("successful", async () => {
expect.assertions(2);

Expand Down Expand Up @@ -95,3 +99,24 @@ describe("shacl", () => {
expect(reportData).toEqual("");
});
});

describe("shacl - config", () => {
test("mime", async () => {
expect.assertions(2);

const func = await validate({
shaclPath,
incoming,
outgoing,
report,
mime: "application/n-triples",
});
func();

await incoming.push(validNTriples);
await endAll();

expect(outgoingData).toEqual(validNTriples);
expect(reportData).toEqual("");
});
});

0 comments on commit 33ca58f

Please sign in to comment.