Skip to content

Commit

Permalink
Removes JSONStream dependency
Browse files Browse the repository at this point in the history
Works directly using jsonparse.
  • Loading branch information
Tpt committed Jul 8, 2022
1 parent 2109894 commit 4637324
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 68 deletions.
1 change: 0 additions & 1 deletion index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export * from "./lib/SparqlJsonParser";
export * from "./lib/SparqlJsonBindingsTransformer";
21 changes: 0 additions & 21 deletions lib/SparqlJsonBindingsTransformer.ts

This file was deleted.

48 changes: 35 additions & 13 deletions lib/SparqlJsonParser.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import {DataFactory} from "rdf-data-factory";
import * as RDF from "@rdfjs/types";
import {SparqlJsonBindingsTransformer} from "./SparqlJsonBindingsTransformer";
import {Transform} from "readable-stream";

// tslint:disable-next-line:no-var-requires
const JsonParser = require('jsonparse');

/**
* Parser for the SPARQL 1.1 Query Results JSON format.
Expand Down Expand Up @@ -38,14 +41,25 @@ export class SparqlJsonParser {
public parseJsonResultsStream(sparqlResponseStream: NodeJS.ReadableStream): NodeJS.ReadableStream {
const errorListener = (error: Error) => resultStream.emit('error', error);
sparqlResponseStream.on('error', errorListener);
const variables: RDF.Variable[] = [];
sparqlResponseStream
.pipe(require('JSONStream').parse('head.vars.*').on('error', errorListener))
.on('data', (variable: string) => variables.push(this.dataFactory.variable(variable)))
.on('end', () => resultStream.emit('variables', variables));

const jsonParser = new JsonParser();
jsonParser.onError = errorListener;
jsonParser.onValue = (value: any) => {
if(jsonParser.key === "vars" && jsonParser.stack.length === 2 && jsonParser.stack[1].key === 'head') {
resultStream.emit('variables', value.map((v: string) => this.dataFactory.variable(v)))
} else if(typeof jsonParser.key === 'number' && jsonParser.stack.length === 3 && jsonParser.stack[1].key === 'results' && jsonParser.stack[2].key === 'bindings') {
resultStream.push(this.parseJsonBindings(value))
}
}

const resultStream = sparqlResponseStream
.pipe(require('JSONStream').parse('results.bindings.*').on('error', errorListener))
.pipe(new SparqlJsonBindingsTransformer(this));
.pipe(new Transform({
objectMode: true,
transform(chunk: any, encoding: string, callback: (error?: Error | null, data?: any) => void) {
jsonParser.write(chunk);
callback();
}
}));
return resultStream;
}

Expand Down Expand Up @@ -102,14 +116,21 @@ export class SparqlJsonParser {
* Convert a SPARQL JSON boolean response stream to a promise resolving to a boolean.
* This will reject if the given reponse was not a valid boolean response.
* @param {NodeJS.ReadableStream} sparqlResponseStream A SPARQL JSON response stream.
* @return {NodeJS.ReadableStream} A stream of bindings.
* @return {Promise<boolean>} The response boolean.
*/
public parseJsonBooleanStream(sparqlResponseStream: NodeJS.ReadableStream): Promise<boolean> {
return new Promise((resolve, reject) => {
sparqlResponseStream.on('error', reject);
sparqlResponseStream.pipe(require('JSONStream').parse('boolean'))
.on('data', resolve)
.on('end', () => reject(new Error('No valid ASK response was found.')));
const parser = new JsonParser();
parser.onError = reject;
parser.onValue = (value: any) => {
if(parser.key === "boolean" && typeof value === 'boolean' && parser.stack.length === 1) {
resolve(value);
}
}
sparqlResponseStream
.on('error', reject)
.on('data', d => parser.write(d))
.on('end', () => reject(new Error('No valid ASK response was found.')));
});
}

Expand All @@ -135,3 +156,4 @@ export interface ISettings {
export interface IBindings {
[key: string]: RDF.Term;
}

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
"@rdfjs/types": "*",
"@types/node": "^18.0.0",
"@types/readable-stream": "^2.3.13",
"JSONStream": "^1.3.3",
"jsonparse": "^1.3.1",
"rdf-data-factory": "^1.1.0"
},
"sideEffects": false
Expand Down
32 changes: 14 additions & 18 deletions test/SparqlJsonParser-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,43 +112,39 @@ describe('SparqlJsonParser', () => {
it('should convert a SPARQL JSON response', async () => {
return expect(await arrayifyStream(parser.parseJsonResultsStream(streamifyString(`
{
"head": { "vars": [ "book" ] },
"head": { "vars": [ "book", "library" ] },
"results": {
"bindings": [
{ "book": { "type": "uri", "value": "http://example.org/book/book1" } },
{ "book": { "type": "uri", "value": "http://example.org/book/book2" } },
{ "book": { "type": "uri", "value": "http://example.org/book/book3" } },
{ "book": { "type": "uri", "value": "http://example.org/book/book4" } },
{ "book": { "type": "uri", "value": "http://example.org/book/book5" } }
{ "book": { "type": "uri", "value": "http://example.org/book/book1" }, "library": { "type": "uri", "value": "http://example.org/book/library1" } },
{ "book": { "type": "uri", "value": "http://example.org/book/book2" }, "library": { "type": "uri", "value": "http://example.org/book/library2" } },
{ "book": { "type": "uri", "value": "http://example.org/book/book3" }, "library": { "type": "uri", "value": "http://example.org/book/library3" } },
{ "book": { "type": "uri", "value": "http://example.org/book/book4" }, "library": { "type": "uri", "value": "http://example.org/book/library4" } },
{ "book": { "type": "uri", "value": "http://example.org/book/book5" }, "library": { "type": "uri", "value": "http://example.org/book/library5" } }
]
}
}
`)))).toEqual([
{ '?book': DF.namedNode('http://example.org/book/book1') },
{ '?book': DF.namedNode('http://example.org/book/book2') },
{ '?book': DF.namedNode('http://example.org/book/book3') },
{ '?book': DF.namedNode('http://example.org/book/book4') },
{ '?book': DF.namedNode('http://example.org/book/book5') },
{ '?book': DF.namedNode('http://example.org/book/book1'), '?library': DF.namedNode('http://example.org/book/library1') },
{ '?book': DF.namedNode('http://example.org/book/book2'), '?library': DF.namedNode('http://example.org/book/library2') },
{ '?book': DF.namedNode('http://example.org/book/book3'), '?library': DF.namedNode('http://example.org/book/library3') },
{ '?book': DF.namedNode('http://example.org/book/book4'), '?library': DF.namedNode('http://example.org/book/library4') },
{ '?book': DF.namedNode('http://example.org/book/book5'), '?library': DF.namedNode('http://example.org/book/library5') },
]);
});

it('should convert a SPARQL JSON response and emit the variables', async () => {
const stream = parser.parseJsonResultsStream(streamifyString(`
{
"head": { "vars": [ "book" ] },
"head": { "vars": [ "book", "library" ] },
"results": {
"bindings": [
{ "book": { "type": "uri", "value": "http://example.org/book/book1" } },
{ "book": { "type": "uri", "value": "http://example.org/book/book2" } },
{ "book": { "type": "uri", "value": "http://example.org/book/book3" } },
{ "book": { "type": "uri", "value": "http://example.org/book/book4" } },
{ "book": { "type": "uri", "value": "http://example.org/book/book5" } }
{ "book": { "type": "uri", "value": "http://example.org/book/book1" }, "library": { "type": "uri", "value": "http://example.org/book/library1" } }
]
}
}
`));
return expect(new Promise((resolve) => stream.on('variables', resolve))).resolves.toEqualRdfTermArray([
DF.variable('book'),
DF.variable('book'), DF.variable('library')
]);
});

Expand Down
15 changes: 1 addition & 14 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -676,14 +676,6 @@
dependencies:
"@types/yargs-parser" "*"

JSONStream@^1.3.3:
version "1.3.5"
resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0"
integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==
dependencies:
jsonparse "^1.2.0"
through ">=2.2.7 <3"

ajv@^6.12.3:
version "6.12.6"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
Expand Down Expand Up @@ -2062,7 +2054,7 @@ json5@^2.2.1:
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c"
integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==

jsonparse@^1.2.0:
jsonparse@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==
Expand Down Expand Up @@ -3051,11 +3043,6 @@ through2@^4.0.0:
dependencies:
readable-stream "3"

"through@>=2.2.7 <3":
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==

tmpl@1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc"
Expand Down

0 comments on commit 4637324

Please sign in to comment.