From 052e2b2339078a2ab5055859022bfdc108eebe38 Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Thu, 29 Sep 2016 16:10:23 +0200 Subject: [PATCH 01/34] Add Term and NamedNode. --- N3.js | 5 +++ lib/Datatypes.js | 49 ++++++++++++++++++++++++ test/NamedNode-test.js | 85 ++++++++++++++++++++++++++++++++++++++++++ test/Term-test.js | 17 +++++++++ 4 files changed, 156 insertions(+) create mode 100644 lib/Datatypes.js create mode 100644 test/NamedNode-test.js create mode 100644 test/Term-test.js diff --git a/N3.js b/N3.js index 3fd779bd..4646847f 100644 --- a/N3.js +++ b/N3.js @@ -24,3 +24,8 @@ Object.keys(exports).forEach(function (submodule) { }, }); }); + +// Load data types directly +var Core = globalRequire('./lib/Datatypes'); +for (var type in Core) + exports[type] = Core[type]; diff --git a/lib/Datatypes.js b/lib/Datatypes.js new file mode 100644 index 00000000..d521dd3c --- /dev/null +++ b/lib/Datatypes.js @@ -0,0 +1,49 @@ +// N3.js implementations of the RDF/JS core data types +// See https://github.com/rdfjs/representation-task-force/blob/master/interface-spec.md + +// ## Term constructor +function Term(id) { + if (!(this instanceof Term)) + return new Term(id); + this.id = id; +} +// ### Makes this class a subclass of the given type +Term.subclass = function subclass(Type) { + Type.prototype = Object.create(this.prototype, { + constructor: { value: Type }, + termType: { value: Type.name }, + }); + Type.subclass = subclass; +}; + +// ### Returns whether this object represents the same term as the other +Term.prototype.equals = function (other) { + // If both terms were created by this library, + // equality can be computed through ids + if (other instanceof Term) + return this.id === other.id; + // Otherwise, compare term type and value + return !!other && this.termType === other.termType && + this.value === other.value; +}; + + +// ## NamedNode constructor +function NamedNode(iri) { + if (!(this instanceof NamedNode)) + return new NamedNode(iri); + this.id = iri; +} +Term.subclass(NamedNode); + +// ### The IRI of this named node +Object.defineProperty(NamedNode.prototype, 'value', { + get: function () { return this.id; }, +}); + + +// ## Module exports +module.exports = { + Term: Term, + NamedNode: NamedNode, +}; diff --git a/test/NamedNode-test.js b/test/NamedNode-test.js new file mode 100644 index 00000000..380b76f3 --- /dev/null +++ b/test/NamedNode-test.js @@ -0,0 +1,85 @@ +var NamedNode = require('../N3').NamedNode; + +var Term = require('../N3').Term; + +describe('NamedNode', function () { + describe('The NamedNode module', function () { + it('should be a function', function () { + NamedNode.should.be.a('function'); + }); + + it('should make NamedNode objects', function () { + NamedNode().should.be.an.instanceof(NamedNode); + }); + + it('should make Term objects', function () { + NamedNode().should.be.an.instanceof(Term); + }); + + it('should be a NamedNode constructor', function () { + new NamedNode().should.be.an.instanceof(NamedNode); + }); + + it('should be a Term constructor', function () { + new NamedNode().should.be.an.instanceof(Term); + }); + }); + + describe('A NamedNode instance created from an IRI', function () { + var namedNode; + before(function () { namedNode = new NamedNode('http://example.org/foo#bar'); }); + + it('should be a NamedNode', function () { + namedNode.should.be.an.instanceof(NamedNode); + }); + + it('should be a Term', function () { + namedNode.should.be.an.instanceof(Term); + }); + + it('should have term type "NamedNode"', function () { + namedNode.termType.should.equal('NamedNode'); + }); + + it('should have the IRI as value', function () { + namedNode.should.have.property('value', 'http://example.org/foo#bar'); + }); + + it('should have the IRI as id', function () { + namedNode.should.have.property('id', 'http://example.org/foo#bar'); + }); + + it('should equal a NamedNode instance with the same IRI', function () { + namedNode.equals(new NamedNode('http://example.org/foo#bar')).should.be.true; + }); + + it('should equal an object with the same term type and value', function () { + namedNode.equals({ + termType: 'NamedNode', + value: 'http://example.org/foo#bar', + }).should.be.true; + }); + + it('should not equal a falsy object', function () { + namedNode.equals(null).should.be.false; + }); + + it('should not equal a NamedNode instance with another IRI', function () { + namedNode.equals(new NamedNode('http://example.org/other')).should.be.false; + }); + + it('should not equal an object with the same term type but a different value', function () { + namedNode.equals({ + termType: 'NamedNode', + value: 'http://example.org/other', + }).should.be.false; + }); + + it('should not equal an object with a different term type but the same value', function () { + namedNode.equals({ + termType: 'BlankNode', + value: 'http://example.org/foo#bar', + }).should.be.false; + }); + }); +}); diff --git a/test/Term-test.js b/test/Term-test.js new file mode 100644 index 00000000..a84dbad1 --- /dev/null +++ b/test/Term-test.js @@ -0,0 +1,17 @@ +var Term = require('../N3').Term; + +describe('Term', function () { + describe('The Term module', function () { + it('should be a function', function () { + Term.should.be.a('function'); + }); + + it('should make Term objects', function () { + Term().should.be.an.instanceof(Term); + }); + + it('should be a Term constructor', function () { + new Term().should.be.an.instanceof(Term); + }); + }); +}); From b8b898d743edcb903cc6dbcc78ce561a7ac190f8 Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Thu, 29 Sep 2016 16:17:26 +0200 Subject: [PATCH 02/34] Add BlankNode. --- lib/Datatypes.js | 15 ++++++++ test/BlankNode-test.js | 85 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 test/BlankNode-test.js diff --git a/lib/Datatypes.js b/lib/Datatypes.js index d521dd3c..0b35a3a3 100644 --- a/lib/Datatypes.js +++ b/lib/Datatypes.js @@ -42,8 +42,23 @@ Object.defineProperty(NamedNode.prototype, 'value', { }); +// ## BlankNode constructor +function BlankNode(name) { + if (!(this instanceof BlankNode)) + return new BlankNode(name); + this.id = '_:' + name; +} +Term.subclass(BlankNode); + +// ### The name of this blank node +Object.defineProperty(BlankNode.prototype, 'value', { + get: function () { return this.id.substr(2); }, +}); + + // ## Module exports module.exports = { Term: Term, NamedNode: NamedNode, + BlankNode: BlankNode, }; diff --git a/test/BlankNode-test.js b/test/BlankNode-test.js new file mode 100644 index 00000000..681c3184 --- /dev/null +++ b/test/BlankNode-test.js @@ -0,0 +1,85 @@ +var BlankNode = require('../N3').BlankNode; + +var Term = require('../N3').Term; + +describe('BlankNode', function () { + describe('The BlankNode module', function () { + it('should be a function', function () { + BlankNode.should.be.a('function'); + }); + + it('should make BlankNode objects', function () { + BlankNode().should.be.an.instanceof(BlankNode); + }); + + it('should make Term objects', function () { + BlankNode().should.be.an.instanceof(Term); + }); + + it('should be a BlankNode constructor', function () { + new BlankNode().should.be.an.instanceof(BlankNode); + }); + + it('should be a Term constructor', function () { + new BlankNode().should.be.an.instanceof(Term); + }); + }); + + describe('A BlankNode instance created from a name', function () { + var blankNode; + before(function () { blankNode = new BlankNode('b1'); }); + + it('should be a BlankNode', function () { + blankNode.should.be.an.instanceof(BlankNode); + }); + + it('should be a Term', function () { + blankNode.should.be.an.instanceof(Term); + }); + + it('should have term type "BlankNode"', function () { + blankNode.termType.should.equal('BlankNode'); + }); + + it('should have the name as value', function () { + blankNode.should.have.property('value', 'b1'); + }); + + it('should have "_:name" as id', function () { + blankNode.should.have.property('id', '_:b1'); + }); + + it('should equal a BlankNode instance with the same name', function () { + blankNode.equals(new BlankNode('b1')).should.be.true; + }); + + it('should equal an object with the same term type and value', function () { + blankNode.equals({ + termType: 'BlankNode', + value: 'b1', + }).should.be.true; + }); + + it('should not equal a falsy object', function () { + blankNode.equals(null).should.be.false; + }); + + it('should not equal a BlankNode instance with another name', function () { + blankNode.equals(new BlankNode('b2')).should.be.false; + }); + + it('should not equal an object with the same term type but a different value', function () { + blankNode.equals({ + termType: 'BlankNode', + value: 'b2', + }).should.be.false; + }); + + it('should not equal an object with a different term type but the same value', function () { + blankNode.equals({ + termType: 'NamedNode', + value: 'b1', + }).should.be.false; + }); + }); +}); From 5f8ff592f3f2ee635c0d1d951c873e8e04cab3ed Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Thu, 29 Sep 2016 16:24:01 +0200 Subject: [PATCH 03/34] Add Variable. --- lib/Datatypes.js | 17 ++++++++- test/Variable-test.js | 85 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 test/Variable-test.js diff --git a/lib/Datatypes.js b/lib/Datatypes.js index 0b35a3a3..897b72f8 100644 --- a/lib/Datatypes.js +++ b/lib/Datatypes.js @@ -56,9 +56,24 @@ Object.defineProperty(BlankNode.prototype, 'value', { }); +// ## Variable constructor +function Variable(name) { + if (!(this instanceof Variable)) + return new Variable(name); + this.id = '?' + name; +} +Term.subclass(Variable); + +// ### The name of this variable +Object.defineProperty(Variable.prototype, 'value', { + get: function () { return this.id.substr(1); }, +}); + + // ## Module exports module.exports = { - Term: Term, + Term: Term, NamedNode: NamedNode, BlankNode: BlankNode, + Variable: Variable, }; diff --git a/test/Variable-test.js b/test/Variable-test.js new file mode 100644 index 00000000..cc6f4444 --- /dev/null +++ b/test/Variable-test.js @@ -0,0 +1,85 @@ +var Variable = require('../N3').Variable; + +var Term = require('../N3').Term; + +describe('Variable', function () { + describe('The Variable module', function () { + it('should be a function', function () { + Variable.should.be.a('function'); + }); + + it('should make Variable objects', function () { + Variable().should.be.an.instanceof(Variable); + }); + + it('should make Term objects', function () { + Variable().should.be.an.instanceof(Term); + }); + + it('should be a Variable constructor', function () { + new Variable().should.be.an.instanceof(Variable); + }); + + it('should be a Term constructor', function () { + new Variable().should.be.an.instanceof(Term); + }); + }); + + describe('A Variable instance created from a name', function () { + var variable; + before(function () { variable = new Variable('v1'); }); + + it('should be a Variable', function () { + variable.should.be.an.instanceof(Variable); + }); + + it('should be a Term', function () { + variable.should.be.an.instanceof(Term); + }); + + it('should have term type "Variable"', function () { + variable.termType.should.equal('Variable'); + }); + + it('should have the name as value', function () { + variable.should.have.property('value', 'v1'); + }); + + it('should have "?name" as id value', function () { + variable.should.have.property('id', '?v1'); + }); + + it('should equal a Variable instance with the same name', function () { + variable.equals(new Variable('v1')).should.be.true; + }); + + it('should equal an object with the same term type and value', function () { + variable.equals({ + termType: 'Variable', + value: 'v1', + }).should.be.true; + }); + + it('should not equal a falsy object', function () { + variable.equals(null).should.be.false; + }); + + it('should not equal a Variable instance with another name', function () { + variable.equals(new Variable('v2')).should.be.false; + }); + + it('should not equal an object with the same term type but a different value', function () { + variable.equals({ + termType: 'Variable', + value: 'v2', + }).should.be.false; + }); + + it('should not equal an object with a different term type but the same value', function () { + variable.equals({ + termType: 'NamedNode', + value: 'v1', + }).should.be.false; + }); + }); +}); From eeea1821c5f40ed07d4fb7a4c20041cd6974bfcf Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Thu, 29 Sep 2016 17:45:59 +0200 Subject: [PATCH 04/34] Add Literal. --- lib/Datatypes.js | 55 ++++ test/Literal-test.js | 580 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 635 insertions(+) create mode 100644 test/Literal-test.js diff --git a/lib/Datatypes.js b/lib/Datatypes.js index 897b72f8..facec10d 100644 --- a/lib/Datatypes.js +++ b/lib/Datatypes.js @@ -70,10 +70,65 @@ Object.defineProperty(Variable.prototype, 'value', { }); +// ## Literal constructor +function Literal(id) { + if (!(this instanceof Literal)) + return new Literal(id); + this.id = id; +} +Term.subclass(Literal); + +// ### The text value of this literal +Object.defineProperty(Literal.prototype, 'value', { + get: function () { + return this.id.substring(1, this.id.indexOf('"', 1)); + }, +}); + +// ### The language of this literal +Object.defineProperty(Literal.prototype, 'language', { + get: function () { + // Find the last quotation mark (e.g., '"abc"@en-us') + var id = this.id, atPos = id.lastIndexOf('"') + 1; + // If "@" it follows, return the remaining substring; empty otherwise + return atPos < id.length && id[atPos++] === '@' ? id.substr(atPos) : ''; + }, +}); + +// ### The datatype of this literal +Object.defineProperty(Literal.prototype, 'datatype', { + get: function () { + // Find the last quotation mark (e.g., '"abc"^^http://ex.org/types#t') + var id = this.id, dtPos = id.lastIndexOf('"') + 1, ch; + // If "^" it follows, return the remaining substring + var type = dtPos < id.length && (ch = id[dtPos]) === '^' ? id.substr(dtPos + 2) : + // If "@" follows, return rdf:langString; xsd:string otherwise + (ch === '@' ? 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString' + : 'http://www.w3.org/2001/XMLSchema#string'); + return new NamedNode(type); + }, +}); + +// ### Returns whether this object represents the same term as the other +Literal.prototype.equals = function (other) { + // If both literals were created by this library, + // equality can be computed through ids + if (other instanceof Literal) + return this.id === other.id; + // Otherwise, compare term type, value, language, and datatype + return !!other && !!other.datatype && + this.termType === other.termType && + this.value === other.value && + this.language === other.language && + this.datatype.value === other.datatype.value; +}; + + // ## Module exports module.exports = { Term: Term, NamedNode: NamedNode, BlankNode: BlankNode, Variable: Variable, + Literal: Literal, }; diff --git a/test/Literal-test.js b/test/Literal-test.js new file mode 100644 index 00000000..13e20753 --- /dev/null +++ b/test/Literal-test.js @@ -0,0 +1,580 @@ +var Literal = require('../N3').Literal; + +var Term = require('../N3').Term; +var NamedNode = require('../N3').NamedNode; + +describe('Literal', function () { + describe('The Literal module', function () { + it('should be a function', function () { + Literal.should.be.a('function'); + }); + + it('should make Literal objects', function () { + Literal().should.be.an.instanceof(Literal); + }); + + it('should make Term objects', function () { + Literal().should.be.an.instanceof(Term); + }); + + it('should be a Literal constructor', function () { + new Literal().should.be.an.instanceof(Literal); + }); + + it('should be a Term constructor', function () { + new Literal().should.be.an.instanceof(Term); + }); + }); + + describe('A Literal instance created from the empty string without language or datatype', function () { + var literal; + before(function () { literal = new Literal('""'); }); + + it('should be a Literal', function () { + literal.should.be.an.instanceof(Literal); + }); + + it('should be a Term', function () { + literal.should.be.an.instanceof(Term); + }); + + it('should have term type "Literal"', function () { + literal.termType.should.equal('Literal'); + }); + + it('should have the empty string as value', function () { + literal.should.have.property('value', ''); + }); + + it('should have the empty string as language', function () { + literal.should.have.property('language', ''); + }); + + it('should have xsd:string as datatype', function () { + literal.should.have.property('datatype'); + literal.datatype.should.be.an.instanceof(NamedNode); + literal.datatype.value.should.equal('http://www.w3.org/2001/XMLSchema#string'); + }); + + it('should have the quoted empty string as id', function () { + literal.should.have.property('id', '""'); + }); + + it('should equal a Literal instance with the same value', function () { + literal.equals(new Literal('""')).should.be.true; + }); + + it('should equal an object with the same term type, value, language, and datatype', function () { + literal.equals({ + termType: 'Literal', + value: '', + language: '', + datatype: { value: 'http://www.w3.org/2001/XMLSchema#string', termType: 'NamedNode' }, + }).should.be.true; + }); + + it('should not equal a falsy object', function () { + literal.equals(null).should.be.false; + }); + + it('should not equal a Literal instance with a non-empty value', function () { + literal.equals(new Literal('"x"')).should.be.false; + }); + + it('should not equal an object with the same term type but a different value', function () { + literal.equals({ + termType: 'Literal', + value: 'x', + language: '', + datatype: { value: 'http://www.w3.org/2001/XMLSchema#string', termType: 'NamedNode' }, + }).should.be.false; + }); + + it('should not equal an object with the same term type but a different language', function () { + literal.equals({ + termType: 'Literal', + value: '', + language: 'en', + datatype: { value: 'http://www.w3.org/2001/XMLSchema#string', termType: 'NamedNode' }, + }).should.be.false; + }); + + it('should not equal an object with the same term type but a different datatype', function () { + literal.equals({ + termType: 'Literal', + value: '', + language: '', + datatype: { value: 'other', termType: 'NamedNode' }, + }).should.be.false; + }); + + it('should not equal an object with a different term type', function () { + literal.equals({ + termType: 'NamedNode', + value: '', + language: '', + datatype: { value: 'http://www.w3.org/2001/XMLSchema#string', termType: 'NamedNode' }, + }).should.be.false; + }); + }); + + describe('A Literal instance created from a string without language or datatype', function () { + var literal; + before(function () { literal = new Literal('"my @^^ string"'); }); + + it('should be a Literal', function () { + literal.should.be.an.instanceof(Literal); + }); + + it('should be a Term', function () { + literal.should.be.an.instanceof(Term); + }); + + it('should have term type "Literal"', function () { + literal.termType.should.equal('Literal'); + }); + + it('should have the text value as value', function () { + literal.should.have.property('value', 'my @^^ string'); + }); + + it('should have the empty string as language', function () { + literal.should.have.property('language', ''); + }); + + it('should have xsd:string as datatype', function () { + literal.should.have.property('datatype'); + literal.datatype.should.be.an.instanceof(NamedNode); + literal.datatype.value.should.equal('http://www.w3.org/2001/XMLSchema#string'); + }); + + it('should have the quoted string as id', function () { + literal.should.have.property('id', '"my @^^ string"'); + }); + + it('should equal a Literal instance with the same value', function () { + literal.equals(new Literal('"my @^^ string"')).should.be.true; + }); + + it('should equal an object with the same term type, value, language, and datatype', function () { + literal.equals({ + termType: 'Literal', + value: 'my @^^ string', + language: '', + datatype: { value: 'http://www.w3.org/2001/XMLSchema#string', termType: 'NamedNode' }, + }).should.be.true; + }); + + it('should not equal a falsy object', function () { + literal.equals(null).should.be.false; + }); + + it('should not equal a Literal instance with another value', function () { + literal.equals(new Literal('"other string"')).should.be.false; + }); + + it('should not equal an object with the same term type but a different value', function () { + literal.equals({ + termType: 'Literal', + value: 'other string', + language: '', + datatype: { value: 'http://www.w3.org/2001/XMLSchema#string', termType: 'NamedNode' }, + }).should.be.false; + }); + + it('should not equal an object with the same term type but a different language', function () { + literal.equals({ + termType: 'Literal', + value: 'my @^^ string', + language: 'en', + datatype: { value: 'http://www.w3.org/2001/XMLSchema#string', termType: 'NamedNode' }, + }).should.be.false; + }); + + it('should not equal an object with the same term type but a different datatype', function () { + literal.equals({ + termType: 'Literal', + value: 'my @^^ string', + language: '', + datatype: { value: 'other', termType: 'NamedNode' }, + }).should.be.false; + }); + + it('should not equal an object with a different term type', function () { + literal.equals({ + termType: 'NamedNode', + value: 'my @^^ string', + language: '', + datatype: { value: 'http://www.w3.org/2001/XMLSchema#string', termType: 'NamedNode' }, + }).should.be.false; + }); + }); + + describe('A Literal instance created from the empty string with a language', function () { + var literal; + before(function () { literal = new Literal('""@en-us'); }); + + it('should be a Literal', function () { + literal.should.be.an.instanceof(Literal); + }); + + it('should be a Term', function () { + literal.should.be.an.instanceof(Term); + }); + + it('should have term type "Literal"', function () { + literal.termType.should.equal('Literal'); + }); + + it('should have the empty string as value', function () { + literal.should.have.property('value', ''); + }); + + it('should have the language tag as language', function () { + literal.should.have.property('language', 'en-us'); + }); + + it('should have rdf:langString as datatype', function () { + literal.should.have.property('datatype'); + literal.datatype.should.be.an.instanceof(NamedNode); + literal.datatype.value.should.equal('http://www.w3.org/1999/02/22-rdf-syntax-ns#langString'); + }); + + it('should have the quoted empty string as id', function () { + literal.should.have.property('id', '""@en-us'); + }); + + it('should equal a Literal instance with the same value', function () { + literal.equals(new Literal('""@en-us')).should.be.true; + }); + + it('should equal an object with the same term type, value, language, and datatype', function () { + literal.equals({ + termType: 'Literal', + value: '', + language: 'en-us', + datatype: { value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString', termType: 'NamedNode' }, + }).should.be.true; + }); + + it('should not equal a falsy object', function () { + literal.equals(null).should.be.false; + }); + + it('should not equal a Literal instance with a non-empty value', function () { + literal.equals(new Literal('"x"')).should.be.false; + }); + + it('should not equal an object with the same term type but a different value', function () { + literal.equals({ + termType: 'Literal', + value: 'x', + language: 'en-us', + datatype: { value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString', termType: 'NamedNode' }, + }).should.be.false; + }); + + it('should not equal an object with the same term type but a different language', function () { + literal.equals({ + termType: 'Literal', + value: '', + language: '', + datatype: { value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString', termType: 'NamedNode' }, + }).should.be.false; + }); + + it('should not equal an object with the same term type but a different datatype', function () { + literal.equals({ + termType: 'Literal', + value: '', + language: 'en-us', + datatype: { value: 'other', termType: 'NamedNode' }, + }).should.be.false; + }); + + it('should not equal an object with a different term type', function () { + literal.equals({ + termType: 'NamedNode', + value: '', + language: 'en-us', + datatype: { value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString', termType: 'NamedNode' }, + }).should.be.false; + }); + }); + + describe('A Literal instance created from a string without language or datatype', function () { + var literal; + before(function () { literal = new Literal('"my @^^ string"@en-us'); }); + + it('should be a Literal', function () { + literal.should.be.an.instanceof(Literal); + }); + + it('should be a Term', function () { + literal.should.be.an.instanceof(Term); + }); + + it('should have term type "Literal"', function () { + literal.termType.should.equal('Literal'); + }); + + it('should have the text value as value', function () { + literal.should.have.property('value', 'my @^^ string'); + }); + + it('should have the language tag as language', function () { + literal.should.have.property('language', 'en-us'); + }); + + it('should have rdf:langString as datatype', function () { + literal.should.have.property('datatype'); + literal.datatype.should.be.an.instanceof(NamedNode); + literal.datatype.value.should.equal('http://www.w3.org/1999/02/22-rdf-syntax-ns#langString'); + }); + + it('should have the quoted string as id', function () { + literal.should.have.property('id', '"my @^^ string"@en-us'); + }); + + it('should equal a Literal instance with the same value', function () { + literal.equals(new Literal('"my @^^ string"@en-us')).should.be.true; + }); + + it('should equal an object with the same term type, value, language, and datatype', function () { + literal.equals({ + termType: 'Literal', + value: 'my @^^ string', + language: 'en-us', + datatype: { value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString', termType: 'NamedNode' }, + }).should.be.true; + }); + + it('should not equal a falsy object', function () { + literal.equals(null).should.be.false; + }); + + it('should not equal a Literal instance with another value', function () { + literal.equals(new Literal('"other string"')).should.be.false; + }); + + it('should not equal an object with the same term type but a different value', function () { + literal.equals({ + termType: 'Literal', + value: 'other string', + language: 'en-us', + datatype: { value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString', termType: 'NamedNode' }, + }).should.be.false; + }); + + it('should not equal an object with the same term type but a different language', function () { + literal.equals({ + termType: 'Literal', + value: 'my @^^ string', + language: 'fr', + datatype: { value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString', termType: 'NamedNode' }, + }).should.be.false; + }); + + it('should not equal an object with the same term type but a different datatype', function () { + literal.equals({ + termType: 'Literal', + value: 'my @^^ string', + language: 'en-us', + datatype: { value: 'other', termType: 'NamedNode' }, + }).should.be.false; + }); + + it('should not equal an object with a different term type', function () { + literal.equals({ + termType: 'NamedNode', + value: 'my @^^ string', + language: 'en-us', + datatype: { value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString', termType: 'NamedNode' }, + }).should.be.false; + }); + }); + + describe('A Literal instance created from the empty string with a datatype', function () { + var literal; + before(function () { literal = new Literal('""^^http://example.org/types#type'); }); + + it('should be a Literal', function () { + literal.should.be.an.instanceof(Literal); + }); + + it('should be a Term', function () { + literal.should.be.an.instanceof(Term); + }); + + it('should have term type "Literal"', function () { + literal.termType.should.equal('Literal'); + }); + + it('should have the empty string as value', function () { + literal.should.have.property('value', ''); + }); + + it('should have the empty string as language', function () { + literal.should.have.property('language', ''); + }); + + it('should have the datatype', function () { + literal.should.have.property('datatype'); + literal.datatype.should.be.an.instanceof(NamedNode); + literal.datatype.value.should.equal('http://example.org/types#type'); + }); + + it('should have the quoted empty string as id', function () { + literal.should.have.property('id', '""^^http://example.org/types#type'); + }); + + it('should equal a Literal instance with the same value', function () { + literal.equals(new Literal('""^^http://example.org/types#type')).should.be.true; + }); + + it('should equal an object with the same term type, value, language, and datatype', function () { + literal.equals({ + termType: 'Literal', + value: '', + language: '', + datatype: { value: 'http://example.org/types#type', termType: 'NamedNode' }, + }).should.be.true; + }); + + it('should not equal a falsy object', function () { + literal.equals(null).should.be.false; + }); + + it('should not equal a Literal instance with a non-empty value', function () { + literal.equals(new Literal('"x"^^http://example.org/types#type')).should.be.false; + }); + + it('should not equal an object with the same term type but a different value', function () { + literal.equals({ + termType: 'Literal', + value: 'x', + language: '', + datatype: { value: 'http://example.org/types#type', termType: 'NamedNode' }, + }).should.be.false; + }); + + it('should not equal an object with the same term type but a different language', function () { + literal.equals({ + termType: 'Literal', + value: '', + language: 'en', + datatype: { value: 'http://example.org/types#type', termType: 'NamedNode' }, + }).should.be.false; + }); + + it('should not equal an object with the same term type but a different datatype', function () { + literal.equals({ + termType: 'Literal', + value: '', + language: '', + datatype: { value: 'other', termType: 'NamedNode' }, + }).should.be.false; + }); + + it('should not equal an object with a different term type', function () { + literal.equals({ + termType: 'NamedNode', + value: '', + language: '', + datatype: { value: 'http://example.org/types#type', termType: 'NamedNode' }, + }).should.be.false; + }); + }); + + describe('A Literal instance created from a string with a datatype', function () { + var literal; + before(function () { literal = new Literal('"my @^^ string"^^http://example.org/types#type'); }); + + it('should be a Literal', function () { + literal.should.be.an.instanceof(Literal); + }); + + it('should be a Term', function () { + literal.should.be.an.instanceof(Term); + }); + + it('should have term type "Literal"', function () { + literal.termType.should.equal('Literal'); + }); + + it('should have the text value as value', function () { + literal.should.have.property('value', 'my @^^ string'); + }); + + it('should have the empty string as language', function () { + literal.should.have.property('language', ''); + }); + + it('should have the datatype', function () { + literal.should.have.property('datatype'); + literal.datatype.should.be.an.instanceof(NamedNode); + literal.datatype.value.should.equal('http://example.org/types#type'); + }); + + it('should have the quoted string as id', function () { + literal.should.have.property('id', '"my @^^ string"^^http://example.org/types#type'); + }); + + it('should equal a Literal instance with the same value', function () { + literal.equals(new Literal('"my @^^ string"^^http://example.org/types#type')).should.be.true; + }); + + it('should equal an object with the same term type, value, language, and datatype', function () { + literal.equals({ + termType: 'Literal', + value: 'my @^^ string', + language: '', + datatype: { value: 'http://example.org/types#type', termType: 'NamedNode' }, + }).should.be.true; + }); + + it('should not equal a falsy object', function () { + literal.equals(null).should.be.false; + }); + + it('should not equal a Literal instance with another value', function () { + literal.equals(new Literal('"other string"^^http://example.org/types#type')).should.be.false; + }); + + it('should not equal an object with the same term type but a different value', function () { + literal.equals({ + termType: 'Literal', + value: 'other string', + language: '', + datatype: { value: 'http://example.org/types#type', termType: 'NamedNode' }, + }).should.be.false; + }); + + it('should not equal an object with the same term type but a different language', function () { + literal.equals({ + termType: 'Literal', + value: 'my @^^ string', + language: 'en', + datatype: { value: 'http://example.org/types#type', termType: 'NamedNode' }, + }).should.be.false; + }); + + it('should not equal an object with the same term type but a different datatype', function () { + literal.equals({ + termType: 'Literal', + value: 'my @^^ string', + language: '', + datatype: { value: 'other', termType: 'NamedNode' }, + }).should.be.false; + }); + + it('should not equal an object with a different term type', function () { + literal.equals({ + termType: 'NamedNode', + value: 'my @^^ string', + language: '', + datatype: { value: 'http://example.org/types#type', termType: 'NamedNode' }, + }).should.be.false; + }); + }); +}); From f30a05e0c7084f5b50d6cda45c29f57cb9996fde Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Thu, 29 Sep 2016 17:50:13 +0200 Subject: [PATCH 05/34] Add DefaultGraph. --- lib/Datatypes.js | 26 ++++++++++++++ test/DefaultGraph-test.js | 72 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 test/DefaultGraph-test.js diff --git a/lib/Datatypes.js b/lib/Datatypes.js index facec10d..c30ca259 100644 --- a/lib/Datatypes.js +++ b/lib/Datatypes.js @@ -124,6 +124,31 @@ Literal.prototype.equals = function (other) { }; +// ## DefaultGraph singleton +var defaultGraph; +function DefaultGraph() { + if (!(this instanceof DefaultGraph)) + return new DefaultGraph(); + return defaultGraph || this; +} +Term.subclass(DefaultGraph); + +// Initialize singleton +defaultGraph = new DefaultGraph(); +defaultGraph.id = ''; + +// ### The empty string +Object.defineProperty(DefaultGraph.prototype, 'value', { value: '' }); + +// ### Returns whether this object represents the same term as the other +DefaultGraph.prototype.equals = function (other) { + // If both terms were created by this library, + // equality can be computed through strict equality; + // otherwise, compare term types. + return (this === other) || (!!other && (this.termType === other.termType)); +}; + + // ## Module exports module.exports = { Term: Term, @@ -131,4 +156,5 @@ module.exports = { BlankNode: BlankNode, Variable: Variable, Literal: Literal, + DefaultGraph: DefaultGraph, }; diff --git a/test/DefaultGraph-test.js b/test/DefaultGraph-test.js new file mode 100644 index 00000000..06ccbaa1 --- /dev/null +++ b/test/DefaultGraph-test.js @@ -0,0 +1,72 @@ +var DefaultGraph = require('../N3').DefaultGraph; + +var Term = require('../N3').Term; + +describe('DefaultGraph', function () { + describe('The DefaultGraph module', function () { + it('should be a function', function () { + DefaultGraph.should.be.a('function'); + }); + + it('should make DefaultGraph objects', function () { + DefaultGraph().should.be.an.instanceof(DefaultGraph); + }); + + it('should make Term objects', function () { + DefaultGraph().should.be.an.instanceof(Term); + }); + + it('should be a DefaultGraph constructor', function () { + new DefaultGraph().should.be.an.instanceof(DefaultGraph); + }); + + it('should be a Term constructor', function () { + new DefaultGraph().should.be.an.instanceof(Term); + }); + }); + + describe('A DefaultGraph instance', function () { + var defaultGraph; + before(function () { defaultGraph = new DefaultGraph(); }); + + it('should be a DefaultGraph', function () { + defaultGraph.should.be.an.instanceof(DefaultGraph); + }); + + it('should be a Term', function () { + defaultGraph.should.be.an.instanceof(Term); + }); + + it('should have term type "DefaultGraph"', function () { + defaultGraph.termType.should.equal('DefaultGraph'); + }); + + it('should have the empty string as value', function () { + defaultGraph.should.have.property('value', ''); + }); + + it('should have the empty string as id', function () { + defaultGraph.should.have.property('id', ''); + }); + + it('should equal another DefaultGraph instance', function () { + defaultGraph.equals(new DefaultGraph()).should.be.true; + }); + + it('should equal an object with the same term type', function () { + defaultGraph.equals({ + termType: 'DefaultGraph', + }).should.be.true; + }); + + it('should not equal a falsy object', function () { + defaultGraph.equals(null).should.be.false; + }); + + it('should not equal an object with a different term type', function () { + defaultGraph.equals({ + termType: 'Literal', + }).should.be.false; + }); + }); +}); From d23cefcf22df3872fe00079633d493f131c43778 Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Mon, 3 Oct 2016 10:26:55 +0200 Subject: [PATCH 06/34] Add toJSON. --- lib/Datatypes.js | 36 ++++++++++++++++---- test/BlankNode-test.js | 7 ++++ test/DefaultGraph-test.js | 7 ++++ test/Literal-test.js | 72 +++++++++++++++++++++++++++++++++++++++ test/NamedNode-test.js | 7 ++++ test/Variable-test.js | 7 ++++ 6 files changed, 130 insertions(+), 6 deletions(-) diff --git a/lib/Datatypes.js b/lib/Datatypes.js index c30ca259..8befc132 100644 --- a/lib/Datatypes.js +++ b/lib/Datatypes.js @@ -27,6 +27,14 @@ Term.prototype.equals = function (other) { this.value === other.value; }; +// ### Returns a plain object representation of this term +Term.prototype.toJSON = function () { + return { + termType: this.termType, + value: this.value, + }; +}; + // ## NamedNode constructor function NamedNode(iri) { @@ -95,17 +103,23 @@ Object.defineProperty(Literal.prototype, 'language', { }, }); -// ### The datatype of this literal +// ### The datatype IRI of this literal Object.defineProperty(Literal.prototype, 'datatype', { + get: function () { + return new NamedNode(this.datatypeString); + }, +}); + +// ### The datatype string of this literal +Object.defineProperty(Literal.prototype, 'datatypeString', { get: function () { // Find the last quotation mark (e.g., '"abc"^^http://ex.org/types#t') var id = this.id, dtPos = id.lastIndexOf('"') + 1, ch; // If "^" it follows, return the remaining substring - var type = dtPos < id.length && (ch = id[dtPos]) === '^' ? id.substr(dtPos + 2) : - // If "@" follows, return rdf:langString; xsd:string otherwise - (ch === '@' ? 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString' - : 'http://www.w3.org/2001/XMLSchema#string'); - return new NamedNode(type); + return dtPos < id.length && (ch = id[dtPos]) === '^' ? id.substr(dtPos + 2) : + // If "@" follows, return rdf:langString; xsd:string otherwise + (ch === '@' ? 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString' + : 'http://www.w3.org/2001/XMLSchema#string'); }, }); @@ -123,6 +137,16 @@ Literal.prototype.equals = function (other) { this.datatype.value === other.datatype.value; }; +// ### Returns a plain object representation of this term +Literal.prototype.toJSON = function () { + return { + termType: this.termType, + value: this.value, + language: this.language, + datatype: { termType: 'NamedNode', value: this.datatypeString }, + }; +}; + // ## DefaultGraph singleton var defaultGraph; diff --git a/test/BlankNode-test.js b/test/BlankNode-test.js index 681c3184..5333b81a 100644 --- a/test/BlankNode-test.js +++ b/test/BlankNode-test.js @@ -81,5 +81,12 @@ describe('BlankNode', function () { value: 'b1', }).should.be.false; }); + + it('should provide a JSON representation', function () { + blankNode.toJSON().should.deep.equal({ + termType: 'BlankNode', + value: 'b1', + }); + }); }); }); diff --git a/test/DefaultGraph-test.js b/test/DefaultGraph-test.js index 06ccbaa1..56c4facd 100644 --- a/test/DefaultGraph-test.js +++ b/test/DefaultGraph-test.js @@ -68,5 +68,12 @@ describe('DefaultGraph', function () { termType: 'Literal', }).should.be.false; }); + + it('should provide a JSON representation', function () { + defaultGraph.toJSON().should.deep.equal({ + termType: 'DefaultGraph', + value: '', + }); + }); }); }); diff --git a/test/Literal-test.js b/test/Literal-test.js index 13e20753..cf9dde4d 100644 --- a/test/Literal-test.js +++ b/test/Literal-test.js @@ -116,6 +116,18 @@ describe('Literal', function () { datatype: { value: 'http://www.w3.org/2001/XMLSchema#string', termType: 'NamedNode' }, }).should.be.false; }); + + it('should provide a JSON representation', function () { + literal.toJSON().should.deep.equal({ + termType: 'Literal', + value: '', + language: '', + datatype: { + termType: 'NamedNode', + value: 'http://www.w3.org/2001/XMLSchema#string', + }, + }); + }); }); describe('A Literal instance created from a string without language or datatype', function () { @@ -208,6 +220,18 @@ describe('Literal', function () { datatype: { value: 'http://www.w3.org/2001/XMLSchema#string', termType: 'NamedNode' }, }).should.be.false; }); + + it('should provide a JSON representation', function () { + literal.toJSON().should.deep.equal({ + termType: 'Literal', + value: 'my @^^ string', + language: '', + datatype: { + termType: 'NamedNode', + value: 'http://www.w3.org/2001/XMLSchema#string', + }, + }); + }); }); describe('A Literal instance created from the empty string with a language', function () { @@ -300,6 +324,18 @@ describe('Literal', function () { datatype: { value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString', termType: 'NamedNode' }, }).should.be.false; }); + + it('should provide a JSON representation', function () { + literal.toJSON().should.deep.equal({ + termType: 'Literal', + value: '', + language: 'en-us', + datatype: { + termType: 'NamedNode', + value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString', + }, + }); + }); }); describe('A Literal instance created from a string without language or datatype', function () { @@ -392,6 +428,18 @@ describe('Literal', function () { datatype: { value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString', termType: 'NamedNode' }, }).should.be.false; }); + + it('should provide a JSON representation', function () { + literal.toJSON().should.deep.equal({ + termType: 'Literal', + value: 'my @^^ string', + language: 'en-us', + datatype: { + termType: 'NamedNode', + value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString', + }, + }); + }); }); describe('A Literal instance created from the empty string with a datatype', function () { @@ -484,6 +532,18 @@ describe('Literal', function () { datatype: { value: 'http://example.org/types#type', termType: 'NamedNode' }, }).should.be.false; }); + + it('should provide a JSON representation', function () { + literal.toJSON().should.deep.equal({ + termType: 'Literal', + value: '', + language: '', + datatype: { + termType: 'NamedNode', + value: 'http://example.org/types#type', + }, + }); + }); }); describe('A Literal instance created from a string with a datatype', function () { @@ -576,5 +636,17 @@ describe('Literal', function () { datatype: { value: 'http://example.org/types#type', termType: 'NamedNode' }, }).should.be.false; }); + + it('should provide a JSON representation', function () { + literal.toJSON().should.deep.equal({ + termType: 'Literal', + value: 'my @^^ string', + language: '', + datatype: { + termType: 'NamedNode', + value: 'http://example.org/types#type', + }, + }); + }); }); }); diff --git a/test/NamedNode-test.js b/test/NamedNode-test.js index 380b76f3..6ec1aa50 100644 --- a/test/NamedNode-test.js +++ b/test/NamedNode-test.js @@ -81,5 +81,12 @@ describe('NamedNode', function () { value: 'http://example.org/foo#bar', }).should.be.false; }); + + it('should provide a JSON representation', function () { + namedNode.toJSON().should.deep.equal({ + termType: 'NamedNode', + value: 'http://example.org/foo#bar', + }); + }); }); }); diff --git a/test/Variable-test.js b/test/Variable-test.js index cc6f4444..ff627043 100644 --- a/test/Variable-test.js +++ b/test/Variable-test.js @@ -81,5 +81,12 @@ describe('Variable', function () { value: 'v1', }).should.be.false; }); + + it('should provide a JSON representation', function () { + variable.toJSON().should.deep.equal({ + termType: 'Variable', + value: 'v1', + }); + }); }); }); From 3cf6ee93e91ff21bebe9fca8362f77010145eca4 Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Mon, 3 Oct 2016 10:38:40 +0200 Subject: [PATCH 07/34] Add fromId. --- lib/Datatypes.js | 24 +++++++++++++++++++---- test/Term-test.js | 49 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/lib/Datatypes.js b/lib/Datatypes.js index 8befc132..6bb15928 100644 --- a/lib/Datatypes.js +++ b/lib/Datatypes.js @@ -1,6 +1,8 @@ // N3.js implementations of the RDF/JS core data types // See https://github.com/rdfjs/representation-task-force/blob/master/interface-spec.md +var DEFAULTGRAPH; + // ## Term constructor function Term(id) { if (!(this instanceof Term)) @@ -16,6 +18,21 @@ Term.subclass = function subclass(Type) { Type.subclass = subclass; }; +// ### Constructs a term from the given ID +Term.fromId = function (id) { + // Falsy value or empty string indicate the default graph + if (!id) + return DEFAULTGRAPH; + + // Identify the term type based on the first character + switch (id[0]) { + case '_': return new BlankNode(id.substr(2)); + case '?': return new Variable(id.substr(1)); + case '"': return new Literal(id); + default: return new NamedNode(id); + } +}; + // ### Returns whether this object represents the same term as the other Term.prototype.equals = function (other) { // If both terms were created by this library, @@ -149,17 +166,16 @@ Literal.prototype.toJSON = function () { // ## DefaultGraph singleton -var defaultGraph; function DefaultGraph() { if (!(this instanceof DefaultGraph)) return new DefaultGraph(); - return defaultGraph || this; + return DEFAULTGRAPH || this; } Term.subclass(DefaultGraph); // Initialize singleton -defaultGraph = new DefaultGraph(); -defaultGraph.id = ''; +DEFAULTGRAPH = new DefaultGraph(); +DEFAULTGRAPH.id = ''; // ### The empty string Object.defineProperty(DefaultGraph.prototype, 'value', { value: '' }); diff --git a/test/Term-test.js b/test/Term-test.js index a84dbad1..125b1c1b 100644 --- a/test/Term-test.js +++ b/test/Term-test.js @@ -14,4 +14,53 @@ describe('Term', function () { new Term().should.be.an.instanceof(Term); }); }); + + describe('Term.fromId', function () { + it('should create a DefaultGraph from a falsy value', function () { + Term.fromId(null).toJSON().should.deep.equal({ + termType: 'DefaultGraph', + value: '', + }); + }); + + it('should create a DefaultGraph from the empty string', function () { + Term.fromId('').toJSON().should.deep.equal({ + termType: 'DefaultGraph', + value: '', + }); + }); + + it('should create a NamedNode from an IRI', function () { + Term.fromId('http://example.org/foo#bar').toJSON().should.deep.equal({ + termType: 'NamedNode', + value: 'http://example.org/foo#bar', + }); + }); + + it('should create a BlankNode from a string that starts with an underscore', function () { + Term.fromId('_:b1').toJSON().should.deep.equal({ + termType: 'BlankNode', + value: 'b1', + }); + }); + + it('should create a Variable from a string that starts with a question mark', function () { + Term.fromId('?v1').toJSON().should.deep.equal({ + termType: 'Variable', + value: 'v1', + }); + }); + + it('should create a Literal from a string that starts with a quotation mark', function () { + Term.fromId('"abc"@en-us').toJSON().should.deep.equal({ + termType: 'Literal', + value: 'abc', + language: 'en-us', + datatype: { + termType: 'NamedNode', + value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString', + }, + }); + }); + }); }); From 472bc10bd6eb553f556156d58c6d2adbac10b20d Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Tue, 24 Jan 2017 21:53:53 +0100 Subject: [PATCH 08/34] Add Quad. --- lib/Datatypes.js | 31 ++++++++ test/Quad-test.js | 196 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 227 insertions(+) create mode 100644 test/Quad-test.js diff --git a/lib/Datatypes.js b/lib/Datatypes.js index 6bb15928..1bc53e7e 100644 --- a/lib/Datatypes.js +++ b/lib/Datatypes.js @@ -189,6 +189,35 @@ DefaultGraph.prototype.equals = function (other) { }; +// ## Quad constructor +function Quad(subject, predicate, object, graph) { + if (!(this instanceof Quad)) + return new Quad(); + this.subject = subject; + this.predicate = predicate; + this.object = object; + this.graph = graph || DEFAULTGRAPH; +} + +// ### Returns a plain object representation of this quad +Quad.prototype.toJSON = function () { + return { + subject: this.subject.toJSON(), + predicate: this.predicate.toJSON(), + object: this.object.toJSON(), + graph: this.graph.toJSON(), + }; +}; + +// ### Returns whether this object represents the same quad as the other +Quad.prototype.equals = function (other) { + return !!other && this.subject.equals(other.subject) && + this.predicate.equals(other.predicate) && + this.object.equals(other.object) && + this.graph.equals(other.graph); +}; + + // ## Module exports module.exports = { Term: Term, @@ -197,4 +226,6 @@ module.exports = { Variable: Variable, Literal: Literal, DefaultGraph: DefaultGraph, + Quad: Quad, + Triple: Quad, }; diff --git a/test/Quad-test.js b/test/Quad-test.js new file mode 100644 index 00000000..72399724 --- /dev/null +++ b/test/Quad-test.js @@ -0,0 +1,196 @@ +var Quad = require('../N3').Quad; + +var Triple = require('../N3').Triple, + Term = require('../N3').Term, + DefaultGraph = require('../N3').DefaultGraph; + +describe('Quad', function () { + describe('The Quad module', function () { + it('should be a function', function () { + Quad.should.be.a('function'); + }); + + it('should make Quad objects', function () { + Quad().should.be.an.instanceof(Quad); + }); + + it('should be a Quad constructor', function () { + new Quad().should.be.an.instanceof(Quad); + }); + + it('should equal Triple', function () { + Quad.should.equal(Triple); + }); + }); + + describe('A Quad instance created with subject/predicate/object', function () { + var quad, subject, predicate, object; + before(function () { + quad = new Quad( + subject = Term.fromId('s'), + predicate = Term.fromId('p'), + object = Term.fromId('o') + ); + }); + + it('should be a Quad', function () { + quad.should.be.an.instanceof(Quad); + }); + + it('should have the correct subject', function () { + quad.subject.should.equal(subject); + }); + + it('should have the correct predicate', function () { + quad.predicate.should.equal(predicate); + }); + + it('should have the correct object', function () { + quad.object.should.equal(object); + }); + + it('should have the default graph', function () { + quad.graph.should.equal(new DefaultGraph()); + }); + + it('should equal a quad with the same components', function () { + quad.equals({ + subject: subject, + predicate: predicate, + object: object, + graph: new DefaultGraph(), + }).should.be.true; + }); + + it('should not equal a quad with a different subject', function () { + quad.equals({ + subject: Term.fromId('x'), + predicate: predicate, + object: object, + graph: new DefaultGraph(), + }).should.be.false; + }); + + it('should not equal a quad with a different predicate', function () { + quad.equals({ + subject: subject, + predicate: Term.fromId('x'), + object: object, + graph: new DefaultGraph(), + }).should.be.false; + }); + + it('should not equal a quad with a different object', function () { + quad.equals({ + subject: subject, + predicate: predicate, + object: Term.fromId('x'), + graph: new DefaultGraph(), + }).should.be.false; + }); + + it('should not equal a quad with a different graph', function () { + quad.equals({ + subject: subject, + predicate: predicate, + object: object, + graph: Term.fromId('x'), + }).should.be.false; + }); + + it('should provide a JSON representation', function () { + quad.toJSON().should.deep.equal({ + subject: { termType: 'NamedNode', value: 's' }, + predicate: { termType: 'NamedNode', value: 'p' }, + object: { termType: 'NamedNode', value: 'o' }, + graph: { termType: 'DefaultGraph', value: '' }, + }); + }); + }); + + describe('A Quad instance created with subject/predicate/object/graph', function () { + var quad, subject, predicate, object, graph; + before(function () { + quad = new Quad( + subject = Term.fromId('s'), + predicate = Term.fromId('p'), + object = Term.fromId('o'), + graph = Term.fromId('g') + ); + }); + + it('should be a Quad', function () { + quad.should.be.an.instanceof(Quad); + }); + + it('should have the correct subject', function () { + quad.subject.should.equal(subject); + }); + + it('should have the correct predicate', function () { + quad.predicate.should.equal(predicate); + }); + + it('should have the correct object', function () { + quad.object.should.equal(object); + }); + + it('should have the default graph', function () { + quad.graph.should.equal(graph); + }); + + it('should equal a quad with the same components', function () { + quad.equals({ + subject: subject, + predicate: predicate, + object: object, + graph: graph, + }).should.be.true; + }); + + it('should not equal a quad with a different subject', function () { + quad.equals({ + subject: Term.fromId('x'), + predicate: predicate, + object: object, + graph: graph, + }).should.be.false; + }); + + it('should not equal a quad with a different predicate', function () { + quad.equals({ + subject: subject, + predicate: Term.fromId('x'), + object: object, + graph: graph, + }).should.be.false; + }); + + it('should not equal a quad with a different object', function () { + quad.equals({ + subject: subject, + predicate: predicate, + object: Term.fromId('x'), + graph: graph, + }).should.be.false; + }); + + it('should not equal a quad with a different graph', function () { + quad.equals({ + subject: subject, + predicate: predicate, + object: object, + graph: Term.fromId('x'), + }).should.be.false; + }); + + it('should provide a JSON representation', function () { + quad.toJSON().should.deep.equal({ + subject: { termType: 'NamedNode', value: 's' }, + predicate: { termType: 'NamedNode', value: 'p' }, + object: { termType: 'NamedNode', value: 'o' }, + graph: { termType: 'NamedNode', value: 'g' }, + }); + }); + }); +}); From 9977fd6db5286748d386c347ecddf7f41af279c5 Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Tue, 24 Jan 2017 22:15:02 +0100 Subject: [PATCH 09/34] Change parser output to RDF/JS. --- lib/N3Parser.js | 47 ++++++++++++++++++++++++------------------- test/N3Parser-test.js | 21 +++++++++++++++---- 2 files changed, 43 insertions(+), 25 deletions(-) diff --git a/lib/N3Parser.js b/lib/N3Parser.js index aa682950..131cc8dd 100644 --- a/lib/N3Parser.js +++ b/lib/N3Parser.js @@ -1,5 +1,8 @@ // **N3Parser** parses N3 documents. -var N3Lexer = require('./N3Lexer'); +var N3Lexer = require('./N3Lexer'), + Datatype = require('./Datatypes'); +var Term = Datatype.Term, + Quad = Datatype.Quad; var RDF_PREFIX = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', RDF_NIL = RDF_PREFIX + 'nil', @@ -337,7 +340,7 @@ N3Parser.prototype = { // Store blank node triple if (this._subject !== null) - this._triple(this._subject, this._predicate, this._object, this._graph); + this._quad(this._subject, this._predicate, this._object, this._graph); // Restore the parent context containing this blank node var empty = this._predicate === null; @@ -390,7 +393,7 @@ N3Parser.prototype = { // If this list is contained within a parent list, return the membership triple here. // This will be ` rdf:first .`. if (stack.length !== 0 && stack[stack.length - 1].type === 'list') - this._triple(this._subject, this._predicate, this._object, this._graph); + this._quad(this._subject, this._predicate, this._object, this._graph); // Was this list the parent's subject? if (this._predicate === null) { // The next token is the predicate @@ -433,7 +436,7 @@ N3Parser.prototype = { } else { // Continue the previous list with the current list - this._triple(prevList, RDF_REST, list, this._graph); + this._quad(prevList, RDF_REST, list, this._graph); } // Add the item's value if (item !== null) { @@ -447,7 +450,7 @@ N3Parser.prototype = { } // Output the item if it is complete if (itemComplete) - this._triple(list, RDF_FIRST, item, this._graph); + this._quad(list, RDF_FIRST, item, this._graph); // Otherwise, save it for completion else this._object = item; @@ -487,7 +490,7 @@ N3Parser.prototype = { // If this literal was part of a list, write the item // (we could also check the context stack, but passing in a flag is faster) if (listItem) - this._triple(this._subject, RDF_FIRST, this._object, this._graph); + this._quad(this._subject, RDF_FIRST, this._object, this._graph); // Continue with the rest of the input if (suffix) return this._getContextEndReader(); @@ -504,7 +507,7 @@ N3Parser.prototype = { // Store the last triple of the formula if (this._subject !== null) - this._triple(this._subject, this._predicate, this._object, this._graph); + this._quad(this._subject, this._predicate, this._object, this._graph); // Restore the parent context containing this formula this._restoreContext(); @@ -551,9 +554,9 @@ N3Parser.prototype = { if (subject !== null) { var predicate = this._predicate, object = this._object; if (!inversePredicate) - this._triple(subject, predicate, object, graph); + this._quad(subject, predicate, object, graph); else - this._triple(object, predicate, subject, graph); + this._quad(object, predicate, subject, graph); } return next; }, @@ -574,7 +577,7 @@ N3Parser.prototype = { return this._error('Expected punctuation to follow "' + this._object + '"', token); } // A triple has been completed now, so return it - this._triple(this._subject, this._predicate, this._object, this._graph); + this._quad(this._subject, this._predicate, this._object, this._graph); return next; }, @@ -665,14 +668,14 @@ N3Parser.prototype = { else { // If this is the first item, start a new quantifier list if (this._subject === null) - this._triple(this._graph || '', this._predicate, + this._quad(this._graph || '', this._predicate, this._subject = '_:b' + blankNodeCount++, QUANTIFIERS_GRAPH); // Otherwise, continue the previous list else - this._triple(this._subject, RDF_REST, + this._quad(this._subject, RDF_REST, this._subject = '_:b' + blankNodeCount++, QUANTIFIERS_GRAPH); // Output the list item - this._triple(this._subject, RDF_FIRST, entity, QUANTIFIERS_GRAPH); + this._quad(this._subject, RDF_FIRST, entity, QUANTIFIERS_GRAPH); } return this._readQuantifierPunctuation; }, @@ -686,7 +689,7 @@ N3Parser.prototype = { else { // With explicit quantifiers, close the quantifier list if (this._explicitQuantifiers) { - this._triple(this._subject, RDF_REST, RDF_NIL, QUANTIFIERS_GRAPH); + this._quad(this._subject, RDF_REST, RDF_NIL, QUANTIFIERS_GRAPH); this._subject = null; } // Read a dot @@ -718,7 +721,7 @@ N3Parser.prototype = { // Switch back to the context of the list this._restoreContext(); // Output the list item - this._triple(this._subject, RDF_FIRST, item, this._graph); + this._quad(this._subject, RDF_FIRST, item, this._graph); } return this._afterPath(token); } @@ -737,7 +740,7 @@ N3Parser.prototype = { else subject = this._object, this._object = object; // Emit the path's current triple and read its next section - this._triple(subject, predicate, object, this._graph); + this._quad(subject, predicate, object, this._graph); return this._readPath; }, @@ -754,7 +757,7 @@ N3Parser.prototype = { else object = this._object, this._object = subject; // Emit the path's current triple and read its next section - this._triple(subject, predicate, object, this._graph); + this._quad(subject, predicate, object, this._graph); return this._readPath; }, @@ -774,10 +777,12 @@ N3Parser.prototype = { } }, - // ### `_triple` emits a triple through the callback - _triple: function (subject, predicate, object, graph) { - this._callback(null, - { subject: subject, predicate: predicate, object: object, graph: graph || '' }); + // ### `_quad` emits a triple through the callback + _quad: function (subject, predicate, object, graph) { + this._callback(null, new Quad( + Term.fromId(subject), Term.fromId(predicate), + Term.fromId(object), Term.fromId(graph || '') + )); }, // ### `_error` emits an error message through the callback diff --git a/test/N3Parser-test.js b/test/N3Parser-test.js index dd3da799..6094c2b6 100644 --- a/test/N3Parser-test.js +++ b/test/N3Parser-test.js @@ -1,5 +1,8 @@ var N3Parser = require('../N3').Parser; +var Term = require('../N3').Term, + Quad = require('../N3').Quad; + describe('N3Parser', function () { describe('The N3Parser module', function () { it('should be a function', function () { @@ -848,7 +851,10 @@ describe('N3Parser', function () { it('should parse a string synchronously if no callback is given', function () { var triples = new N3Parser().parse('@prefix a: . a:a a:b a:c.'); - triples.should.deep.equal([{ subject: 'urn:a:a', predicate: 'urn:a:b', object: 'urn:a:c', graph: '' }]); + triples.should.deep.equal([ + new Quad(Term.fromId('urn:a:a'), Term.fromId('urn:a:b'), + Term.fromId('urn:a:c'), Term.fromId('')), + ]); }); it('should throw on syntax errors if no callback is given', function () { @@ -1933,7 +1939,10 @@ function shouldParse(createParser, input) { return function (done) { var results = []; var items = expected.map(function (item) { - return { subject: item[0], predicate: item[1], object: item[2], graph: item[3] || '' }; + return new Quad( + Term.fromId(item[0]), Term.fromId(item[1]), + Term.fromId(item[2]), Term.fromId(item[3] || '') + ); }); N3Parser._resetBlankNodeIds(); createParser().parse(input, function (error, triple) { @@ -1947,7 +1956,11 @@ function shouldParse(createParser, input) { } function toSortedJSON(triples) { - triples = triples.map(JSON.stringify); + triples = triples.map(function (t) { + return JSON.stringify([ + t.subject.id, t.predicate.id, t.object.id, t.graph.id, + ]); + }); triples.sort(); return '[\n ' + triples.join('\n ') + '\n]'; } @@ -1987,7 +2000,7 @@ function itShouldResolve(baseIri, relativeIri, expected) { catch (error) { done(error); } }); it('should result in ' + expected, function () { - expect(result.object).to.equal(expected); + expect(result.object.value).to.equal(expected); }); }); } From 11e268d8dadd2cd51af7c5f51487c4b3640e9875 Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Tue, 31 Jan 2017 13:00:29 +0100 Subject: [PATCH 10/34] Move RDF/JS term creation to parser. --- lib/N3Lexer.js | 8 ++-- lib/N3Parser.js | 109 ++++++++++++++++++++++++------------------ test/N3Lexer-test.js | 8 ++-- test/N3Parser-test.js | 10 ++-- 4 files changed, 76 insertions(+), 59 deletions(-) diff --git a/lib/N3Lexer.js b/lib/N3Lexer.js index 7bed5b42..5cabfd5f 100644 --- a/lib/N3Lexer.js +++ b/lib/N3Lexer.js @@ -140,7 +140,7 @@ N3Lexer.prototype = { } // Try to find a backwards implication arrow else if (this._n3Mode && input.length > 1 && input[1] === '=') - type = 'inverse', matchLength = 2, value = 'http://www.w3.org/2000/10/swap/log#implies'; + type = 'inverse', matchLength = 2, value = '>'; break; case '_': @@ -248,7 +248,7 @@ N3Lexer.prototype = { case 'a': // Try to find an abbreviated predicate if (match = this._shortPredicates.exec(input)) - type = 'abbreviation', value = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'; + type = 'abbreviation', value = 'a'; else inconclusive = true; break; @@ -258,9 +258,9 @@ N3Lexer.prototype = { if (this._n3Mode && input.length > 1) { type = 'abbreviation'; if (input[1] !== '>') - matchLength = 1, value = 'http://www.w3.org/2002/07/owl#sameAs'; + matchLength = 1, value = '='; else - matchLength = 2, value = 'http://www.w3.org/2000/10/swap/log#implies'; + matchLength = 2, value = '>'; } break; diff --git a/lib/N3Parser.js b/lib/N3Parser.js index 131cc8dd..3f543788 100644 --- a/lib/N3Parser.js +++ b/lib/N3Parser.js @@ -1,15 +1,27 @@ // **N3Parser** parses N3 documents. var N3Lexer = require('./N3Lexer'), Datatype = require('./Datatypes'); -var Term = Datatype.Term, +var NamedNode = Datatype.NamedNode, + BlankNode = Datatype.BlankNode, + Literal = Datatype.Literal, + Variable = Datatype.Variable, + DefaultGraph = Datatype.DefaultGraph, Quad = Datatype.Quad; -var RDF_PREFIX = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', - RDF_NIL = RDF_PREFIX + 'nil', - RDF_FIRST = RDF_PREFIX + 'first', - RDF_REST = RDF_PREFIX + 'rest'; - -var QUANTIFIERS_GRAPH = 'urn:n3:quantifiers'; +var RDF_PREFIX = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', + SWAP_PREFIX = 'http://www.w3.org/2000/10/swap/', + RDF_NIL = new NamedNode(RDF_PREFIX + 'nil'), + RDF_FIRST = new NamedNode(RDF_PREFIX + 'first'), + RDF_REST = new NamedNode(RDF_PREFIX + 'rest'), + N3_FORSOME = new NamedNode(SWAP_PREFIX + 'reify#forSome'), + N3_FORALL = new NamedNode(SWAP_PREFIX + 'reify#forAll'), + ABBREVIATIONS = { + 'a': new NamedNode(RDF_PREFIX + 'type'), + '=': new NamedNode('http://www.w3.org/2002/07/owl#sameAs'), + '>': new NamedNode(SWAP_PREFIX + 'log#implies'), + }, + DEFAULTGRAPH = new DefaultGraph(), + QUANTIFIERS_GRAPH = new NamedNode('urn:n3:quantifiers'); var absoluteIRI = /^[a-z][a-z0-9+.-]*:/i, schemeAuthority = /^(?:([a-z][a-z0-9+.-]*:))?(?:\/\/[^\/]*)?/i, @@ -64,6 +76,11 @@ N3Parser._resetBlankNodeIds = function () { N3Parser.prototype = { // ## Private methods + // ### `_blankNode` creates a new blank node + _blankNode: function () { + return new BlankNode('b' + blankNodeCount++); + }, + // ### `_setBase` sets the base IRI to resolve relative IRIs _setBase: function (baseIRI) { if (!baseIRI) @@ -100,7 +117,7 @@ N3Parser.prototype = { this._inversePredicate = false; // In N3, blank nodes are scoped to a formula // (using a dot as separator, as a blank node label cannot start with it) - this._prefixes._ = this._graph + '.'; + this._prefixes._ = (this._graph ? this._graph.id + '.' : '.'); // Quantifiers are scoped to a formula this._quantified = Object.create(this._quantified); } @@ -164,8 +181,8 @@ N3Parser.prototype = { // Read a relative or absolute IRI case 'IRI': case 'typeIRI': - value = (this._base === null || absoluteIRI.test(token.value)) ? - token.value : this._resolveIRI(token); + value = new NamedNode(this._base === null || absoluteIRI.test(token.value) ? + token.value : this._resolveIRI(token)); break; // Read a blank node or prefixed name case 'type': @@ -174,18 +191,19 @@ N3Parser.prototype = { var prefix = this._prefixes[token.prefix]; if (prefix === undefined) return this._error('Undefined prefix "' + token.prefix + ':"', token); - value = prefix + token.value; + value = new NamedNode(prefix + token.value); break; // Read a variable case 'var': - return token.value; + value = new Variable(token.value.substr(1)); + break; // Everything else is not an entity default: return this._error('Expected entity but got ' + token.type, token); } // In N3 mode, replace the entity if it is quantified - if (!quantifier && this._n3Mode && (value in this._quantified)) - value = this._quantified[value]; + if (!quantifier && this._n3Mode && (value.id in this._quantified)) + value = this._quantified[value.id]; return value; }, @@ -196,7 +214,7 @@ N3Parser.prototype = { case '[': // Start a new triple with a new blank node as subject this._saveContext('blank', this._graph, - this._subject = '_:b' + blankNodeCount++, null, null); + this._subject = this._blankNode(), null, null); return this._readBlankNodeHead; case '(': // Start a new list @@ -208,7 +226,7 @@ N3Parser.prototype = { if (!this._n3Mode) return this._error('Unexpected graph', token); this._saveContext('formula', this._graph, - this._graph = '_:b' + blankNodeCount++, null, null); + this._graph = this._blankNode(), null, null); return this._readSubject; case '}': // No subject; the graph in which we are reading is closed instead @@ -217,15 +235,15 @@ N3Parser.prototype = { if (!this._n3Mode) return this._error('Unexpected "@forSome"', token); this._subject = null; - this._predicate = 'http://www.w3.org/2000/10/swap/reify#forSome'; - this._quantifiedPrefix = '_:b'; + this._predicate = N3_FORSOME; + this._quantifier = BlankNode; return this._readQuantifierList; case '@forAll': if (!this._n3Mode) return this._error('Unexpected "@forAll"', token); this._subject = null; - this._predicate = 'http://www.w3.org/2000/10/swap/reify#forAll'; - this._quantifiedPrefix = '?b-'; + this._predicate = N3_FORALL; + this._quantifier = Variable; return this._readQuantifierList; default: // Read the subject entity @@ -248,7 +266,7 @@ N3Parser.prototype = { case 'inverse': this._inversePredicate = true; case 'abbreviation': - this._predicate = token.value; + this._predicate = ABBREVIATIONS[token.value]; break; case '.': case ']': @@ -277,12 +295,12 @@ N3Parser.prototype = { _readObject: function (token) { switch (token.type) { case 'literal': - this._object = token.value; + this._object = new Literal(token.value); return this._readDataTypeOrLang; case '[': // Start a new triple with a new blank node as subject this._saveContext('blank', this._graph, this._subject, this._predicate, - this._subject = '_:b' + blankNodeCount++); + this._subject = this._blankNode()); return this._readBlankNodeHead; case '(': // Start a new list @@ -294,7 +312,7 @@ N3Parser.prototype = { if (!this._n3Mode) return this._error('Unexpected graph', token); this._saveContext('formula', this._graph, this._subject, this._predicate, - this._graph = '_:b' + blankNodeCount++); + this._graph = this._blankNode()); return this._readSubject; default: // Read the object entity @@ -377,14 +395,15 @@ N3Parser.prototype = { switch (token.type) { case '[': // Stack the current list triple and start a new triple with a blank node as subject - this._saveContext('blank', this._graph, list = '_:b' + blankNodeCount++, - RDF_FIRST, this._subject = item = '_:b' + blankNodeCount++); + this._saveContext('blank', this._graph, + list = this._blankNode(), RDF_FIRST, + this._subject = item = this._blankNode()); next = this._readBlankNodeHead; break; case '(': // Stack the current list triple and start a new list - this._saveContext('list', this._graph, list = '_:b' + blankNodeCount++, - RDF_FIRST, RDF_NIL); + this._saveContext('list', this._graph, + list = this._blankNode(), RDF_FIRST, RDF_NIL); this._subject = null; break; case ')': @@ -413,7 +432,7 @@ N3Parser.prototype = { list = RDF_NIL; break; case 'literal': - item = token.value; + item = new Literal(token.value); itemComplete = false; // Can still have a datatype or language next = this._readListItemDataTypeOrLang; break; @@ -424,7 +443,7 @@ N3Parser.prototype = { // Create a new blank node if no item head was assigned yet if (list === null) - this._subject = list = '_:b' + blankNodeCount++; + this._subject = list = this._blankNode(); // Is this the first element of the list? if (prevList === null) { @@ -479,12 +498,12 @@ N3Parser.prototype = { // No datatype means an error was reported, so abort if (datatype === undefined) return; suffix = true; - this._object += '^^' + datatype; + this._object.id += '^^' + datatype.id; break; // Add an "@lang" suffix for language tags case 'langcode': suffix = true; - this._object += '@' + token.value.toLowerCase(); + this._object.id += '@' + token.value.toLowerCase(); break; } // If this literal was part of a list, write the item @@ -548,7 +567,7 @@ N3Parser.prototype = { next = this._readQuadPunctuation; break; } - return this._error('Expected punctuation to follow "' + this._object + '"', token); + return this._error('Expected punctuation to follow "' + this._object.id + '"', token); } // A triple has been completed now, so return it if (subject !== null) { @@ -574,7 +593,7 @@ N3Parser.prototype = { next = this._readObject; break; default: - return this._error('Expected punctuation to follow "' + this._object + '"', token); + return this._error('Expected punctuation to follow "' + this._object.id + '"', token); } // A triple has been completed now, so return it this._quad(this._subject, this._predicate, this._object, this._graph); @@ -600,7 +619,7 @@ N3Parser.prototype = { _readPrefixIRI: function (token) { if (token.type !== 'IRI') return this._error('Expected IRI to follow prefix "' + this._prefix + ':"', token); - var prefixIRI = this._readEntity(token); + var prefixIRI = this._readEntity(token).id; this._prefixes[this._prefix] = prefixIRI; this._prefixCallback(this._prefix, prefixIRI); return this._readDeclarationPunctuation; @@ -633,7 +652,7 @@ N3Parser.prototype = { _readNamedGraphBlankLabel: function (token) { if (token.type !== ']') return this._error('Invalid graph label', token); - this._subject = '_:b' + blankNodeCount++; + this._subject = this._blankNode(); return this._readGraph; }, @@ -663,17 +682,17 @@ N3Parser.prototype = { } // Without explicit quantifiers, map entities to a quantified entity if (!this._explicitQuantifiers) - this._quantified[entity] = this._quantifiedPrefix + blankNodeCount++; + this._quantified[entity.id] = this._quantifier('b' + blankNodeCount++); // With explicit quantifiers, output the reified quantifier else { // If this is the first item, start a new quantifier list if (this._subject === null) - this._quad(this._graph || '', this._predicate, - this._subject = '_:b' + blankNodeCount++, QUANTIFIERS_GRAPH); + this._quad(this._graph || DEFAULTGRAPH, this._predicate, + this._subject = this._blankNode(), QUANTIFIERS_GRAPH); // Otherwise, continue the previous list else this._quad(this._subject, RDF_REST, - this._subject = '_:b' + blankNodeCount++, QUANTIFIERS_GRAPH); + this._subject = this._blankNode(), QUANTIFIERS_GRAPH); // Output the list item this._quad(this._subject, RDF_FIRST, entity, QUANTIFIERS_GRAPH); } @@ -729,7 +748,7 @@ N3Parser.prototype = { // ### `_readForwardPath` reads a '!' path _readForwardPath: function (token) { - var subject, predicate, object = '_:b' + blankNodeCount++; + var subject, predicate, object = this._blankNode(); // The next token is the predicate if ((predicate = this._readEntity(token)) === undefined) return; @@ -746,7 +765,7 @@ N3Parser.prototype = { // ### `_readBackwardPath` reads a '^' path _readBackwardPath: function (token) { - var subject = '_:b' + blankNodeCount++, predicate, object; + var subject = this._blankNode(), predicate, object; // The next token is the predicate if ((predicate = this._readEntity(token)) === undefined) return; @@ -779,10 +798,8 @@ N3Parser.prototype = { // ### `_quad` emits a triple through the callback _quad: function (subject, predicate, object, graph) { - this._callback(null, new Quad( - Term.fromId(subject), Term.fromId(predicate), - Term.fromId(object), Term.fromId(graph || '') - )); + this._callback(null, + new Quad(subject, predicate, object, graph || DEFAULTGRAPH)); }, // ### `_error` emits an error message through the callback diff --git a/test/N3Lexer-test.js b/test/N3Lexer-test.js index 6c174dbd..bb6505ce 100644 --- a/test/N3Lexer-test.js +++ b/test/N3Lexer-test.js @@ -620,7 +620,7 @@ describe('N3Lexer', function () { it('should tokenize the "a" predicate', shouldTokenize(' a .', { type: 'IRI', value: 'x', line: 1 }, - { type: 'abbreviation', value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', line: 1 }, + { type: 'abbreviation', value: 'a', line: 1 }, { type: 'IRI', value: 'y', line: 1 }, { type: '.', line: 1 }, { type: 'eof', line: 1 })); @@ -707,21 +707,21 @@ describe('N3Lexer', function () { it('should tokenize the equality sign', shouldTokenize(' = ', { type: 'IRI', value: 'a', line: 1 }, - { type: 'abbreviation', value: 'http://www.w3.org/2002/07/owl#sameAs', line: 1 }, + { type: 'abbreviation', value: '=', line: 1 }, { type: 'IRI', value: 'b', line: 1 }, { type: 'eof', line: 1 })); it('should tokenize the right implication', shouldTokenize(' => ', { type: 'IRI', value: 'a', line: 1 }, - { type: 'abbreviation', value: 'http://www.w3.org/2000/10/swap/log#implies', line: 1 }, + { type: 'abbreviation', value: '>', line: 1 }, { type: 'IRI', value: 'b', line: 1 }, { type: 'eof', line: 1 })); it('should tokenize the left implication', shouldTokenize(' <= ', { type: 'IRI', value: 'a', line: 1 }, - { type: 'inverse', value: 'http://www.w3.org/2000/10/swap/log#implies', line: 1 }, + { type: 'inverse', value: '>', line: 1 }, { type: 'IRI', value: 'b', line: 1 }, { type: 'eof', line: 1 })); diff --git a/test/N3Parser-test.js b/test/N3Parser-test.js index 6094c2b6..566c83f7 100644 --- a/test/N3Parser-test.js +++ b/test/N3Parser-test.js @@ -1258,11 +1258,11 @@ describe('N3Parser', function () { it('should parse a @forAll statement', shouldParse(parser, '@forAll . .', - ['?b-0', '?b-0', '?b-0'])); + ['?b0', '?b0', '?b0'])); it('should parse a @forAll statement with multiple entities', shouldParse(parser, '@prefix a: . @base . @forAll a:x, , a:z. a:x a:z.', - ['?b-0', '?b-1', '?b-2'])); + ['?b0', '?b1', '?b2'])); it('should not parse a @forAll statement with an invalid prefix', shouldNotParse(parser, '@forAll a:b.', @@ -1278,9 +1278,9 @@ describe('N3Parser', function () { it('should correctly scope @forAll statements', shouldParse(parser, '@forAll . { @forAll . . }. .', - ['?b-0', '?b-0', '_:b1'], - ['?b-2', '?b-2', '?b-2', '_:b1'], - ['?b-0', '?b-0', '?b-0'])); + ['?b0', '?b0', '_:b1'], + ['?b2', '?b2', '?b2', '_:b1'], + ['?b0', '?b0', '?b0'])); it('should parse a ! path of length 2 as subject', shouldParse(parser, '@prefix : . @prefix fam: .' + From e1f6844945f0124dd2f767699959e72eb27f0ba3 Mon Sep 17 00:00:00 2001 From: Ruben Taelman Date: Fri, 13 Oct 2017 14:15:20 +0900 Subject: [PATCH 11/34] Add Term#toId. --- lib/Datatypes.js | 29 +++++++++++++-- test/Term-test.js | 89 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 114 insertions(+), 4 deletions(-) diff --git a/lib/Datatypes.js b/lib/Datatypes.js index 1bc53e7e..94c17a86 100644 --- a/lib/Datatypes.js +++ b/lib/Datatypes.js @@ -3,6 +3,9 @@ var DEFAULTGRAPH; +var STRING = 'http://www.w3.org/2001/XMLSchema#string', + LANG_STRING = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString'; + // ## Term constructor function Term(id) { if (!(this instanceof Term)) @@ -33,6 +36,28 @@ Term.fromId = function (id) { } }; +// ### Constructs an ID from the given term or ID string +Term.toId = function (term) { + if (typeof term === 'string') + return term; + if (term instanceof Term) + return term.id; + if (!term) + return DEFAULTGRAPH.value; + + // Term instantiated with another library + switch (term.termType) { + case 'NamedNode': return term.value; + case 'BlankNode': return '_:' + term.value; + case 'Variable': return '?' + term.value; + case 'DefaultGraph': return ''; + case 'Literal': return '"' + term.value + '"' + + (term.language ? '@' + term.language : + (term.datatype && term.datatype.value !== STRING ? '^^' + term.datatype.value : '')); + default: throw new Error('Unexpected termType: ' + term.termType); + } +}; + // ### Returns whether this object represents the same term as the other Term.prototype.equals = function (other) { // If both terms were created by this library, @@ -52,7 +77,6 @@ Term.prototype.toJSON = function () { }; }; - // ## NamedNode constructor function NamedNode(iri) { if (!(this instanceof NamedNode)) @@ -135,8 +159,7 @@ Object.defineProperty(Literal.prototype, 'datatypeString', { // If "^" it follows, return the remaining substring return dtPos < id.length && (ch = id[dtPos]) === '^' ? id.substr(dtPos + 2) : // If "@" follows, return rdf:langString; xsd:string otherwise - (ch === '@' ? 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString' - : 'http://www.w3.org/2001/XMLSchema#string'); + (ch !== '@' ? STRING : LANG_STRING); }, }); diff --git a/test/Term-test.js b/test/Term-test.js index 125b1c1b..0c774a50 100644 --- a/test/Term-test.js +++ b/test/Term-test.js @@ -1,4 +1,10 @@ -var Term = require('../N3').Term; +var Datatype = require('../lib/Datatypes'); +var Term = Datatype.Term, + NamedNode = Datatype.NamedNode, + BlankNode = Datatype.BlankNode, + Literal = Datatype.Literal, + Variable = Datatype.Variable, + DefaultGraph = Datatype.DefaultGraph; describe('Term', function () { describe('The Term module', function () { @@ -63,4 +69,85 @@ describe('Term', function () { }); }); }); + + describe('Term.toId', function () { + it('should create the empty string a falsy value', function () { + Term.toId(null).should.equal(''); + Term.toId(false).should.equal(''); + Term.toId('').should.equal(''); + }); + + it('should create the empty string from the DefaultGraph', function () { + Term.toId(new DefaultGraph()).should.equal(''); + Term.toId(new DefaultGraph().toJSON()).should.equal(''); + }); + + it('should create an id that starts with a question mark from a Variable', function () { + Term.toId(new Variable('abc')).should.equal('?abc'); + Term.toId(new Variable('abc').toJSON()).should.equal('?abc'); + }); + + it('should create an id that starts with a question mark from a Variable string', function () { + Term.toId('?abc').should.equal('?abc'); + }); + + it('should create an id that starts with a quotation mark from a Literal', function () { + Term.toId(new Literal('"abc"')).should.equal('"abc"'); + Term.toId(new Literal('"abc"').toJSON()).should.equal('"abc"'); + }); + + it('should create an id that starts with a quotation mark from a Literal string', function () { + Term.toId('"abc"').should.equal('"abc"'); + }); + + it('should create an id that starts with a quotation mark and datatype from a Literal with a datatype', function () { + Term.toId(new Literal('"abc"^^http://example.org')).should.equal('"abc"^^http://example.org'); + Term.toId(new Literal('"abc"^^http://example.org').toJSON()).should.equal('"abc"^^http://example.org'); + }); + + it('should create an id that starts with a quotation mark and datatype from a Literal string with a datatype', function () { + Term.toId('"abc"^^http://example.org').should.equal('"abc"^^http://example.org'); + }); + + it('should create an id that starts with a quotation mark and language tag from a Literal with a language', function () { + Term.toId(new Literal('"abc"@en-us')).should.equal('"abc"@en-us'); + Term.toId(new Literal('"abc"@en-us').toJSON()).should.equal('"abc"@en-us'); + }); + + it('should create an id that starts with a quotation mark and language tag from a Literal string with a language', function () { + Term.toId('"abc"@en-us').should.equal('"abc"@en-us'); + }); + + it('should create an id that starts with a quotation mark, datatype and language tag from a Literal with a datatype and language', function () { + Term.toId(new Literal('"abc"^^http://example.org@en-us')).should.equal('"abc"^^http://example.org@en-us'); + Term.toId(new Literal('"abc"^^http://example.org@en-us').toJSON()).should.equal('"abc"^^http://example.org@en-us'); + }); + + it('should create an id that starts with a quotation mark, datatype and language tag from a Literal string with a datatype and language', function () { + Term.toId('"abc"^^http://example.org@en-us').should.equal('"abc"^^http://example.org@en-us'); + }); + + it('should create an id that starts with an underscore from a BlankNode', function () { + Term.toId(new BlankNode('abc')).should.equal('_:abc'); + Term.toId(new BlankNode('abc').toJSON()).should.equal('_:abc'); + }); + + it('should create an id that starts with an underscore from a BlankNode string', function () { + Term.toId('_:abc').should.equal('_:abc'); + }); + + it('should create an IRI from a NamedNode', function () { + Term.toId(new NamedNode('http://example.org/')).should.equal('http://example.org/'); + Term.toId(new NamedNode('http://example.org/').toJSON()).should.equal('http://example.org/'); + }); + + it('should create an IRI from a NamedNode string', function () { + Term.toId('http://example.org/').should.equal('http://example.org/'); + }); + + it('should throw on an unknown type', function () { + (function () { Term.toId({ termType: 'unknown' }); }) + .should.throw('Unexpected termType: unknown'); + }); + }); }); From afd0b17aa059ebdf56798089727d3d0313cab403 Mon Sep 17 00:00:00 2001 From: Ruben Taelman Date: Fri, 13 Oct 2017 14:16:31 +0900 Subject: [PATCH 12/34] Migrate writer to RDF/JS interface. --- lib/N3Writer.js | 48 ++++++---- test/N3StreamWriter-test.js | 7 +- test/N3Writer-test.js | 178 +++++++++++++++++++----------------- 3 files changed, 125 insertions(+), 108 deletions(-) diff --git a/lib/N3Writer.js b/lib/N3Writer.js index 93c55155..37002fd8 100644 --- a/lib/N3Writer.js +++ b/lib/N3Writer.js @@ -1,5 +1,9 @@ // **N3Writer** writes N3 documents. +var Datatype = require('./Datatypes'); +var Term = Datatype.Term, + DefaultGraph = Datatype.DefaultGraph; + // Matches a literal as represented in memory by the N3 library var N3LiteralMatcher = /^"([^]*)"(?:\^\^(.+)|@([a-z]+(?:-[a-z0-9]+)*))?$/i; @@ -59,7 +63,12 @@ N3Writer.prototype = { this._outputStream.write(string, 'utf8', callback); }, - // ### `_writeTriple` writes the triple to the output stream + // ### `_writeTripleTerms` writes the triple term objects to the output stream + _writeTripleTerms: function (subject, predicate, object, graph, done) { + this._writeTriple(Term.toId(subject), Term.toId(predicate), Term.toId(object), Term.toId(graph), done); + }, + + // ### `_writeTriple` writes the triple to the output stream _writeTriple: function (subject, predicate, object, graph, done) { try { // Write the graph's label if it has changed @@ -102,10 +111,10 @@ N3Writer.prototype = { // ### `tripleToString` serializes a triple or quad as a string tripleToString: function (subject, predicate, object, graph) { - return this._encodeIriOrBlankNode(subject) + ' ' + - this._encodeIriOrBlankNode(predicate) + ' ' + - this._encodeObject(object) + - (graph ? ' ' + this._encodeIriOrBlankNode(graph) + '.\n' : '.\n'); + return this._encodeIriOrBlankNode(Term.toId(subject)) + ' ' + + this._encodeIriOrBlankNode(Term.toId(predicate)) + ' ' + + this._encodeObject(Term.toId(object)) + + (graph && (typeof graph === 'string' || graph.value) ? ' ' + this._encodeIriOrBlankNode(Term.toId(graph)) + '.\n' : '.\n'); }, // ### `triplesToString` serializes an array of triples or quads as a string @@ -181,14 +190,13 @@ N3Writer.prototype = { addTriple: function (subject, predicate, object, graph, done) { // The triple was given as a triple object, so shift parameters if (object === undefined) - this._writeTriple(subject.subject, subject.predicate, subject.object, - subject.graph || '', predicate); + this._writeTripleTerms(subject.subject, subject.predicate, subject.object, subject.graph, predicate); // The optional `graph` parameter was not provided - else if (typeof graph !== 'string') - this._writeTriple(subject, predicate, object, '', graph); + else if (typeof graph === 'function') + this._writeTripleTerms(subject, predicate, object, new DefaultGraph(), graph); // The `graph` parameter was provided else - this._writeTriple(subject, predicate, object, graph, done); + this._writeTripleTerms(subject, predicate, object, graph, done); }, // ### `addTriples` adds the triples to the output stream @@ -244,8 +252,8 @@ N3Writer.prototype = { // Empty blank node if (predicate === undefined) children = []; - // Blank node passed as blank("predicate", "object") - else if (typeof predicate === 'string') + // Blank node passed as blank(Term("predicate"), Term("object")) + else if (predicate.termType) children = [{ predicate: predicate, object: object }]; // Blank node passed as blank({ predicate: predicate, object: object }) else if (!('length' in predicate)) @@ -259,8 +267,8 @@ N3Writer.prototype = { case 1: child = children[0]; if (child.object[0] !== '[') - return '[ ' + this._encodePredicate(child.predicate) + ' ' + - this._encodeObject(child.object) + ' ]'; + return '[ ' + this._encodePredicate(Term.toId(child.predicate)) + ' ' + + this._encodeObject(Term.toId(child.object)) + ' ]'; // Generate a multi-triple or nested blank node default: var contents = '['; @@ -268,14 +276,14 @@ N3Writer.prototype = { for (var i = 0; i < length; i++) { child = children[i]; // Write only the object is the predicate is the same as the previous - if (child.predicate === predicate) - contents += ', ' + this._encodeObject(child.object); + if (Term.toId(child.predicate) === predicate) + contents += ', ' + this._encodeObject(Term.toId(child.object)); // Otherwise, write the predicate and the object else { contents += (i ? ';\n ' : '\n ') + - this._encodePredicate(child.predicate) + ' ' + - this._encodeObject(child.object); - predicate = child.predicate; + this._encodePredicate(Term.toId(child.predicate)) + ' ' + + this._encodeObject(Term.toId(child.object)); + predicate = Term.toId(child.predicate); } } return contents + '\n]'; @@ -286,7 +294,7 @@ N3Writer.prototype = { list: function (elements) { var length = elements && elements.length || 0, contents = new Array(length); for (var i = 0; i < length; i++) - contents[i] = this._encodeObject(elements[i]); + contents[i] = this._encodeObject(Term.toId(elements[i])); return '(' + contents.join(' ') + ')'; }, diff --git a/test/N3StreamWriter-test.js b/test/N3StreamWriter-test.js index f16b22e3..33cdec83 100644 --- a/test/N3StreamWriter-test.js +++ b/test/N3StreamWriter-test.js @@ -1,7 +1,10 @@ var N3StreamWriter = require('../N3').StreamWriter; var Readable = require('stream').Readable, - Writable = require('stream').Writable; + Writable = require('stream').Writable, + Datatype = require('../lib/Datatypes'); +var Term = Datatype.Term, + Quad = Datatype.Quad; describe('N3StreamWriter', function () { describe('The N3StreamWriter module', function () { @@ -101,7 +104,7 @@ function shouldNotSerialize(/* tripleArrays..., expectedMessage */) { function ArrayReader(items) { var reader = new Readable({ objectMode: true }); - items = items.map(function (i) { return { subject: i[0], predicate: i[1], object: i[2] }; }); + items = items.map(function (i) { return new Quad(Term.fromId(i[0]), Term.fromId(i[1]), Term.fromId(i[2])); }); reader._read = function () { this.push(items.shift() || null); }; return reader; } diff --git a/test/N3Writer-test.js b/test/N3Writer-test.js index 4840c036..deb706eb 100644 --- a/test/N3Writer-test.js +++ b/test/N3Writer-test.js @@ -1,4 +1,10 @@ -var N3Writer = require('../N3').Writer; +var N3Writer = require('../N3').Writer, + Datatype = require('../lib/Datatypes'); +var Term = Datatype.Term, + NamedNode = Datatype.NamedNode, + Literal = Datatype.Literal, + Quad = Datatype.Quad, + Triple = Datatype.Triple; describe('N3Writer', function () { describe('The N3Writer module', function () { @@ -18,18 +24,18 @@ describe('N3Writer', function () { describe('An N3Writer instance', function () { it('should serialize a single triple', function () { var writer = N3Writer(); - writer.tripleToString('a', 'b', 'c').should.equal(' .\n'); + writer.tripleToString(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')).should.equal(' .\n'); }); it('should serialize a single quad', function () { var writer = N3Writer(); - writer.tripleToString('a', 'b', 'c', 'g').should.equal(' .\n'); + writer.tripleToString(new NamedNode('a'), new NamedNode('b'), new NamedNode('c'), new NamedNode('g')).should.equal(' .\n'); }); it('should serialize an array of triples', function () { var writer = N3Writer(); - var triples = [{ subject: 'a', predicate: 'b', object: 'c' }, - { subject: 'd', predicate: 'e', object: 'f' }]; + var triples = [new Quad(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')), + new Quad(new NamedNode('d'), new NamedNode('e'), new NamedNode('f'))]; writer.triplesToString(triples).should.equal(' .\n .\n'); }); @@ -224,7 +230,7 @@ describe('N3Writer', function () { it('sends output through end when no stream argument is given', function (done) { var writer = new N3Writer(), notCalled = true; - writer.addTriple({ subject: 'a', predicate: 'b', object: 'c' }, function () { notCalled = false; }); + writer.addTriple(new Triple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')), function () { notCalled = false; }); writer.end(function (error, output) { output.should.equal(' .\n'); done(notCalled || error); @@ -233,7 +239,7 @@ describe('N3Writer', function () { it('respects the prefixes argument when no stream argument is given', function (done) { var writer = new N3Writer({ prefixes: { a: 'b#' } }); - writer.addTriple({ subject: 'b#a', predicate: 'b#b', object: 'b#c' }); + writer.addTriple(new Triple(new NamedNode('b#a'), new NamedNode('b#b'), new NamedNode('b#c'))); writer.end(function (error, output) { output.should.equal('@prefix a: .\n\na:a a:b a:c.\n'); done(error); @@ -244,7 +250,7 @@ describe('N3Writer', function () { var writer = new N3Writer(); writer.addPrefix('a', 'b#'); writer.addPrefix('a', 'b#'); - writer.addTriple({ subject: 'b#a', predicate: 'b#b', object: 'b#c' }); + writer.addTriple(new Triple(new NamedNode('b#a'), new NamedNode('b#b'), new NamedNode('b#c'))); writer.addPrefix('a', 'b#'); writer.addPrefix('a', 'b#'); writer.addPrefix('b', 'b#'); @@ -259,9 +265,9 @@ describe('N3Writer', function () { it('serializes triples of a graph with a prefix declaration in between', function (done) { var writer = new N3Writer(); writer.addPrefix('a', 'b#'); - writer.addTriple({ subject: 'b#a', predicate: 'b#b', object: 'b#c', graph: 'b#g' }); + writer.addTriple(new Quad(new NamedNode('b#a'), new NamedNode('b#b'), new NamedNode('b#c'), new NamedNode('b#g'))); writer.addPrefix('d', 'e#'); - writer.addTriple({ subject: 'b#a', predicate: 'b#b', object: 'b#d', graph: 'b#g' }); + writer.addTriple(new Quad(new NamedNode('b#a'), new NamedNode('b#b'), new NamedNode('b#d'), new NamedNode('b#g'))); writer.end(function (error, output) { output.should.equal('@prefix a: .\n\na:g {\na:a a:b a:c\n}\n' + '@prefix d: .\n\na:g {\na:a a:b a:d\n}\n'); @@ -271,8 +277,8 @@ describe('N3Writer', function () { it('should accept triples with separated components', function (done) { var writer = N3Writer(); - writer.addTriple('a', 'b', 'c'); - writer.addTriple('a', 'b', 'd'); + writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')); + writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('d')); writer.end(function (error, output) { output.should.equal(' , .\n'); done(error); @@ -281,8 +287,8 @@ describe('N3Writer', function () { it('should accept quads with separated components', function (done) { var writer = N3Writer(); - writer.addTriple('a', 'b', 'c', 'g'); - writer.addTriple('a', 'b', 'd', 'g'); + writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c'), new NamedNode('g')); + writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('d'), new NamedNode('g')); writer.end(function (error, output) { output.should.equal(' {\n , \n}\n'); done(error); @@ -291,8 +297,8 @@ describe('N3Writer', function () { it('should serialize triples with an empty blank node as object', function (done) { var writer = N3Writer(); - writer.addTriple('a1', 'b', writer.blank()); - writer.addTriple('a2', 'b', writer.blank([])); + writer.addTriple(new NamedNode('a1'), new NamedNode('b'), writer.blank()); + writer.addTriple(new NamedNode('a2'), new NamedNode('b'), writer.blank([])); writer.end(function (error, output) { output.should.equal(' [].\n' + ' [].\n'); @@ -302,9 +308,9 @@ describe('N3Writer', function () { it('should serialize triples with a one-triple blank node as object', function (done) { var writer = N3Writer(); - writer.addTriple('a1', 'b', writer.blank('d', 'e')); - writer.addTriple('a2', 'b', writer.blank({ predicate: 'd', object: 'e' })); - writer.addTriple('a3', 'b', writer.blank([{ predicate: 'd', object: 'e' }])); + writer.addTriple(new NamedNode('a1'), new NamedNode('b'), writer.blank(new NamedNode('d'), new NamedNode('e'))); + writer.addTriple(new NamedNode('a2'), new NamedNode('b'), writer.blank({ predicate: new NamedNode('d'), object: new NamedNode('e') })); + writer.addTriple(new NamedNode('a3'), new NamedNode('b'), writer.blank([{ predicate: new NamedNode('d'), object: new NamedNode('e') }])); writer.end(function (error, output) { output.should.equal(' [ ].\n' + ' [ ].\n' + @@ -315,9 +321,9 @@ describe('N3Writer', function () { it('should serialize triples with a two-triple blank node as object', function (done) { var writer = N3Writer(); - writer.addTriple('a', 'b', writer.blank([ - { predicate: 'd', object: 'e' }, - { predicate: 'f', object: '"g"' }, + writer.addTriple(new NamedNode('a'), new NamedNode('b'), writer.blank([ + { predicate: new NamedNode('d'), object: new NamedNode('e') }, + { predicate: new NamedNode('f'), object: new Literal('"g"') }, ])); writer.end(function (error, output) { output.should.equal(' [\n' + @@ -330,10 +336,10 @@ describe('N3Writer', function () { it('should serialize triples with a three-triple blank node as object', function (done) { var writer = N3Writer(); - writer.addTriple('a', 'b', writer.blank([ - { predicate: 'd', object: 'e' }, - { predicate: 'f', object: '"g"' }, - { predicate: 'h', object: 'i' }, + writer.addTriple(new NamedNode('a'), new NamedNode('b'), writer.blank([ + { predicate: new NamedNode('d'), object: new NamedNode('e') }, + { predicate: new NamedNode('f'), object: new Literal('"g"') }, + { predicate: new NamedNode('h'), object: new NamedNode('i') }, ])); writer.end(function (error, output) { output.should.equal(' [\n' + @@ -347,58 +353,58 @@ describe('N3Writer', function () { it('should serialize triples with predicate-sharing blank node triples as object', function (done) { var writer = N3Writer(); - writer.addTriple('a', 'b', writer.blank([ - { predicate: 'd', object: 'e' }, - { predicate: 'd', object: 'f' }, - { predicate: 'g', object: 'h' }, - { predicate: 'g', object: 'i' }, + writer.addTriple(new NamedNode('a'), new NamedNode('b'), writer.blank([ + { predicate: new NamedNode('d'), object: new NamedNode('e') }, + { predicate: new NamedNode('d'), object: new NamedNode('f') }, + { predicate: new NamedNode('g'), object: new NamedNode('h') }, + { predicate: new NamedNode('g'), object: new NamedNode('i') }, ])); writer.end(function (error, output) { output.should.equal(' [\n' + - ' , ;\n' + - ' , \n' + - '].\n'); + ' , ;\n' + + ' , \n' + + '].\n'); done(error); }); }); it('should serialize triples with nested blank nodes as object', function (done) { var writer = N3Writer(); - writer.addTriple('a1', 'b', writer.blank([ - { predicate: 'd', object: writer.blank() }, + writer.addTriple(new NamedNode('a1'), new NamedNode('b'), writer.blank([ + { predicate: new NamedNode('d'), object: writer.blank() }, ])); - writer.addTriple('a2', 'b', writer.blank([ - { predicate: 'd', object: writer.blank('e', 'f') }, - { predicate: 'g', object: writer.blank('h', '"i"') }, + writer.addTriple(new NamedNode('a2'), new NamedNode('b'), writer.blank([ + { predicate: new NamedNode('d'), object: writer.blank(new NamedNode('e'), new NamedNode('f')) }, + { predicate: new NamedNode('g'), object: writer.blank(new NamedNode('h'), new Literal('"i"')) }, ])); - writer.addTriple('a3', 'b', writer.blank([ - { predicate: 'd', object: writer.blank([ - { predicate: 'g', object: writer.blank('h', 'i') }, - { predicate: 'j', object: writer.blank('k', '"l"') }, + writer.addTriple(new NamedNode('a3'), new NamedNode('b'), writer.blank([ + { predicate: new NamedNode('d'), object: writer.blank([ + { predicate: new NamedNode('g'), object: writer.blank(new NamedNode('h'), new NamedNode('i')) }, + { predicate: new NamedNode('j'), object: writer.blank(new NamedNode('k'), new Literal('"l"')) }, ]) }, ])); writer.end(function (error, output) { output.should.equal(' [\n' + - ' []\n' + - '].\n' + - ' [\n' + - ' [ ];\n' + - ' [ "i" ]\n' + - '].\n' + - ' [\n' + - ' [\n' + - ' [ ];\n' + - ' [ "l" ]\n' + - ']\n' + - '].\n'); + ' []\n' + + '].\n' + + ' [\n' + + ' [ ];\n' + + ' [ "i" ]\n' + + '].\n' + + ' [\n' + + ' [\n' + + ' [ ];\n' + + ' [ "l" ]\n' + + ']\n' + + '].\n'); done(error); }); }); it('should serialize triples with an empty blank node as subject', function (done) { var writer = N3Writer(); - writer.addTriple(writer.blank(), 'b', 'c'); - writer.addTriple(writer.blank([]), 'b', 'c'); + writer.addTriple(writer.blank(), new NamedNode('b'), new NamedNode('c')); + writer.addTriple(writer.blank([]), new NamedNode('b'), new NamedNode('c')); writer.end(function (error, output) { output.should.equal('[] .\n' + '[] .\n'); @@ -408,9 +414,9 @@ describe('N3Writer', function () { it('should serialize triples with a one-triple blank node as subject', function (done) { var writer = N3Writer(); - writer.addTriple(writer.blank('a', 'b'), 'c', 'd'); - writer.addTriple(writer.blank({ predicate: 'a', object: 'b' }), 'c', 'd'); - writer.addTriple(writer.blank([{ predicate: 'a', object: 'b' }]), 'c', 'd'); + writer.addTriple(writer.blank(new NamedNode('a'), new NamedNode('b')), new NamedNode('c'), new NamedNode('d')); + writer.addTriple(writer.blank({ predicate: new NamedNode('a'), object: new NamedNode('b') }), new NamedNode('c'), new NamedNode('d')); + writer.addTriple(writer.blank([{ predicate: new NamedNode('a'), object: new NamedNode('b') }]), new NamedNode('c'), new NamedNode('d')); writer.end(function (error, output) { output.should.equal('[ ] .\n' + '[ ] .\n' + @@ -421,8 +427,8 @@ describe('N3Writer', function () { it('should serialize triples with an empty blank node as graph', function (done) { var writer = N3Writer(); - writer.addTriple('a', 'b', 'c', writer.blank()); - writer.addTriple('a', 'b', 'c', writer.blank([])); + writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c'), writer.blank()); + writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c'), writer.blank([])); writer.end(function (error, output) { output.should.equal('[] {\n \n}\n' + '[] {\n \n}\n'); @@ -432,8 +438,8 @@ describe('N3Writer', function () { it('should serialize triples with an empty list as object', function (done) { var writer = N3Writer(); - writer.addTriple('a1', 'b', writer.list()); - writer.addTriple('a2', 'b', writer.list([])); + writer.addTriple(new NamedNode('a1'), new NamedNode('b'), writer.list()); + writer.addTriple(new NamedNode('a2'), new NamedNode('b'), writer.list([])); writer.end(function (error, output) { output.should.equal(' ().\n' + ' ().\n'); @@ -443,8 +449,8 @@ describe('N3Writer', function () { it('should serialize triples with a one-element list as object', function (done) { var writer = N3Writer(); - writer.addTriple('a1', 'b', writer.list(['c'])); - writer.addTriple('a2', 'b', writer.list(['"c"'])); + writer.addTriple(new NamedNode('a1'), new NamedNode('b'), writer.list([new NamedNode('c')])); + writer.addTriple(new NamedNode('a2'), new NamedNode('b'), writer.list([new Literal('"c"')])); writer.end(function (error, output) { output.should.equal(' ().\n' + ' ("c").\n'); @@ -454,8 +460,8 @@ describe('N3Writer', function () { it('should serialize triples with a three-element list as object', function (done) { var writer = N3Writer(); - writer.addTriple('a1', 'b', writer.list(['c', 'd', 'e'])); - writer.addTriple('a2', 'b', writer.list(['"c"', '"d"', '"e"'])); + writer.addTriple(new NamedNode('a1'), new NamedNode('b'), writer.list([new NamedNode('c'), new NamedNode('d'), new NamedNode('e')])); + writer.addTriple(new NamedNode('a2'), new NamedNode('b'), writer.list([new Literal('"c"'), new Literal('"d"'), new Literal('"e"')])); writer.end(function (error, output) { output.should.equal(' ( ).\n' + ' ("c" "d" "e").\n'); @@ -465,8 +471,8 @@ describe('N3Writer', function () { it('should serialize triples with an empty list as subject', function (done) { var writer = N3Writer(); - writer.addTriple(writer.list(), 'b1', 'c'); - writer.addTriple(writer.list([]), 'b2', 'c'); + writer.addTriple(writer.list(), new NamedNode('b1'), new NamedNode('c')); + writer.addTriple(writer.list([]), new NamedNode('b2'), new NamedNode('c')); writer.end(function (error, output) { output.should.equal('() ;\n' + ' .\n'); @@ -476,8 +482,8 @@ describe('N3Writer', function () { it('should serialize triples with a one-element list as subject', function (done) { var writer = N3Writer(); - writer.addTriple(writer.list(['a']), 'b1', 'c'); - writer.addTriple(writer.list(['a']), 'b2', 'c'); + writer.addTriple(writer.list([new NamedNode('a')]), new NamedNode('b1'), new NamedNode('c')); + writer.addTriple(writer.list([new NamedNode('a')]), new NamedNode('b2'), new NamedNode('c')); writer.end(function (error, output) { output.should.equal('() ;\n' + ' .\n'); @@ -487,17 +493,17 @@ describe('N3Writer', function () { it('should serialize triples with a three-element list as subject', function (done) { var writer = N3Writer(); - writer.addTriple(writer.list(['a', '"b"', '"c"']), 'd', 'e'); + writer.addTriple(writer.list([new NamedNode('a1'), new Literal('"b"'), new Literal('"c"')]), new NamedNode('d'), new NamedNode('e')); writer.end(function (error, output) { - output.should.equal('( "b" "c") .\n'); + output.should.equal('( "b" "c") .\n'); done(error); }); }); it('should accept triples in bulk', function (done) { var writer = N3Writer(); - writer.addTriples([{ subject: 'a', predicate: 'b', object: 'c' }, - { subject: 'a', predicate: 'b', object: 'd' }]); + writer.addTriples([new Triple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')), + new Triple(new NamedNode('a'), new NamedNode('b'), new NamedNode('d'))]); writer.end(function (error, output) { output.should.equal(' , .\n'); done(error); @@ -506,9 +512,9 @@ describe('N3Writer', function () { it('should not allow writing after end', function (done) { var writer = N3Writer(); - writer.addTriple({ subject: 'a', predicate: 'b', object: 'c' }); + writer.addTriple(new Triple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c'))); writer.end(); - writer.addTriple({ subject: 'd', predicate: 'e', object: 'f' }, function (error) { + writer.addTriple(new Triple(new NamedNode('d'), new NamedNode('e'), new NamedNode('f')), function (error) { error.should.be.an.instanceof(Error); error.should.have.property('message', 'Cannot write because the writer has been closed.'); done(); @@ -517,8 +523,8 @@ describe('N3Writer', function () { it('should write simple triples in N-Triples mode', function (done) { var writer = N3Writer({ format: 'N-Triples' }); - writer.addTriple('a', 'b', 'c'); - writer.addTriple('a', 'b', 'd'); + writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')); + writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('d')); writer.end(function (error, output) { output.should.equal(' .\n .\n'); done(error); @@ -527,7 +533,7 @@ describe('N3Writer', function () { it('should not write an invalid literal in N-Triples mode', function (done) { var writer = N3Writer({ format: 'N-Triples' }); - writer.addTriple('a', 'b', '"c', function (error) { + writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('"c'), function (error) { error.should.be.an.instanceof(Error); error.should.have.property('message', 'Invalid literal: "c'); done(); @@ -536,8 +542,8 @@ describe('N3Writer', function () { it('should write simple quads in N-Quads mode', function (done) { var writer = N3Writer({ format: 'N-Quads' }); - writer.addTriple('a', 'b', 'c'); - writer.addTriple('a', 'b', 'd', 'g'); + writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')); + writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('d'), new NamedNode('g')); writer.end(function (error, output) { output.should.equal(' .\n .\n'); done(error); @@ -546,7 +552,7 @@ describe('N3Writer', function () { it('should not write an invalid literal in N-Quads mode', function (done) { var writer = N3Writer({ format: 'N-Quads' }); - writer.addTriple('a', 'b', '"c', 'g', function (error) { + writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('"c'), new NamedNode('g'), function (error) { error.should.be.an.instanceof(Error); error.should.have.property('message', 'Invalid literal: "c'); done(); @@ -594,7 +600,7 @@ function shouldSerialize(/* prefixes?, tripleArrays..., expectedResult */) { (function next() { var item = tripleArrays.shift(); if (item) - writer.addTriple({ subject: item[0], predicate: item[1], object: item[2], graph: item[3] }, next); + writer.addTriple(new Quad(Term.fromId(item[0]), Term.fromId(item[1]), Term.fromId(item[2]), Term.fromId(item[3])), next); else writer.end(function (error) { try { @@ -618,7 +624,7 @@ function shouldNotSerialize(/* tripleArrays..., expectedResult */) { var outputStream = new QuickStream(), writer = N3Writer(outputStream), item = tripleArrays.shift(); - writer.addTriple({ subject: item[0], predicate: item[1], object: item[2], graph: item[3] }, + writer.addTriple(new Quad(Term.fromId(item[0]), Term.fromId(item[1]), Term.fromId(item[2]), Term.fromId(item[3])), function (error) { if (error) { error.message.should.equal(expectedMessage); From 7fb82db286be087d696ac7599097b7059c648b23 Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Mon, 9 Apr 2018 17:50:24 +0200 Subject: [PATCH 13/34] Eliminate toId for object writing. --- lib/Datatypes.js | 7 ++++--- lib/N3Writer.js | 41 ++++++++++++++++++----------------------- test/N3Writer-test.js | 28 ++++------------------------ 3 files changed, 26 insertions(+), 50 deletions(-) diff --git a/lib/Datatypes.js b/lib/Datatypes.js index 94c17a86..63b69afe 100644 --- a/lib/Datatypes.js +++ b/lib/Datatypes.js @@ -3,8 +3,9 @@ var DEFAULTGRAPH; -var STRING = 'http://www.w3.org/2001/XMLSchema#string', - LANG_STRING = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString'; +var STRING = Literal.STRING = 'http://www.w3.org/2001/XMLSchema#string', + LANG_STRING = Literal.LANG_STRING = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString'; + // ## Term constructor function Term(id) { @@ -130,7 +131,7 @@ Term.subclass(Literal); // ### The text value of this literal Object.defineProperty(Literal.prototype, 'value', { get: function () { - return this.id.substring(1, this.id.indexOf('"', 1)); + return this.id.substring(1, this.id.lastIndexOf('"')); }, }); diff --git a/lib/N3Writer.js b/lib/N3Writer.js index 37002fd8..14fc3bea 100644 --- a/lib/N3Writer.js +++ b/lib/N3Writer.js @@ -2,11 +2,9 @@ var Datatype = require('./Datatypes'); var Term = Datatype.Term, + Literal = Datatype.Literal, DefaultGraph = Datatype.DefaultGraph; -// Matches a literal as represented in memory by the N3 library -var N3LiteralMatcher = /^"([^]*)"(?:\^\^(.+)|@([a-z]+(?:-[a-z0-9]+)*))?$/i; - // rdf:type predicate (for 'a' abbreviation) var RDF_PREFIX = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', RDF_TYPE = RDF_PREFIX + 'type'; @@ -65,7 +63,7 @@ N3Writer.prototype = { // ### `_writeTripleTerms` writes the triple term objects to the output stream _writeTripleTerms: function (subject, predicate, object, graph, done) { - this._writeTriple(Term.toId(subject), Term.toId(predicate), Term.toId(object), Term.toId(graph), done); + this._writeTriple(Term.toId(subject), Term.toId(predicate), object, Term.toId(graph), done); }, // ### `_writeTriple` writes the triple to the output stream @@ -105,15 +103,14 @@ N3Writer.prototype = { _writeTripleLine: function (subject, predicate, object, graph, done) { // Write the triple without prefixes delete this._prefixMatch; - try { this._write(this.tripleToString(subject, predicate, object, graph), done); } - catch (error) { done && done(error); } + this._write(this.tripleToString(subject, predicate, object, graph), done); }, // ### `tripleToString` serializes a triple or quad as a string tripleToString: function (subject, predicate, object, graph) { return this._encodeIriOrBlankNode(Term.toId(subject)) + ' ' + this._encodeIriOrBlankNode(Term.toId(predicate)) + ' ' + - this._encodeObject(Term.toId(object)) + + this._encodeObject(object) + (graph && (typeof graph === 'string' || graph.value) ? ' ' + this._encodeIriOrBlankNode(Term.toId(graph)) + '.\n' : '.\n'); }, @@ -140,15 +137,16 @@ N3Writer.prototype = { }, // ### `_encodeLiteral` represents a literal - _encodeLiteral: function (value, type, language) { + _encodeLiteral: function (literal) { // Escape special characters + var value = literal.value; if (escape.test(value)) value = value.replace(escapeAll, characterReplacer); // Write the literal, possibly with type or language - if (language) - return '"' + value + '"@' + language; - else if (type) - return '"' + value + '"^^' + this._encodeIriOrBlankNode(type); + if (literal.language) + return '"' + value + '"@' + literal.language; + else if (literal.datatype.value !== Literal.STRING) + return '"' + value + '"^^' + this._encodeIriOrBlankNode(literal.datatype.value); else return '"' + value + '"'; }, @@ -172,13 +170,10 @@ N3Writer.prototype = { // ### `_encodeObject` represents an object _encodeObject: function (object) { - // Represent an IRI or blank node - if (object[0] !== '"') - return this._encodeIriOrBlankNode(object); - // Represent a literal - var match = N3LiteralMatcher.exec(object); - if (!match) throw new Error('Invalid literal: ' + object); - return this._encodeLiteral(match[1], match[2], match[3]); + if (object.termType !== 'Literal') + return this._encodeIriOrBlankNode(Term.toId(object)); + else + return this._encodeLiteral(object); }, // ### `_blockedWrite` replaces `_write` after the writer has been closed @@ -268,7 +263,7 @@ N3Writer.prototype = { child = children[0]; if (child.object[0] !== '[') return '[ ' + this._encodePredicate(Term.toId(child.predicate)) + ' ' + - this._encodeObject(Term.toId(child.object)) + ' ]'; + this._encodeObject(child.object) + ' ]'; // Generate a multi-triple or nested blank node default: var contents = '['; @@ -277,12 +272,12 @@ N3Writer.prototype = { child = children[i]; // Write only the object is the predicate is the same as the previous if (Term.toId(child.predicate) === predicate) - contents += ', ' + this._encodeObject(Term.toId(child.object)); + contents += ', ' + this._encodeObject(child.object); // Otherwise, write the predicate and the object else { contents += (i ? ';\n ' : '\n ') + this._encodePredicate(Term.toId(child.predicate)) + ' ' + - this._encodeObject(Term.toId(child.object)); + this._encodeObject(child.object); predicate = Term.toId(child.predicate); } } @@ -294,7 +289,7 @@ N3Writer.prototype = { list: function (elements) { var length = elements && elements.length || 0, contents = new Array(length); for (var i = 0; i < length; i++) - contents[i] = this._encodeObject(Term.toId(elements[i])); + contents[i] = this._encodeObject(elements[i]); return '(' + contents.join(' ') + ')'; }, diff --git a/test/N3Writer-test.js b/test/N3Writer-test.js index deb706eb..621ae0f5 100644 --- a/test/N3Writer-test.js +++ b/test/N3Writer-test.js @@ -134,10 +134,6 @@ describe('N3Writer', function () { shouldNotSerialize(['a', '"b"', '"c"'], 'A literal as predicate is not allowed: "b"')); - it('should not serialize an invalid object literal', - shouldNotSerialize(['a', 'b', '"c'], - 'Invalid literal: "c')); - it('should not leave leading whitespace if the prefix set is empty', shouldSerialize({}, ['a', 'b', 'c'], @@ -531,35 +527,19 @@ describe('N3Writer', function () { }); }); - it('should not write an invalid literal in N-Triples mode', function (done) { - var writer = N3Writer({ format: 'N-Triples' }); - writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('"c'), function (error) { - error.should.be.an.instanceof(Error); - error.should.have.property('message', 'Invalid literal: "c'); - done(); - }); - }); - it('should write simple quads in N-Quads mode', function (done) { var writer = N3Writer({ format: 'N-Quads' }); - writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')); + var called = false; + function callback() { called = true; } + writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c'), callback); writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('d'), new NamedNode('g')); writer.end(function (error, output) { + called.should.be.true; output.should.equal(' .\n .\n'); done(error); }); }); - it('should not write an invalid literal in N-Quads mode', function (done) { - var writer = N3Writer({ format: 'N-Quads' }); - writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('"c'), new NamedNode('g'), function (error) { - error.should.be.an.instanceof(Error); - error.should.have.property('message', 'Invalid literal: "c'); - done(); - }); - }); - - it('should end when the end option is not set', function (done) { var outputStream = new QuickStream(), writer = N3Writer(outputStream, {}); outputStream.should.have.property('ended', false); From 7a2c70c1a9980bf8eb2e902ec0e6d73586b7c892 Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Mon, 9 Apr 2018 17:59:40 +0200 Subject: [PATCH 14/34] Eliminate toId for predicate writing. --- lib/N3Writer.js | 12 +++++------- test/N3StreamWriter-test.js | 4 ---- test/N3Writer-test.js | 4 ---- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/lib/N3Writer.js b/lib/N3Writer.js index 14fc3bea..b88657e5 100644 --- a/lib/N3Writer.js +++ b/lib/N3Writer.js @@ -63,7 +63,7 @@ N3Writer.prototype = { // ### `_writeTripleTerms` writes the triple term objects to the output stream _writeTripleTerms: function (subject, predicate, object, graph, done) { - this._writeTriple(Term.toId(subject), Term.toId(predicate), object, Term.toId(graph), done); + this._writeTriple(Term.toId(subject), predicate, object, Term.toId(graph), done); }, // ### `_writeTriple` writes the triple to the output stream @@ -81,7 +81,7 @@ N3Writer.prototype = { // Don't repeat the subject if it's the same if (this._subject === subject) { // Don't repeat the predicate if it's the same - if (this._predicate === predicate) + if (predicate.equals(this._predicate)) this._write(', ' + this._encodeObject(object), done); // Same subject, different predicate else @@ -163,9 +163,7 @@ N3Writer.prototype = { // ### `_encodePredicate` represents a predicate _encodePredicate: function (predicate) { - if (predicate[0] === '"') - throw new Error('A literal as predicate is not allowed: ' + predicate); - return predicate === RDF_TYPE ? 'a' : this._encodeIriOrBlankNode(predicate); + return predicate.value === RDF_TYPE ? 'a' : this._encodeIriOrBlankNode(Term.toId(predicate)); }, // ### `_encodeObject` represents an object @@ -262,7 +260,7 @@ N3Writer.prototype = { case 1: child = children[0]; if (child.object[0] !== '[') - return '[ ' + this._encodePredicate(Term.toId(child.predicate)) + ' ' + + return '[ ' + this._encodePredicate(child.predicate) + ' ' + this._encodeObject(child.object) + ' ]'; // Generate a multi-triple or nested blank node default: @@ -276,7 +274,7 @@ N3Writer.prototype = { // Otherwise, write the predicate and the object else { contents += (i ? ';\n ' : '\n ') + - this._encodePredicate(Term.toId(child.predicate)) + ' ' + + this._encodePredicate(child.predicate) + ' ' + this._encodeObject(child.object); predicate = Term.toId(child.predicate); } diff --git a/test/N3StreamWriter-test.js b/test/N3StreamWriter-test.js index 33cdec83..2abb940a 100644 --- a/test/N3StreamWriter-test.js +++ b/test/N3StreamWriter-test.js @@ -47,10 +47,6 @@ describe('N3StreamWriter', function () { shouldNotSerialize(['"a"', 'b', '"c'], 'A literal as subject is not allowed: "a"')); - it('should not serialize a literal in the predicate', - shouldNotSerialize(['a', '"b"', '"c'], - 'A literal as predicate is not allowed: "b"')); - it('should use prefixes when possible', shouldSerialize({ prefixes: { a: 'http://a.org/', b: 'http://a.org/b#', c: 'http://a.org/b' } }, ['http://a.org/bc', 'http://a.org/b#ef', 'http://a.org/bhi'], diff --git a/test/N3Writer-test.js b/test/N3Writer-test.js index 621ae0f5..9e6176a9 100644 --- a/test/N3Writer-test.js +++ b/test/N3Writer-test.js @@ -130,10 +130,6 @@ describe('N3Writer', function () { shouldNotSerialize(['"a"', 'b', '"c"'], 'A literal as subject is not allowed: "a"')); - it('should not serialize a literal in the predicate', - shouldNotSerialize(['a', '"b"', '"c"'], - 'A literal as predicate is not allowed: "b"')); - it('should not leave leading whitespace if the prefix set is empty', shouldSerialize({}, ['a', 'b', 'c'], From d3ac950ab02c0db8777abd22f7bbbe0c87cd8ede Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Mon, 9 Apr 2018 18:31:33 +0200 Subject: [PATCH 15/34] Eliminate toId for graph writing. --- lib/Datatypes.js | 2 -- lib/N3Writer.js | 28 ++++++++++++++++------------ test/N3Writer-test.js | 2 +- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/lib/Datatypes.js b/lib/Datatypes.js index 63b69afe..b06d9720 100644 --- a/lib/Datatypes.js +++ b/lib/Datatypes.js @@ -191,8 +191,6 @@ Literal.prototype.toJSON = function () { // ## DefaultGraph singleton function DefaultGraph() { - if (!(this instanceof DefaultGraph)) - return new DefaultGraph(); return DEFAULTGRAPH || this; } Term.subclass(DefaultGraph); diff --git a/lib/N3Writer.js b/lib/N3Writer.js index b88657e5..c49dcc00 100644 --- a/lib/N3Writer.js +++ b/lib/N3Writer.js @@ -3,7 +3,7 @@ var Datatype = require('./Datatypes'); var Term = Datatype.Term, Literal = Datatype.Literal, - DefaultGraph = Datatype.DefaultGraph; + DEFAULTGRAPH = new Datatype.DefaultGraph(); // rdf:type predicate (for 'a' abbreviation) var RDF_PREFIX = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', @@ -44,7 +44,7 @@ function N3Writer(outputStream, options) { // Initialize writer, depending on the format this._subject = null; if (!(/triple|quad/i).test(options.format)) { - this._graph = ''; + this._graph = DEFAULTGRAPH; this._prefixIRIs = Object.create(null); options.prefixes && this.addPrefixes(options.prefixes); } @@ -56,6 +56,11 @@ function N3Writer(outputStream, options) { N3Writer.prototype = { // ## Private methods + // ### Whether the current graph is the default graph + get _inDefaultGraph() { + return DEFAULTGRAPH.equals(this._graph); + }, + // ### `_write` writes the argument to the output stream _write: function (string, callback) { this._outputStream.write(string, 'utf8', callback); @@ -63,20 +68,19 @@ N3Writer.prototype = { // ### `_writeTripleTerms` writes the triple term objects to the output stream _writeTripleTerms: function (subject, predicate, object, graph, done) { - this._writeTriple(Term.toId(subject), predicate, object, Term.toId(graph), done); + this._writeTriple(Term.toId(subject), predicate, object, graph, done); }, // ### `_writeTriple` writes the triple to the output stream _writeTriple: function (subject, predicate, object, graph, done) { try { // Write the graph's label if it has changed - if (this._graph !== graph) { + if (!graph.equals(this._graph)) { // Close the previous graph and start the new one - this._write((this._subject === null ? '' : (this._graph ? '\n}\n' : '.\n')) + - (graph ? this._encodeIriOrBlankNode(graph) + ' {\n' : '')); + this._write((this._subject === null ? '' : (this._inDefaultGraph ? '.\n' : '\n}\n')) + + (DEFAULTGRAPH.equals(graph) ? '' : this._encodeIriOrBlankNode(Term.toId(graph)) + ' {\n')); + this._graph = graph; this._subject = null; - // Don't treat identical blank nodes as repeating graphs - this._graph = graph[0] !== '[' ? graph : ']'; } // Don't repeat the subject if it's the same if (this._subject === subject) { @@ -186,10 +190,10 @@ N3Writer.prototype = { this._writeTripleTerms(subject.subject, subject.predicate, subject.object, subject.graph, predicate); // The optional `graph` parameter was not provided else if (typeof graph === 'function') - this._writeTripleTerms(subject, predicate, object, new DefaultGraph(), graph); + this._writeTripleTerms(subject, predicate, object, DEFAULTGRAPH, graph); // The `graph` parameter was provided else - this._writeTripleTerms(subject, predicate, object, graph, done); + this._writeTripleTerms(subject, predicate, object, graph || DEFAULTGRAPH, done); }, // ### `addTriples` adds the triples to the output stream @@ -217,7 +221,7 @@ N3Writer.prototype = { prefixIRIs[iri] = prefix; // Finish a possible pending triple if (this._subject !== null) { - this._write(this._graph ? '\n}\n' : '.\n'); + this._write(this._inDefaultGraph ? '.\n' : '\n}\n'); this._subject = null, this._graph = ''; } // Write prefix @@ -298,7 +302,7 @@ N3Writer.prototype = { end: function (done) { // Finish a possible pending triple if (this._subject !== null) { - this._write(this._graph ? '\n}\n' : '.\n'); + this._write(this._inDefaultGraph ? '.\n' : '\n}\n'); this._subject = null; } // Disallow further writing diff --git a/test/N3Writer-test.js b/test/N3Writer-test.js index 9e6176a9..f886e5ca 100644 --- a/test/N3Writer-test.js +++ b/test/N3Writer-test.js @@ -417,7 +417,7 @@ describe('N3Writer', function () { }); }); - it('should serialize triples with an empty blank node as graph', function (done) { + it.skip('should serialize triples with an empty blank node as graph', function (done) { var writer = N3Writer(); writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c'), writer.blank()); writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c'), writer.blank([])); From 83c6346ccf100c8c9478407d4034f5b0918c7588 Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Mon, 9 Apr 2018 19:25:11 +0200 Subject: [PATCH 16/34] Eliminate toId for subject writing. --- lib/N3Writer.js | 74 ++++++++++++++++++------------------- test/N3StreamWriter-test.js | 22 ----------- test/N3Writer-test.js | 32 +++------------- 3 files changed, 42 insertions(+), 86 deletions(-) diff --git a/lib/N3Writer.js b/lib/N3Writer.js index c49dcc00..ea989e79 100644 --- a/lib/N3Writer.js +++ b/lib/N3Writer.js @@ -66,11 +66,6 @@ N3Writer.prototype = { this._outputStream.write(string, 'utf8', callback); }, - // ### `_writeTripleTerms` writes the triple term objects to the output stream - _writeTripleTerms: function (subject, predicate, object, graph, done) { - this._writeTriple(Term.toId(subject), predicate, object, graph, done); - }, - // ### `_writeTriple` writes the triple to the output stream _writeTriple: function (subject, predicate, object, graph, done) { try { @@ -78,12 +73,12 @@ N3Writer.prototype = { if (!graph.equals(this._graph)) { // Close the previous graph and start the new one this._write((this._subject === null ? '' : (this._inDefaultGraph ? '.\n' : '\n}\n')) + - (DEFAULTGRAPH.equals(graph) ? '' : this._encodeIriOrBlankNode(Term.toId(graph)) + ' {\n')); + (DEFAULTGRAPH.equals(graph) ? '' : this._encodeIriOrBlankNode(graph) + ' {\n')); this._graph = graph; this._subject = null; } // Don't repeat the subject if it's the same - if (this._subject === subject) { + if (subject.equals(this._subject)) { // Don't repeat the predicate if it's the same if (predicate.equals(this._predicate)) this._write(', ' + this._encodeObject(object), done); @@ -112,10 +107,10 @@ N3Writer.prototype = { // ### `tripleToString` serializes a triple or quad as a string tripleToString: function (subject, predicate, object, graph) { - return this._encodeIriOrBlankNode(Term.toId(subject)) + ' ' + - this._encodeIriOrBlankNode(Term.toId(predicate)) + ' ' + + return this._encodeIriOrBlankNode(subject) + ' ' + + this._encodeIriOrBlankNode(predicate) + ' ' + this._encodeObject(object) + - (graph && (typeof graph === 'string' || graph.value) ? ' ' + this._encodeIriOrBlankNode(Term.toId(graph)) + '.\n' : '.\n'); + (graph && (typeof graph === 'string' || graph.value) ? ' ' + this._encodeIriOrBlankNode(graph) + '.\n' : '.\n'); }, // ### `triplesToString` serializes an array of triples or quads as a string @@ -128,16 +123,16 @@ N3Writer.prototype = { // ### `_encodeIriOrBlankNode` represents an IRI or blank node _encodeIriOrBlankNode: function (entity) { // A blank node or list is represented as-is - var firstChar = entity[0]; - if (firstChar === '[' || firstChar === '(' || firstChar === '_' && entity[1] === ':') - return entity; + if (entity.termType !== 'NamedNode') + return entity.id; // Escape special characters - if (escape.test(entity)) - entity = entity.replace(escapeAll, characterReplacer); + var iri = entity.value; + if (escape.test(iri)) + iri = iri.replace(escapeAll, characterReplacer); // Try to represent the IRI as prefixed name - var prefixMatch = this._prefixRegex.exec(entity); - return !prefixMatch ? '<' + entity + '>' : - (!prefixMatch[1] ? entity : this._prefixIRIs[prefixMatch[1]] + prefixMatch[2]); + var prefixMatch = this._prefixRegex.exec(iri); + return !prefixMatch ? '<' + iri + '>' : + (!prefixMatch[1] ? iri : this._prefixIRIs[prefixMatch[1]] + prefixMatch[2]); }, // ### `_encodeLiteral` represents a literal @@ -150,30 +145,25 @@ N3Writer.prototype = { if (literal.language) return '"' + value + '"@' + literal.language; else if (literal.datatype.value !== Literal.STRING) - return '"' + value + '"^^' + this._encodeIriOrBlankNode(literal.datatype.value); + return '"' + value + '"^^' + this._encodeIriOrBlankNode(literal.datatype); else return '"' + value + '"'; }, // ### `_encodeSubject` represents a subject _encodeSubject: function (subject) { - if (subject[0] === '"') - throw new Error('A literal as subject is not allowed: ' + subject); - // Don't treat identical blank nodes as repeating subjects - if (subject[0] === '[') - this._subject = ']'; return this._encodeIriOrBlankNode(subject); }, // ### `_encodePredicate` represents a predicate _encodePredicate: function (predicate) { - return predicate.value === RDF_TYPE ? 'a' : this._encodeIriOrBlankNode(Term.toId(predicate)); + return predicate.value === RDF_TYPE ? 'a' : this._encodeIriOrBlankNode(predicate); }, // ### `_encodeObject` represents an object _encodeObject: function (object) { if (object.termType !== 'Literal') - return this._encodeIriOrBlankNode(Term.toId(object)); + return this._encodeIriOrBlankNode(object); else return this._encodeLiteral(object); }, @@ -187,13 +177,13 @@ N3Writer.prototype = { addTriple: function (subject, predicate, object, graph, done) { // The triple was given as a triple object, so shift parameters if (object === undefined) - this._writeTripleTerms(subject.subject, subject.predicate, subject.object, subject.graph, predicate); + this._writeTriple(subject.subject, subject.predicate, subject.object, subject.graph, predicate); // The optional `graph` parameter was not provided else if (typeof graph === 'function') - this._writeTripleTerms(subject, predicate, object, DEFAULTGRAPH, graph); + this._writeTriple(subject, predicate, object, DEFAULTGRAPH, graph); // The `graph` parameter was provided else - this._writeTripleTerms(subject, predicate, object, graph || DEFAULTGRAPH, done); + this._writeTriple(subject, predicate, object, graph || DEFAULTGRAPH, done); }, // ### `addTriples` adds the triples to the output stream @@ -259,13 +249,13 @@ N3Writer.prototype = { switch (length = children.length) { // Generate an empty blank node case 0: - return '[]'; + return new SerializedTerm('[]'); // Generate a non-nested one-triple blank node case 1: child = children[0]; - if (child.object[0] !== '[') - return '[ ' + this._encodePredicate(child.predicate) + ' ' + - this._encodeObject(child.object) + ' ]'; + if (!(child.object instanceof SerializedTerm)) + return new SerializedTerm('[ ' + this._encodePredicate(child.predicate) + ' ' + + this._encodeObject(child.object) + ' ]'); // Generate a multi-triple or nested blank node default: var contents = '['; @@ -273,17 +263,17 @@ N3Writer.prototype = { for (var i = 0; i < length; i++) { child = children[i]; // Write only the object is the predicate is the same as the previous - if (Term.toId(child.predicate) === predicate) + if (child.predicate.equals(predicate)) contents += ', ' + this._encodeObject(child.object); // Otherwise, write the predicate and the object else { contents += (i ? ';\n ' : '\n ') + this._encodePredicate(child.predicate) + ' ' + this._encodeObject(child.object); - predicate = Term.toId(child.predicate); + predicate = child.predicate; } } - return contents + '\n]'; + return new SerializedTerm(contents + '\n]'); } }, @@ -292,7 +282,7 @@ N3Writer.prototype = { var length = elements && elements.length || 0, contents = new Array(length); for (var i = 0; i < length; i++) contents[i] = this._encodeObject(elements[i]); - return '(' + contents.join(' ') + ')'; + return new SerializedTerm('(' + contents.join(' ') + ')'); }, // ### `_prefixRegex` matches a prefixed name or IRI that begins with one of the added prefixes @@ -338,5 +328,15 @@ function characterReplacer(character) { return result; } +// ## Placeholder class to represent already pretty-printed terms +function SerializedTerm(value) { + this.id = value; +} +Term.subclass(SerializedTerm); + +// Pretty-printed nodes are not equal to any other node +// (e.g., [] does not equal []) +SerializedTerm.prototype.equals = function () { return false; }; + // ## Exports module.exports = N3Writer; diff --git a/test/N3StreamWriter-test.js b/test/N3StreamWriter-test.js index 2abb940a..cb252c77 100644 --- a/test/N3StreamWriter-test.js +++ b/test/N3StreamWriter-test.js @@ -43,10 +43,6 @@ describe('N3StreamWriter', function () { ' .\n' + ' .\n')); - it('should not serialize a literal in the subject', - shouldNotSerialize(['"a"', 'b', '"c'], - 'A literal as subject is not allowed: "a"')); - it('should use prefixes when possible', shouldSerialize({ prefixes: { a: 'http://a.org/', b: 'http://a.org/b#', c: 'http://a.org/b' } }, ['http://a.org/bc', 'http://a.org/b#ef', 'http://a.org/bhi'], @@ -80,24 +76,6 @@ function shouldSerialize(/* options?, tripleArrays..., expectedResult */) { }; } -function shouldNotSerialize(/* tripleArrays..., expectedMessage */) { - var tripleArrays = Array.prototype.slice.call(arguments), - expectedMessage = tripleArrays.pop(); - - return function (done) { - var inputStream = new ArrayReader(tripleArrays), - transform = new N3StreamWriter(), - outputStream = new StringWriter(); - inputStream.pipe(transform); - transform.pipe(outputStream); - transform.on('error', function (error) { - error.should.be.an.instanceof(Error); - error.message.should.equal(expectedMessage); - done(); - }); - }; -} - function ArrayReader(items) { var reader = new Readable({ objectMode: true }); items = items.map(function (i) { return new Quad(Term.fromId(i[0]), Term.fromId(i[1]), Term.fromId(i[2])); }); diff --git a/test/N3Writer-test.js b/test/N3Writer-test.js index f886e5ca..99bc9099 100644 --- a/test/N3Writer-test.js +++ b/test/N3Writer-test.js @@ -126,10 +126,6 @@ describe('N3Writer', function () { shouldSerialize(['_:a', 'b', '_:c'], '_:a _:c.\n')); - it('should not serialize a literal in the subject', - shouldNotSerialize(['"a"', 'b', '"c"'], - 'A literal as subject is not allowed: "a"')); - it('should not leave leading whitespace if the prefix set is empty', shouldSerialize({}, ['a', 'b', 'c'], @@ -417,7 +413,7 @@ describe('N3Writer', function () { }); }); - it.skip('should serialize triples with an empty blank node as graph', function (done) { + it('should serialize triples with an empty blank node as graph', function (done) { var writer = N3Writer(); writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c'), writer.blank()); writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c'), writer.blank([])); @@ -466,8 +462,8 @@ describe('N3Writer', function () { writer.addTriple(writer.list(), new NamedNode('b1'), new NamedNode('c')); writer.addTriple(writer.list([]), new NamedNode('b2'), new NamedNode('c')); writer.end(function (error, output) { - output.should.equal('() ;\n' + - ' .\n'); + output.should.equal('() .\n' + + '() .\n'); done(error); }); }); @@ -477,8 +473,8 @@ describe('N3Writer', function () { writer.addTriple(writer.list([new NamedNode('a')]), new NamedNode('b1'), new NamedNode('c')); writer.addTriple(writer.list([new NamedNode('a')]), new NamedNode('b2'), new NamedNode('c')); writer.end(function (error, output) { - output.should.equal('() ;\n' + - ' .\n'); + output.should.equal('() .\n' + + '() .\n'); done(error); }); }); @@ -592,24 +588,6 @@ function shouldSerialize(/* prefixes?, tripleArrays..., expectedResult */) { }; } -function shouldNotSerialize(/* tripleArrays..., expectedResult */) { - var tripleArrays = Array.prototype.slice.call(arguments), - expectedMessage = tripleArrays.pop(); - - return function (done) { - var outputStream = new QuickStream(), - writer = N3Writer(outputStream), - item = tripleArrays.shift(); - writer.addTriple(new Quad(Term.fromId(item[0]), Term.fromId(item[1]), Term.fromId(item[2]), Term.fromId(item[3])), - function (error) { - if (error) { - error.message.should.equal(expectedMessage); - done(); - } - }); - }; -} - function QuickStream() { var stream = { ended: false }, buffer = ''; stream.write = function (chunk, encoding, callback) { From fec8df872ebb1f5493cb61524d1de04c1bfa6c98 Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Mon, 9 Apr 2018 20:06:31 +0200 Subject: [PATCH 17/34] Simplify writer. --- lib/N3Writer.js | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/lib/N3Writer.js b/lib/N3Writer.js index ea989e79..a75efc86 100644 --- a/lib/N3Writer.js +++ b/lib/N3Writer.js @@ -73,7 +73,7 @@ N3Writer.prototype = { if (!graph.equals(this._graph)) { // Close the previous graph and start the new one this._write((this._subject === null ? '' : (this._inDefaultGraph ? '.\n' : '\n}\n')) + - (DEFAULTGRAPH.equals(graph) ? '' : this._encodeIriOrBlankNode(graph) + ' {\n')); + (DEFAULTGRAPH.equals(graph) ? '' : this._encodeIriOrBlank(graph) + ' {\n')); this._graph = graph; this._subject = null; } @@ -91,7 +91,7 @@ N3Writer.prototype = { // Different subject; write the whole triple else this._write((this._subject === null ? '' : '.\n') + - this._encodeSubject(this._subject = subject) + ' ' + + this._encodeIriOrBlank(this._subject = subject) + ' ' + this._encodePredicate(this._predicate = predicate) + ' ' + this._encodeObject(object), done); } @@ -107,10 +107,10 @@ N3Writer.prototype = { // ### `tripleToString` serializes a triple or quad as a string tripleToString: function (subject, predicate, object, graph) { - return this._encodeIriOrBlankNode(subject) + ' ' + - this._encodeIriOrBlankNode(predicate) + ' ' + + return this._encodeIriOrBlank(subject) + ' ' + + this._encodeIriOrBlank(predicate) + ' ' + this._encodeObject(object) + - (graph && (typeof graph === 'string' || graph.value) ? ' ' + this._encodeIriOrBlankNode(graph) + '.\n' : '.\n'); + (graph && graph.value ? ' ' + this._encodeIriOrBlank(graph) + '.\n' : '.\n'); }, // ### `triplesToString` serializes an array of triples or quads as a string @@ -120,8 +120,8 @@ N3Writer.prototype = { }, this).join(''); }, - // ### `_encodeIriOrBlankNode` represents an IRI or blank node - _encodeIriOrBlankNode: function (entity) { + // ### `_encodeIriOrBlank` represents an IRI or blank node + _encodeIriOrBlank: function (entity) { // A blank node or list is represented as-is if (entity.termType !== 'NamedNode') return entity.id; @@ -145,27 +145,19 @@ N3Writer.prototype = { if (literal.language) return '"' + value + '"@' + literal.language; else if (literal.datatype.value !== Literal.STRING) - return '"' + value + '"^^' + this._encodeIriOrBlankNode(literal.datatype); + return '"' + value + '"^^' + this._encodeIriOrBlank(literal.datatype); else return '"' + value + '"'; }, - // ### `_encodeSubject` represents a subject - _encodeSubject: function (subject) { - return this._encodeIriOrBlankNode(subject); - }, - // ### `_encodePredicate` represents a predicate _encodePredicate: function (predicate) { - return predicate.value === RDF_TYPE ? 'a' : this._encodeIriOrBlankNode(predicate); + return predicate.value === RDF_TYPE ? 'a' : this._encodeIriOrBlank(predicate); }, // ### `_encodeObject` represents an object _encodeObject: function (object) { - if (object.termType !== 'Literal') - return this._encodeIriOrBlankNode(object); - else - return this._encodeLiteral(object); + return object.termType === 'Literal' ? this._encodeLiteral(object) : this._encodeIriOrBlank(object); }, // ### `_blockedWrite` replaces `_write` after the writer has been closed From 00a4818b5bda8ca49dd4f862344ed13ad0d96b4f Mon Sep 17 00:00:00 2001 From: Ruben Taelman Date: Wed, 18 Oct 2017 15:05:29 +0900 Subject: [PATCH 18/34] Migrate store to RDF/JS interface --- lib/N3Store.js | 71 +++++++++-- test/N3Store-test.js | 292 +++++++++++++++++++++++++++---------------- 2 files changed, 240 insertions(+), 123 deletions(-) diff --git a/lib/N3Store.js b/lib/N3Store.js index fb29a3a7..60f33c6e 100644 --- a/lib/N3Store.js +++ b/lib/N3Store.js @@ -1,6 +1,10 @@ // **N3Store** objects store N3 triples by graph in memory. var expandPrefixedName = require('./N3Util').expandPrefixedName; +var Datatype = require('./Datatypes'); +var Term = Datatype.Term, + BlankNode = Datatype.BlankNode, + Quad = Datatype.Quad; // ## Constructor function N3Store(triples, options) { @@ -112,10 +116,10 @@ N3Store.prototype = { var values = key2 ? (key2 in index2 ? [key2] : []) : Object.keys(index2); // Create triples for all items found in index 2. for (var l = values.length - 1; l >= 0; l--) { - var result = { subject: '', predicate: '', object: '', graph: graph }; - result[name0] = entity0; - result[name1] = entity1; - result[name2] = entityKeys[values[l]]; + var result = new Quad(null, null, null, Term.fromId(graph)); + result[name0] = Term.fromId(entity0); + result[name1] = Term.fromId(entity1); + result[name2] = Term.fromId(entityKeys[values[l]]); if (array) array.push(result); else if (callback(result)) @@ -204,14 +208,14 @@ N3Store.prototype = { return function (id) { if (!(id in uniqueIds)) { uniqueIds[id] = true; - callback(entities[id]); + callback(Term.fromId(entities[id])); } }; }, // ## Public methods - // ### `addTriple` adds a new N3 triple to the store. + // ### `addTriple` adds a new triple to the store. // Returns if the triple index has changed, if the triple did not already exist. addTriple: function (subject, predicate, object, graph) { // Shift arguments if a triple object is given instead of components @@ -219,8 +223,13 @@ N3Store.prototype = { graph = subject.graph, object = subject.object, predicate = subject.predicate, subject = subject.subject; + // Convert terms to internal string representation + subject = Term.toId(subject); + predicate = Term.toId(predicate); + object = Term.toId(object); + graph = Term.toId(graph); + // Find the graph that will contain the triple - graph = graph || ''; var graphItem = this._graphs[graph]; // Create the graph if it doesn't exist yet if (!graphItem) { @@ -248,7 +257,7 @@ N3Store.prototype = { return changed; }, - // ### `addTriples` adds multiple N3 triples to the store + // ### `addTriples` adds multiple triples to the store addTriples: function (triples) { for (var i = triples.length - 1; i >= 0; i--) this.addTriple(triples[i]); @@ -265,13 +274,18 @@ N3Store.prototype = { this.addPrefix(prefix, prefixes[prefix]); }, - // ### `removeTriple` removes an N3 triple from the store if it exists + // ### `removeTriple` removes a triple from the store if it exists removeTriple: function (subject, predicate, object, graph) { // Shift arguments if a triple object is given instead of components if (!predicate) graph = subject.graph, object = subject.object, predicate = subject.predicate, subject = subject.subject; - graph = graph || ''; + + // Convert terms to internal string representation + subject = Term.toId(subject); + predicate = Term.toId(predicate); + object = Term.toId(object); + graph = Term.toId(graph); // Find internal identifiers for all components // and verify the triple exists. @@ -295,7 +309,7 @@ N3Store.prototype = { return true; }, - // ### `removeTriples` removes multiple N3 triples from the store + // ### `removeTriples` removes multiple triples from the store removeTriples: function (triples) { for (var i = triples.length - 1; i >= 0; i--) this.removeTriple(triples[i]); @@ -316,6 +330,12 @@ N3Store.prototype = { // ### `getTriplesByIRI` returns an array of triples matching a pattern. // Setting any field to `undefined` or `null` indicates a wildcard. getTriplesByIRI: function (subject, predicate, object, graph) { + // Convert terms to internal string representation + subject = subject && Term.toId(subject); + predicate = predicate && Term.toId(predicate); + object = object && Term.toId(object); + graph = graph && Term.toId(graph); + var quads = [], graphs = this._getGraphs(graph), content, ids = this._ids, subjectId, predicateId, objectId; @@ -371,6 +391,12 @@ N3Store.prototype = { // ### `countTriplesByIRI` returns the number of triples matching a pattern. // Setting any field to `undefined` or `null` indicates a wildcard. countTriplesByIRI: function (subject, predicate, object, graph) { + // Convert terms to internal string representation + subject = subject && Term.toId(subject); + predicate = predicate && Term.toId(predicate); + object = object && Term.toId(object); + graph = graph && Term.toId(graph); + var count = 0, graphs = this._getGraphs(graph), content, ids = this._ids, subjectId, predicateId, objectId; @@ -471,6 +497,12 @@ N3Store.prototype = { // and returns `true` if it returns truthy for any of them. // Setting any field to `undefined` or `null` indicates a wildcard. someByIRI: function (callback, subject, predicate, object, graph) { + // Convert terms to internal string representation + subject = subject && Term.toId(subject); + predicate = predicate && Term.toId(predicate); + object = object && Term.toId(object); + graph = graph && Term.toId(graph); + var graphs = this._getGraphs(graph), content, ids = this._ids, subjectId, predicateId, objectId; @@ -556,6 +588,11 @@ N3Store.prototype = { // ### `forSubjectsByIRI` executes the callback on all subjects that match the pattern. // Setting any field to `undefined` or `null` indicates a wildcard. forSubjectsByIRI: function (callback, predicate, object, graph) { + // Convert terms to internal string representation + predicate = predicate && Term.toId(predicate); + object = object && Term.toId(object); + graph = graph && Term.toId(graph); + var ids = this._ids, graphs = this._getGraphs(graph), content, predicateId, objectId; callback = this._uniqueEntities(callback); @@ -620,6 +657,11 @@ N3Store.prototype = { // ### `forPredicatesByIRI` executes the callback on all predicates that match the pattern. // Setting any field to `undefined` or `null` indicates a wildcard. forPredicatesByIRI: function (callback, subject, object, graph) { + // Convert terms to internal string representation + subject = subject && Term.toId(subject); + object = object && Term.toId(object); + graph = graph && Term.toId(graph); + var ids = this._ids, graphs = this._getGraphs(graph), content, subjectId, objectId; callback = this._uniqueEntities(callback); @@ -684,6 +726,11 @@ N3Store.prototype = { // ### `forObjectsByIRI` executes the callback on all objects that match the pattern. // Setting any field to `undefined` or `null` indicates a wildcard. forObjectsByIRI: function (callback, subject, predicate, graph) { + // Convert terms to internal string representation + subject = subject && Term.toId(subject); + predicate = predicate && Term.toId(predicate); + graph = graph && Term.toId(graph); + var ids = this._ids, graphs = this._getGraphs(graph), content, subjectId, predicateId; callback = this._uniqueEntities(callback); @@ -773,7 +820,7 @@ N3Store.prototype = { // Add the blank node to the entities, avoiding the generation of duplicates this._ids[name] = ++this._id; this._entities[this._id] = name; - return name; + return new BlankNode(name.substr(2)); }, }; diff --git a/test/N3Store-test.js b/test/N3Store-test.js index 4657af1d..4bc04c68 100644 --- a/test/N3Store-test.js +++ b/test/N3Store-test.js @@ -1,4 +1,11 @@ -var N3Store = require('../N3').Store; +var N3Store = require('../N3').Store, + Datatype = require('../lib/Datatypes'); +var Term = Datatype.Term, + NamedNode = Datatype.NamedNode, + Literal = Datatype.Literal, + DefaultGraph = Datatype.DefaultGraph, + Quad = Datatype.Quad, + Triple = Datatype.Triple; describe('N3Store', function () { describe('The N3Store module', function () { @@ -54,38 +61,38 @@ describe('N3Store', function () { it('should still have size 0 (instead of null) after adding and removing a triple', function () { expect(store.size).to.eql(0); - store.addTriple('a', 'b', 'c').should.be.true; - store.removeTriple('a', 'b', 'c').should.be.true; + store.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')).should.be.true; + store.removeTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')).should.be.true; expect(store.size).to.eql(0); }); it('should be able to generate unnamed blank nodes', function () { - store.createBlankNode().should.eql('_:b0'); - store.createBlankNode().should.eql('_:b1'); + store.createBlankNode().value.should.eql('b0'); + store.createBlankNode().value.should.eql('b1'); store.addTriple('_:b0', '_:b1', '_:b2').should.be.true; - store.createBlankNode().should.eql('_:b3'); + store.createBlankNode().value.should.eql('b3'); store.removeTriples(store.getTriples()); }); it('should be able to generate named blank nodes', function () { - store.createBlankNode('blank').should.eql('_:blank'); - store.createBlankNode('blank').should.eql('_:blank1'); - store.createBlankNode('blank').should.eql('_:blank2'); + store.createBlankNode('blank').value.should.eql('blank'); + store.createBlankNode('blank').value.should.eql('blank1'); + store.createBlankNode('blank').value.should.eql('blank2'); }); it('should be able to store triples with generated blank nodes', function () { - store.addTriple(store.createBlankNode('x'), 'b', 'c').should.be.true; - shouldIncludeAll(store.getTriples(null, 'b'), ['_:x1', 'b', 'd']); + store.addTriple(store.createBlankNode('x'), new NamedNode('b'), new NamedNode('c')).should.be.true; + shouldIncludeAll(store.getTriples(null, new NamedNode('b')), ['_:x', 'b', 'c'])(); store.removeTriples(store.getTriples()); }); }); describe('An N3Store with initialized with 3 elements', function () { var store = new N3Store([ - { subject: 's1', predicate: 'p1', object: 'o1' }, - { subject: 's1', predicate: 'p1', object: 'o2' }, - { subject: 's1', predicate: 'p1', object: 'o3' }, + new Quad(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o1')), + new Quad(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o2')), + new Quad(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o3')), ]); it('should have size 3', function () { @@ -159,7 +166,7 @@ describe('N3Store', function () { describe('when searched with an existing subject parameter', function () { it('should return all items with this subject in all graphs', - shouldIncludeAll(store.getTriples('s1', null, null), + shouldIncludeAll(store.getTriples(new NamedNode('s1'), null, null), ['s1', 'p1', 'o1'], ['s1', 'p1', 'o2'], ['s1', 'p2', 'o2'], @@ -167,16 +174,16 @@ describe('N3Store', function () { }); describe('when searched with a non-existing subject parameter', function () { - itShouldBeEmpty(store.getTriples('s3', null, null)); + itShouldBeEmpty(store.getTriples(new NamedNode('s3'), null, null)); }); describe('when searched with a non-existing subject parameter that exists elsewhere', function () { - itShouldBeEmpty(store.getTriples('p1', null, null)); + itShouldBeEmpty(store.getTriples(new NamedNode('p1'), null, null)); }); describe('when searched with an existing predicate parameter', function () { it('should return all items with this predicate in all graphs', - shouldIncludeAll(store.getTriples(null, 'p1', null), + shouldIncludeAll(store.getTriples(null, new NamedNode('p1'), null), ['s1', 'p1', 'o1'], ['s1', 'p1', 'o2'], ['s2', 'p1', 'o1'], @@ -184,70 +191,70 @@ describe('N3Store', function () { }); describe('when searched with a non-existing predicate parameter', function () { - itShouldBeEmpty(store.getTriples(null, 'p3', null)); + itShouldBeEmpty(store.getTriples(null, new NamedNode('p3'), null)); }); describe('when searched with an existing object parameter', function () { it('should return all items with this object in all graphs', - shouldIncludeAll(store.getTriples(null, null, 'o1'), + shouldIncludeAll(store.getTriples(null, null, new NamedNode('o1')), ['s1', 'p1', 'o1'], ['s2', 'p1', 'o1'], ['s1', 'p1', 'o1', 'c4'])); }); describe('when searched with a non-existing object parameter', function () { - itShouldBeEmpty(store.getTriples(null, null, 'o4')); + itShouldBeEmpty(store.getTriples(null, null, new NamedNode('o4'))); }); describe('when searched with existing subject and predicate parameters', function () { it('should return all items with this subject and predicate in all graphs', - shouldIncludeAll(store.getTriples('s1', 'p1', null), + shouldIncludeAll(store.getTriples(new NamedNode('s1'), new NamedNode('p1'), null), ['s1', 'p1', 'o1'], ['s1', 'p1', 'o2'], ['s1', 'p1', 'o1', 'c4'])); }); describe('when searched with non-existing subject and predicate parameters', function () { - itShouldBeEmpty(store.getTriples('s2', 'p2', null)); + itShouldBeEmpty(store.getTriples(new NamedNode('s2'), new NamedNode('p2'), null)); }); describe('when searched with existing subject and object parameters', function () { it('should return all items with this subject and object in all graphs', - shouldIncludeAll(store.getTriples('s1', null, 'o1'), + shouldIncludeAll(store.getTriples(new NamedNode('s1'), null, new NamedNode('o1')), ['s1', 'p1', 'o1'], ['s1', 'p1', 'o1', 'c4'])); }); describe('when searched with non-existing subject and object parameters', function () { - itShouldBeEmpty(store.getTriples('s2', 'p2', null)); + itShouldBeEmpty(store.getTriples(new NamedNode('s2'), new NamedNode('p2'), null)); }); describe('when searched with existing predicate and object parameters', function () { it('should return all items with this predicate and object in all graphs', - shouldIncludeAll(store.getTriples(null, 'p1', 'o1'), + shouldIncludeAll(store.getTriples(null, new NamedNode('p1'), new NamedNode('o1')), ['s1', 'p1', 'o1'], ['s2', 'p1', 'o1'], ['s1', 'p1', 'o1', 'c4'])); }); describe('when searched with non-existing predicate and object parameters in the default graph', function () { - itShouldBeEmpty(store.getTriples(null, 'p2', 'o3', '')); + itShouldBeEmpty(store.getTriples(null, new NamedNode('p2'), new NamedNode('o3'), new DefaultGraph())); }); describe('when searched with existing subject, predicate, and object parameters', function () { it('should return all items with this subject, predicate, and object in all graphs', - shouldIncludeAll(store.getTriples('s1', 'p1', 'o1'), + shouldIncludeAll(store.getTriples(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o1')), ['s1', 'p1', 'o1'], ['s1', 'p1', 'o1', 'c4'])); }); describe('when searched with a non-existing triple', function () { - itShouldBeEmpty(store.getTriples('s2', 'p2', 'o1')); + itShouldBeEmpty(store.getTriples(new NamedNode('s2'), new NamedNode('p2'), new NamedNode('o1'))); }); describe('when searched with the default graph parameter', function () { it('should return all items in the default graph', - shouldIncludeAll(store.getTriples(null, null, null, ''), + shouldIncludeAll(store.getTriples(null, null, null, new DefaultGraph()), ['s1', 'p1', 'o1'], ['s1', 'p1', 'o2'], ['s1', 'p2', 'o2'], @@ -256,60 +263,60 @@ describe('N3Store', function () { describe('when searched with an existing named graph parameter', function () { it('should return all items in that graph', - shouldIncludeAll(store.getTriples(null, null, null, 'c4'), + shouldIncludeAll(store.getTriples(null, null, null, new NamedNode('c4')), ['s1', 'p1', 'o1', 'c4'])); }); describe('when searched with a non-existing named graph parameter', function () { - itShouldBeEmpty(store.getTriples(null, null, null, 'c5')); + itShouldBeEmpty(store.getTriples(null, null, null, new NamedNode('c5'))); }); describe('getSubjects', function () { describe('with existing predicate, object and graph parameters', function () { it('should return all subjects with this predicate, object and graph', function () { - store.getSubjects('p1', 'o1', 'c4').should.have.members(['s1']); + store.getSubjects(new NamedNode('p1'), new NamedNode('o1'), new NamedNode('c4')).should.have.deep.members([new NamedNode('s1')]); }); }); describe('with existing predicate and object parameters', function () { it('should return all subjects with this predicate and object', function () { - store.getSubjects('p2', 'o2', null).should.have.members(['s1']); + store.getSubjects(new NamedNode('p2'), new NamedNode('o2'), null).should.have.deep.members([new NamedNode('s1')]); }); }); describe('with existing predicate and graph parameters', function () { it('should return all subjects with this predicate and graph', function () { - store.getSubjects('p1', null, '').should.have.members(['s1', 's2']); + store.getSubjects(new NamedNode('p1'), null, new DefaultGraph()).should.have.deep.members([new NamedNode('s1'), new NamedNode('s2')]); }); }); describe('with existing object and graph parameters', function () { it('should return all subjects with this object and graph', function () { - store.getSubjects(null, 'o1', '').should.have.members(['s1', 's2']); + store.getSubjects(null, new NamedNode('o1'), new DefaultGraph()).should.have.deep.members([new NamedNode('s1'), new NamedNode('s2')]); }); }); describe('with an existing predicate parameter', function () { it('should return all subjects with this predicate', function () { - store.getSubjects('p1', null, null).should.have.members(['s1', 's2']); + store.getSubjects(new NamedNode('p1'), null, null).should.have.deep.members([new NamedNode('s1'), new NamedNode('s2')]); }); }); describe('with an existing object parameter', function () { it('should return all subjects with this object', function () { - store.getSubjects(null, 'o1', null).should.have.members(['s1', 's2']); + store.getSubjects(null, new NamedNode('o1'), null).should.have.deep.members([new NamedNode('s1'), new NamedNode('s2')]); }); }); describe('with an existing graph parameter', function () { it('should return all subjects in the graph', function () { - store.getSubjects(null, null, 'c4').should.have.members(['s1']); + store.getSubjects(null, null, new NamedNode('c4')).should.have.deep.members([new NamedNode('s1')]); }); }); describe('with no parameters', function () { it('should return all subjects', function () { - store.getSubjects(null, null, null).should.have.members(['s1', 's2']); + store.getSubjects(null, null, null).should.have.deep.members([new NamedNode('s1'), new NamedNode('s2')]); }); }); }); @@ -317,49 +324,49 @@ describe('N3Store', function () { describe('getPredicates', function () { describe('with existing subject, object and graph parameters', function () { it('should return all predicates with this subject, object and graph', function () { - store.getPredicates('s1', 'o1', 'c4').should.have.members(['p1']); + store.getPredicates(new NamedNode('s1'), new NamedNode('o1'), new NamedNode('c4')).should.have.deep.members([new NamedNode('p1')]); }); }); describe('with existing subject and object parameters', function () { it('should return all predicates with this subject and object', function () { - store.getPredicates('s1', 'o2', null).should.have.members(['p1', 'p2']); + store.getPredicates(new NamedNode('s1'), new NamedNode('o2'), null).should.have.deep.members([new NamedNode('p1'), new NamedNode('p2')]); }); }); describe('with existing subject and graph parameters', function () { it('should return all predicates with this subject and graph', function () { - store.getPredicates('s1', null, '').should.have.members(['p1', 'p2']); + store.getPredicates(new NamedNode('s1'), null, new DefaultGraph()).should.have.deep.members([new NamedNode('p1'), new NamedNode('p2')]); }); }); describe('with existing object and graph parameters', function () { it('should return all predicates with this object and graph', function () { - store.getPredicates(null, 'o1', '').should.have.members(['p1']); + store.getPredicates(null, new NamedNode('o1'), new DefaultGraph()).should.have.deep.members([new NamedNode('p1')]); }); }); describe('with an existing subject parameter', function () { it('should return all predicates with this subject', function () { - store.getPredicates('s2', null, null).should.have.members(['p1']); + store.getPredicates(new NamedNode('s2'), null, null).should.have.deep.members([new NamedNode('p1')]); }); }); describe('with an existing object parameter', function () { it('should return all predicates with this object', function () { - store.getPredicates(null, 'o1', null).should.have.members(['p1']); + store.getPredicates(null, new NamedNode('o1'), null).should.have.deep.members([new NamedNode('p1')]); }); }); describe('with an existing graph parameter', function () { it('should return all predicates in the graph', function () { - store.getPredicates(null, null, 'c4').should.have.members(['p1']); + store.getPredicates(null, null, new NamedNode('c4')).should.have.deep.members([new NamedNode('p1')]); }); }); describe('with no parameters', function () { it('should return all predicates', function () { - store.getPredicates(null, null, null).should.have.members(['p1', 'p2']); + store.getPredicates(null, null, null).should.have.deep.members([new NamedNode('p1'), new NamedNode('p2')]); }); }); }); @@ -367,49 +374,49 @@ describe('N3Store', function () { describe('getObjects', function () { describe('with existing subject, predicate and graph parameters', function () { it('should return all objects with this subject, predicate and graph', function () { - store.getObjects('s1', 'p1', '').should.have.members(['o1', 'o2']); + store.getObjects(new NamedNode('s1'), new NamedNode('p1'), new DefaultGraph()).should.have.deep.members([new NamedNode('o1'), new NamedNode('o2')]); }); }); describe('with existing subject and predicate parameters', function () { it('should return all objects with this subject and predicate', function () { - store.getObjects('s1', 'p1', null).should.have.members(['o1', 'o2']); + store.getObjects(new NamedNode('s1'), new NamedNode('p1'), null).should.have.deep.members([new NamedNode('o1'), new NamedNode('o2')]); }); }); describe('with existing subject and graph parameters', function () { it('should return all objects with this subject and graph', function () { - store.getObjects('s1', null, '').should.have.members(['o1', 'o2']); + store.getObjects(new NamedNode('s1'), null, new DefaultGraph()).should.have.deep.members([new NamedNode('o1'), new NamedNode('o2')]); }); }); describe('with existing predicate and graph parameters', function () { it('should return all objects with this predicate and graph', function () { - store.getObjects(null, 'p1', '').should.have.members(['o1', 'o2']); + store.getObjects(null, new NamedNode('p1'), new DefaultGraph()).should.have.deep.members([new NamedNode('o1'), new NamedNode('o2')]); }); }); describe('with an existing subject parameter', function () { it('should return all objects with this subject', function () { - store.getObjects('s1', null, null).should.have.members(['o1', 'o2']); + store.getObjects(new NamedNode('s1'), null, null).should.have.deep.members([new NamedNode('o1'), new NamedNode('o2')]); }); }); describe('with an existing predicate parameter', function () { it('should return all objects with this predicate', function () { - store.getObjects(null, 'p1', null).should.have.members(['o1', 'o2']); + store.getObjects(null, new NamedNode('p1'), null).should.have.deep.members([new NamedNode('o1'), new NamedNode('o2')]); }); }); describe('with an existing graph parameter', function () { it('should return all objects in the graph', function () { - store.getObjects(null, null, 'c4').should.have.members(['o1']); + store.getObjects(null, null, new NamedNode('c4')).should.have.deep.members([new NamedNode('o1')]); }); }); describe('with no parameters', function () { it('should return all objects', function () { - store.getObjects(null, null, null).should.have.members(['o1', 'o2']); + store.getObjects(null, null, null).should.have.deep.members([new NamedNode('o1'), new NamedNode('o2')]); }); }); }); @@ -417,49 +424,49 @@ describe('N3Store', function () { describe('getGraphs', function () { describe('with existing subject, predicate and object parameters', function () { it('should return all graphs with this subject, predicate and object', function () { - store.getGraphs('s1', 'p1', 'o1').should.have.members(['c4', '']); + store.getGraphs(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o1')).should.have.deep.members([new NamedNode('c4'), new DefaultGraph()]); }); }); describe('with existing subject and predicate parameters', function () { it('should return all graphs with this subject and predicate', function () { - store.getGraphs('s1', 'p1', null).should.have.members(['c4', '']); + store.getGraphs(new NamedNode('s1'), new NamedNode('p1'), null).should.have.deep.members([new NamedNode('c4'), new DefaultGraph()]); }); }); describe('with existing subject and object parameters', function () { it('should return all graphs with this subject and object', function () { - store.getGraphs('s1', null, 'o2').should.have.members(['']); + store.getGraphs(new NamedNode('s1'), null, new NamedNode('o2')).should.have.deep.members([new DefaultGraph()]); }); }); describe('with existing predicate and object parameters', function () { it('should return all graphs with this predicate and object', function () { - store.getGraphs(null, 'p1', 'o1').should.have.members(['', 'c4']); + store.getGraphs(null, new NamedNode('p1'), new NamedNode('o1')).should.have.deep.members([new DefaultGraph(), new NamedNode('c4')]); }); }); describe('with an existing subject parameter', function () { it('should return all graphs with this subject', function () { - store.getGraphs('s1', null, null).should.have.members(['c4', '']); + store.getGraphs(new NamedNode('s1'), null, null).should.have.deep.members([new NamedNode('c4'), new DefaultGraph()]); }); }); describe('with an existing predicate parameter', function () { it('should return all graphs with this predicate', function () { - store.getGraphs(null, 'p1', null).should.have.members(['c4', '']); + store.getGraphs(null, new NamedNode('p1'), null).should.have.deep.members([new NamedNode('c4'), new DefaultGraph()]); }); }); describe('with an existing object parameter', function () { it('should return all graphs with this object', function () { - store.getGraphs(null, null, 'o2').should.have.members(['']); + store.getGraphs(null, null, new NamedNode('o2')).should.have.deep.members([new DefaultGraph()]); }); }); describe('with no parameters', function () { it('should return all graphs', function () { - store.getGraphs(null, null, null).should.have.members(['c4', '']); + store.getGraphs(null, null, null).should.have.deep.members([new NamedNode('c4'), new DefaultGraph()]); }); }); }); @@ -588,7 +595,7 @@ describe('N3Store', function () { describe('forSubjects', function () { describe('with existing predicate, object and graph parameters', function () { it('should iterate all subjects with this predicate, object and graph', function () { - collect(store, 'forSubjects', 'p1', 'o1', '').should.have.members(['s1', 's2']); + collect(store, 'forSubjects', 'p1', 'o1', '').should.have.deep.members([new NamedNode('s1'), new NamedNode('s2')]); }); }); describe('with a non-existing predicate', function () { @@ -611,7 +618,7 @@ describe('N3Store', function () { describe('forPredicates', function () { describe('with existing subject, object and graph parameters', function () { it('should iterate all predicates with this subject, object and graph', function () { - collect(store, 'forPredicates', 's1', 'o2', '').should.have.members(['p1', 'p2']); + collect(store, 'forPredicates', 's1', 'o2', '').should.have.deep.members([new NamedNode('p1'), new NamedNode('p2')]); }); }); describe('with a non-existing subject', function () { @@ -634,7 +641,7 @@ describe('N3Store', function () { describe('forObjects', function () { describe('with existing subject, predicate and graph parameters', function () { it('should iterate all objects with this subject, predicate and graph', function () { - collect(store, 'forObjects', 's1', 'p1', '').should.have.members(['o1', 'o2']); + collect(store, 'forObjects', 's1', 'p1', '').should.have.deep.members([new NamedNode('o1'), new NamedNode('o2')]); }); }); describe('with a non-existing subject', function () { @@ -657,7 +664,7 @@ describe('N3Store', function () { describe('forGraphs', function () { describe('with existing subject, predicate and object parameters', function () { it('should iterate all graphs with this subject, predicate and object', function () { - collect(store, 'forGraphs', 's1', 'p1', 'o1').should.have.members(['', 'c4']); + collect(store, 'forGraphs', 's1', 'p1', 'o1').should.have.deep.members([new DefaultGraph(), new NamedNode('c4')]); }); }); describe('with a non-existing subject', function () { @@ -698,6 +705,27 @@ describe('N3Store', function () { }); }); + describe('everyByIRI', function () { + var count = 3; + function thirdTimeFalse() { return count-- === 0; } + + describe('with no parameters and a callback always returning true', function () { + it('should return true', function () { + store.everyByIRI(alwaysTrue, null, null, null, null).should.be.true; + }); + }); + describe('with no parameters and a callback always returning false', function () { + it('should return false', function () { + store.everyByIRI(alwaysFalse, null, null, null, null).should.be.false; + }); + }); + describe('with no parameters and a callback that returns false after 3 calls', function () { + it('should return false', function () { + store.everyByIRI(thirdTimeFalse, null, null, null, null).should.be.false; + }); + }); + }); + describe('some', function () { var count = 3; function thirdTimeFalse() { return count-- !== 0; } @@ -739,6 +767,47 @@ describe('N3Store', function () { }); }); + describe('someByIRI', function () { + var count = 3; + function thirdTimeFalse() { return count-- !== 0; } + + describe('with no parameters and a callback always returning true', function () { + it('should return true', function () { + store.someByIRI(alwaysTrue, null, null, null, null).should.be.true; + }); + }); + describe('with no parameters and a callback always returning false', function () { + it('should return false', function () { + store.someByIRI(alwaysFalse, null, null, null, null).should.be.false; + }); + }); + describe('with no parameters and a callback that returns true after 3 calls', function () { + it('should return false', function () { + store.someByIRI(thirdTimeFalse, null, null, null, null).should.be.true; + }); + }); + describe('with a non-existing subject', function () { + it('should return true', function () { + store.someByIRI(null, new NamedNode('s3'), null, null, null).should.be.false; + }); + }); + describe('with a non-existing predicate', function () { + it('should return false', function () { + store.someByIRI(null, null, new NamedNode('p3'), null, null).should.be.false; + }); + }); + describe('with a non-existing object', function () { + it('should return false', function () { + store.someByIRI(null, null, null, new NamedNode('o4'), null).should.be.false; + }); + }); + describe('with a non-existing graph', function () { + it('should return false', function () { + store.someByIRI(null, null, null, null, new NamedNode('g2')).should.be.false; + }); + }); + }); + describe('when counted without parameters', function () { it('should count all items in all graphs', function () { store.countTriplesByIRI().should.equal(5); @@ -747,31 +816,31 @@ describe('N3Store', function () { describe('when counted with an existing subject parameter', function () { it('should count all items with this subject in all graphs', function () { - store.countTriplesByIRI('s1', null, null).should.equal(4); + store.countTriplesByIRI(new NamedNode('s1'), null, null).should.equal(4); }); }); describe('when counted with a non-existing subject parameter', function () { it('should be empty', function () { - store.countTriplesByIRI('s3', null, null).should.equal(0); + store.countTriplesByIRI(new NamedNode('s3'), null, null).should.equal(0); }); }); describe('when counted with a non-existing subject parameter that exists elsewhere', function () { it('should be empty', function () { - store.countTriplesByIRI('p1', null, null).should.equal(0); + store.countTriplesByIRI(new NamedNode('p1'), null, null).should.equal(0); }); }); describe('when counted with an existing predicate parameter', function () { it('should count all items with this predicate in all graphs', function () { - store.countTriplesByIRI(null, 'p1', null).should.equal(4); + store.countTriplesByIRI(null, new NamedNode('p1'), null).should.equal(4); }); }); describe('when counted with a non-existing predicate parameter', function () { it('should be empty', function () { - store.countTriplesByIRI(null, 'p3', null).should.equal(0); + store.countTriplesByIRI(null, new NamedNode('p3'), null).should.equal(0); }); }); @@ -837,7 +906,7 @@ describe('N3Store', function () { describe('when counted with the default graph parameter', function () { it('should count all items in the default graph', function () { - store.countTriples(null, null, null, '').should.equal(4); + store.countTriples(null, null, null, new DefaultGraph()).should.equal(4); }); }); @@ -854,52 +923,52 @@ describe('N3Store', function () { }); describe('when trying to remove a triple with a non-existing subject', function () { - before(function () { store.removeTriple('s0', 'p1', 'o1').should.be.false; }); + before(function () { store.removeTriple(new NamedNode('s0'), new NamedNode('p1'), new NamedNode('o1')).should.be.false; }); it('should still have size 5', function () { store.size.should.eql(5); }); }); describe('when trying to remove a triple with a non-existing predicate', function () { - before(function () { store.removeTriple('s1', 'p0', 'o1').should.be.false; }); + before(function () { store.removeTriple(new NamedNode('s1'), new NamedNode('p0'), new NamedNode('o1')).should.be.false; }); it('should still have size 5', function () { store.size.should.eql(5); }); }); describe('when trying to remove a triple with a non-existing object', function () { - before(function () { store.removeTriple('s1', 'p1', 'o0').should.be.false; }); + before(function () { store.removeTriple(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o0')).should.be.false; }); it('should still have size 5', function () { store.size.should.eql(5); }); }); describe('when trying to remove a triple for which no subjects exist', function () { - before(function () { store.removeTriple('o1', 'p1', 'o1').should.be.false; }); + before(function () { store.removeTriple(new NamedNode('o1'), new NamedNode('p1'), new NamedNode('o1')).should.be.false; }); it('should still have size 5', function () { store.size.should.eql(5); }); }); describe('when trying to remove a triple for which no predicates exist', function () { - before(function () { store.removeTriple('s1', 's1', 'o1').should.be.false; }); + before(function () { store.removeTriple(new NamedNode('s1'), new NamedNode('s1'), new NamedNode('o1')).should.be.false; }); it('should still have size 5', function () { store.size.should.eql(5); }); }); describe('when trying to remove a triple for which no objects exist', function () { - before(function () { store.removeTriple('s1', 'p1', 's1').should.be.false; }); + before(function () { store.removeTriple(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('s1')).should.be.false; }); it('should still have size 5', function () { store.size.should.eql(5); }); }); describe('when trying to remove a triple that does not exist', function () { - before(function () { store.removeTriple('s1', 'p2', 'o1').should.be.false; }); + before(function () { store.removeTriple(new NamedNode('s1'), new NamedNode('p2'), new NamedNode('o1')).should.be.false; }); it('should still have size 5', function () { store.size.should.eql(5); }); }); describe('when trying to remove an incomplete triple', function () { - before(function () { store.removeTriple('s1', null, null).should.be.false; }); + before(function () { store.removeTriple(new NamedNode('s1'), null, null).should.be.false; }); it('should still have size 5', function () { store.size.should.eql(5); }); }); describe('when trying to remove a triple with a non-existing graph', function () { - before(function () { store.removeTriple('s1', 'p1', 'o1', 'c0').should.be.false; }); + before(function () { store.removeTriple(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o1'), new NamedNode('c0')).should.be.false; }); it('should still have size 5', function () { store.size.should.eql(5); }); }); describe('when removing an existing triple', function () { - before(function () { store.removeTriple('s1', 'p1', 'o1').should.be.true; }); + before(function () { store.removeTriple(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o1')).should.be.true; }); it('should have size 4', function () { store.size.should.eql(4); }); @@ -912,7 +981,7 @@ describe('N3Store', function () { }); describe('when removing an existing triple from a named graph', function () { - before(function () { store.removeTriple('s1', 'p1', 'o1', 'c4').should.be.true; }); + before(function () { store.removeTriple(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o1'), new NamedNode('c4')).should.be.true; }); it('should have size 3', function () { store.size.should.eql(3); }); @@ -922,8 +991,8 @@ describe('N3Store', function () { describe('when removing multiple triples', function () { before(function () { store.removeTriples([ - { subject: 's1', predicate: 'p2', object: 'o2' }, - { subject: 's2', predicate: 'p1', object: 'o1' }, + new Triple(new NamedNode('s1'), new NamedNode('p2'), new NamedNode('o2')), + new Triple(new NamedNode('s2'), new NamedNode('p1'), new NamedNode('o1')), ]); }); @@ -936,8 +1005,8 @@ describe('N3Store', function () { describe('when adding and removing a triple', function () { before(function () { - store.addTriple('a', 'b', 'c').should.be.true; - store.removeTriple('a', 'b', 'c').should.be.true; + store.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')).should.be.true; + store.removeTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')).should.be.true; }); it('should have an unchanged size', function () { store.size.should.eql(1); }); @@ -946,11 +1015,11 @@ describe('N3Store', function () { describe('An N3Store initialized with prefixes', function () { var store = new N3Store([ - { subject: 'http://foo.org/#s1', predicate: 'http://bar.org/p1', object: 'http://foo.org/#o1' }, - { subject: 'http://foo.org/#s1', predicate: 'http://bar.org/p2', object: 'http://foo.org/#o1' }, - { subject: 'http://foo.org/#s2', predicate: 'http://bar.org/p1', object: 'http://foo.org/#o2' }, - { subject: 'http://foo.org/#s3', predicate: 'http://bar.org/p3', object: '"a"^^http://foo.org/#t1' }, - { subject: 'http://foo.org/#s1', predicate: 'http://bar.org/p1', object: 'http://foo.org/#o1', graph: 'http://graphs.org/#g1' }, + new Triple(new NamedNode('http://foo.org/#s1'), new NamedNode('http://bar.org/p1'), new NamedNode('http://foo.org/#o1')), + new Triple(new NamedNode('http://foo.org/#s1'), new NamedNode('http://bar.org/p2'), new NamedNode('http://foo.org/#o1')), + new Triple(new NamedNode('http://foo.org/#s2'), new NamedNode('http://bar.org/p1'), new NamedNode('http://foo.org/#o2')), + new Triple(new NamedNode('http://foo.org/#s3'), new NamedNode('http://bar.org/p3'), new Literal('"a"^^http://foo.org/#t1')), + new Triple(new NamedNode('http://foo.org/#s1'), new NamedNode('http://bar.org/p1'), new NamedNode('http://foo.org/#o1'), new NamedNode('http://graphs.org/#g1')), ], { prefixes: { a: 'http://foo.org/#', b: 'http://bar.org/', g: 'http://graphs.org/#' } }); @@ -964,7 +1033,7 @@ describe('N3Store', function () { describe('should allow to query subjects with prefixes', function () { it('should return all triples with that subject in the default graph', - shouldIncludeAll(store.getTriples('a:s1', null, null, ''), + shouldIncludeAll(store.getTriples('a:s1', null, null, new DefaultGraph()), ['http://foo.org/#s1', 'http://bar.org/p1', 'http://foo.org/#o1'], ['http://foo.org/#s1', 'http://bar.org/p2', 'http://foo.org/#o1'])); }); @@ -994,10 +1063,10 @@ describe('N3Store', function () { describe('An N3Store with prefixes added later on', function () { var store = new N3Store([ - { subject: 'http://foo.org/#s1', predicate: 'http://bar.org/p1', object: 'http://foo.org/#o1' }, - { subject: 'http://foo.org/#s1', predicate: 'http://bar.org/p2', object: 'http://foo.org/#o1' }, - { subject: 'http://foo.org/#s2', predicate: 'http://bar.org/p1', object: 'http://foo.org/#o2' }, - { subject: 'http://foo.org/#s1', predicate: 'http://bar.org/p1', object: 'http://foo.org/#o1', graph: 'http://graphs.org/#g1' }, + new Triple(new NamedNode('http://foo.org/#s1'), new NamedNode('http://bar.org/p1'), new NamedNode('http://foo.org/#o1')), + new Triple(new NamedNode('http://foo.org/#s1'), new NamedNode('http://bar.org/p2'), new NamedNode('http://foo.org/#o1')), + new Triple(new NamedNode('http://foo.org/#s2'), new NamedNode('http://bar.org/p1'), new NamedNode('http://foo.org/#o2')), + new Triple(new NamedNode('http://foo.org/#s1'), new NamedNode('http://bar.org/p1'), new NamedNode('http://foo.org/#o1'), new NamedNode('http://graphs.org/#g1')), ]); store.addPrefix('a', 'http://foo.org/#'); @@ -1005,7 +1074,7 @@ describe('N3Store', function () { describe('should allow to query subjects with prefixes', function () { it('should return all triples with that subject in the default graph', - shouldIncludeAll(store.getTriples('a:s1', null, null, ''), + shouldIncludeAll(store.getTriples('a:s1', null, null, new DefaultGraph()), ['http://foo.org/#s1', 'http://bar.org/p1', 'http://foo.org/#o1'], ['http://foo.org/#s1', 'http://bar.org/p2', 'http://foo.org/#o1'])); }); @@ -1020,7 +1089,7 @@ describe('N3Store', function () { describe('should allow to query predicates with prefixes', function () { it('should return all triples with that predicate in the default graph', - shouldIncludeAll(store.getTriples(null, 'b:p1', null, ''), + shouldIncludeAll(store.getTriples(null, 'b:p1', null, new DefaultGraph()), ['http://foo.org/#s1', 'http://bar.org/p1', 'http://foo.org/#o1'], ['http://foo.org/#s2', 'http://bar.org/p1', 'http://foo.org/#o2'])); }); @@ -1035,7 +1104,7 @@ describe('N3Store', function () { describe('should allow to query objects with prefixes', function () { it('should return all triples with that object in the default graph', - shouldIncludeAll(store.getTriples(null, null, 'a:o1', ''), + shouldIncludeAll(store.getTriples(null, null, 'a:o1', new DefaultGraph()), ['http://foo.org/#s1', 'http://bar.org/p1', 'http://foo.org/#o1'], ['http://foo.org/#s1', 'http://bar.org/p2', 'http://foo.org/#o1'])); }); @@ -1057,9 +1126,9 @@ describe('N3Store', function () { describe('An N3Store with the http prefix', function () { var store = new N3Store([ - { subject: 'http://foo.org/#s1', predicate: 'http://bar.org/p1', object: 'http://foo.org/#o1' }, - { subject: 'http://foo.org/#s1', predicate: 'http://bar.org/p2', object: 'http://foo.org/#o1' }, - { subject: 'http://foo.org/#s2', predicate: 'http://bar.org/p1', object: 'http://foo.org/#o2' }, + new Triple(new NamedNode('http://foo.org/#s1'), new NamedNode('http://bar.org/p1'), new NamedNode('http://foo.org/#o1')), + new Triple(new NamedNode('http://foo.org/#s1'), new NamedNode('http://bar.org/p2'), new NamedNode('http://foo.org/#o1')), + new Triple(new NamedNode('http://foo.org/#s2'), new NamedNode('http://bar.org/p1'), new NamedNode('http://foo.org/#o2')), ], { prefixes: { http: 'http://www.w3.org/2006/http#' } }); @@ -1085,18 +1154,18 @@ describe('N3Store', function () { describe('An N3Store containing a blank node', function () { var store = new N3Store(); var b1 = store.createBlankNode(); - store.addTriple('s1', 'p1', b1).should.be.true; + store.addTriple(new NamedNode('s1'), new NamedNode('p1'), b1).should.be.true; describe('when searched with more than one variable', function () { it('should return a triple with the blank node as an object', shouldIncludeAll(store.getTriples(), - ['s1', 'p1', b1])); + ['s1', 'p1', '_:' + b1.value])); }); describe('when searched with one variable', function () { it('should return a triple with the blank node as an object', shouldIncludeAll(store.getTriples('s1', 'p1'), - ['s1', 'p1', b1])); + ['s1', 'p1', '_:' + b1.value])); }); }); @@ -1123,7 +1192,7 @@ function alwaysFalse() { return false; } function collect(store, method, arg1, arg2, arg3, arg4) { var results = []; - store[method](function (r) { results.push(r); }, arg1, arg2, arg3, arg4); + store[method](function (r) { results.push(r); }, arg1 && Term.fromId(arg1), arg2 && Term.fromId(arg2), arg3 && Term.fromId(arg3), arg4 && Term.fromId(arg4)); return results; } @@ -1136,12 +1205,13 @@ function itShouldBeEmpty(result) { function shouldIncludeAll(result) { var items = Array.prototype.slice.call(arguments, 1).map(function (arg) { - return { subject: arg[0], predicate: arg[1], object: arg[2], graph: arg[3] || '' }; + return new Quad(Term.fromId(arg[0]), Term.fromId(arg[1]), Term.fromId(arg[2]), Term.fromId(arg[3] || '')); }); return function () { if (typeof result === 'function') result = result(); + result = result.map(function (r) { return r.toJSON(); }); result.should.have.length(items.length); for (var i = 0; i < items.length; i++) - result.should.include.something.that.deep.equals(items[i]); + result.should.include.something.that.deep.equals(items[i].toJSON()); }; } From 6ff43960b77a86c5efa512e5f6d343010036a993 Mon Sep 17 00:00:00 2001 From: Ruben Taelman Date: Wed, 18 Oct 2017 15:05:56 +0900 Subject: [PATCH 19/34] Migrate util to RDF/JS interface --- lib/Datatypes.js | 2 +- lib/N3Util.js | 65 +++++++++----------- test/N3Util-test.js | 142 +++++++++++++++++++++++--------------------- 3 files changed, 104 insertions(+), 105 deletions(-) diff --git a/lib/Datatypes.js b/lib/Datatypes.js index b06d9720..5cf5c9de 100644 --- a/lib/Datatypes.js +++ b/lib/Datatypes.js @@ -141,7 +141,7 @@ Object.defineProperty(Literal.prototype, 'language', { // Find the last quotation mark (e.g., '"abc"@en-us') var id = this.id, atPos = id.lastIndexOf('"') + 1; // If "@" it follows, return the remaining substring; empty otherwise - return atPos < id.length && id[atPos++] === '@' ? id.substr(atPos) : ''; + return atPos < id.length && id[atPos++] === '@' ? id.substr(atPos).toLowerCase() : ''; }, }); diff --git a/lib/N3Util.js b/lib/N3Util.js index 5d47adec..91a88b84 100644 --- a/lib/N3Util.js +++ b/lib/N3Util.js @@ -1,67 +1,60 @@ // **N3Util** provides N3 utility functions. var Xsd = 'http://www.w3.org/2001/XMLSchema#'; -var XsdString = Xsd + 'string'; var XsdInteger = Xsd + 'integer'; var XsdDouble = Xsd + 'double'; var XsdBoolean = Xsd + 'boolean'; -var RdfLangString = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString'; + +var Datatype = require('./Datatypes'); +var Term = Datatype.Term, + NamedNode = Datatype.NamedNode, + Literal = Datatype.Literal; var N3Util = { - // Tests whether the given entity (triple object) represents an IRI in the N3 library + // Tests whether the given entity (triple object) represents an IRI isIRI: function (entity) { - if (typeof entity !== 'string') - return false; - else if (entity.length === 0) - return true; - else { - var firstChar = entity[0]; - return firstChar !== '"' && firstChar !== '_'; - } + return !!entity && entity.termType === 'NamedNode'; }, - // Tests whether the given entity (triple object) represents a literal in the N3 library + // Tests whether the given entity (triple object) represents a literal isLiteral: function (entity) { - return typeof entity === 'string' && entity[0] === '"'; + return !!entity && entity.termType === 'Literal'; }, - // Tests whether the given entity (triple object) represents a blank node in the N3 library + // Tests whether the given entity (triple object) represents a blank node isBlank: function (entity) { - return typeof entity === 'string' && entity.substr(0, 2) === '_:'; + return !!entity && entity.termType === 'BlankNode'; }, // Tests whether the given entity represents the default graph isDefaultGraph: function (entity) { - return !entity; + return !entity || entity.termType === 'DefaultGraph'; }, // Tests whether the given triple is in the default graph inDefaultGraph: function (triple) { - return !triple.graph; + return N3Util.isDefaultGraph(triple.graph); }, // Gets the string value of a literal in the N3 library getLiteralValue: function (literal) { - var match = /^"([^]*)"/.exec(literal); - if (!match) - throw new Error(literal + ' is not a literal'); - return match[1]; + if (!N3Util.isLiteral(literal)) + throw new Error((literal && literal.value ? literal.value : literal) + ' is not a literal.'); + return literal.value; }, // Gets the type of a literal in the N3 library getLiteralType: function (literal) { - var match = /^"[^]*"(?:\^\^([^"]+)|(@)[^@"]+)?$/.exec(literal); - if (!match) - throw new Error(literal + ' is not a literal'); - return match[1] || (match[2] ? RdfLangString : XsdString); + if (!N3Util.isLiteral(literal)) + throw new Error((literal && literal.value ? literal.value : literal) + ' is not a literal.'); + return literal.datatype; }, // Gets the language of a literal in the N3 library getLiteralLanguage: function (literal) { - var match = /^"[^]*"(?:@([^@"]+)|\^\^[^"]+)?$/.exec(literal); - if (!match) - throw new Error(literal + ' is not a literal'); - return match[1] ? match[1].toLowerCase() : ''; + if (!N3Util.isLiteral(literal)) + throw new Error((literal && literal.value ? literal.value : literal) + ' is not a literal.'); + return literal.language; }, // Tests whether the given entity (triple object) represents a prefixed name @@ -78,14 +71,14 @@ var N3Util = { return prefixedName; // The match index is non-zero when expanding a literal's type - return index === 0 ? base + prefixedName.substr(prefix.length + 1) - : prefixedName.substr(0, index + 3) + - base + prefixedName.substr(index + prefix.length + 4); + return Term.fromId(index === 0 ? base + prefixedName.substr(prefix.length + 1) + : prefixedName.substr(0, index + 3) + + base + prefixedName.substr(index + prefix.length + 4)); }, // Creates an IRI in N3.js representation createIRI: function (iri) { - return iri && iri[0] === '"' ? N3Util.getLiteralValue(iri) : iri; + return iri && new NamedNode(iri[0] === '"' ? Term.fromId(iri).value : iri); }, // Creates a literal in N3.js representation @@ -105,12 +98,12 @@ var N3Util = { } break; default: - return '"' + value + '"'; + return new Literal('"' + value + '"'); } } - return '"' + value + + return new Literal('"' + value + (/^[a-z]+(-[a-z0-9]+)*$/i.test(modifier) ? '"@' + modifier.toLowerCase() - : '"^^' + modifier); + : '"^^' + modifier)); }, // Creates a function that prepends the given IRI to a local name diff --git a/test/N3Util-test.js b/test/N3Util-test.js index 82570c9f..dc28b11b 100644 --- a/test/N3Util-test.js +++ b/test/N3Util-test.js @@ -1,21 +1,27 @@ -var N3Util = require('../N3').Util; +var N3Util = require('../N3').Util, + Datatype = require('../lib/Datatypes'); +var NamedNode = Datatype.NamedNode, + Literal = Datatype.Literal, + BlankNode = Datatype.BlankNode, + DefaultGraph = Datatype.DefaultGraph, + Quad = Datatype.Quad; describe('N3Util', function () { describe('isIRI', function () { it('matches an IRI', function () { - N3Util.isIRI('http://example.org/').should.be.true; + N3Util.isIRI(new NamedNode('http://example.org/')).should.be.true; }); it('matches an empty IRI', function () { - N3Util.isIRI('').should.be.true; + N3Util.isIRI(new NamedNode('')).should.be.true; }); it('does not match a literal', function () { - N3Util.isIRI('"http://example.org/"').should.be.false; + N3Util.isIRI(new Literal('"http://example.org/"')).should.be.false; }); it('does not match a blank node', function () { - N3Util.isIRI('_:x').should.be.false; + N3Util.isIRI(new BlankNode('x')).should.be.false; }); it('does not match null', function () { @@ -29,35 +35,35 @@ describe('N3Util', function () { describe('isLiteral', function () { it('matches a literal', function () { - N3Util.isLiteral('"http://example.org/"').should.be.true; + N3Util.isLiteral(new Literal('"http://example.org/"')).should.be.true; }); it('matches a literal with a language', function () { - N3Util.isLiteral('"English"@en').should.be.true; + N3Util.isLiteral(new Literal('"English"@en')).should.be.true; }); it('matches a literal with a language that contains a number', function () { - N3Util.isLiteral('"English"@es-419').should.be.true; + N3Util.isLiteral(new Literal('"English"@es-419')).should.be.true; }); it('matches a literal with a type', function () { - N3Util.isLiteral('"3"^^http://www.w3.org/2001/XMLSchema#integer').should.be.true; + N3Util.isLiteral(new Literal('"3"^^http://www.w3.org/2001/XMLSchema#integer')).should.be.true; }); it('matches a literal with a newline', function () { - N3Util.isLiteral('"a\nb"').should.be.true; + N3Util.isLiteral(new Literal('"a\nb"')).should.be.true; }); it('matches a literal with a cariage return', function () { - N3Util.isLiteral('"a\rb"').should.be.true; + N3Util.isLiteral(new Literal('"a\rb"')).should.be.true; }); it('does not match an IRI', function () { - N3Util.isLiteral('http://example.org/').should.be.false; + N3Util.isLiteral(new NamedNode('http://example.org/')).should.be.false; }); it('does not match a blank node', function () { - N3Util.isLiteral('_:x').should.be.false; + N3Util.isLiteral(new BlankNode('_:x')).should.be.false; }); it('does not match null', function () { @@ -71,15 +77,15 @@ describe('N3Util', function () { describe('isBlank', function () { it('matches a blank node', function () { - N3Util.isBlank('_:x').should.be.true; + N3Util.isBlank(new BlankNode('x')).should.be.true; }); it('does not match an IRI', function () { - N3Util.isBlank('http://example.org/').should.be.false; + N3Util.isBlank(new NamedNode('http://example.org/')).should.be.false; }); it('does not match a literal', function () { - N3Util.isBlank('"http://example.org/"').should.be.false; + N3Util.isBlank(new Literal('"http://example.org/"')).should.be.false; }); it('does not match null', function () { @@ -93,15 +99,15 @@ describe('N3Util', function () { describe('isDefaultGraph', function () { it('does not match a blank node', function () { - N3Util.isDefaultGraph('_:x').should.be.false; + N3Util.isDefaultGraph(new BlankNode('x')).should.be.false; }); it('does not match an IRI', function () { - N3Util.isDefaultGraph('http://example.org/').should.be.false; + N3Util.isDefaultGraph(new NamedNode('http://example.org/')).should.be.false; }); it('does not match a literal', function () { - N3Util.isDefaultGraph('"http://example.org/"').should.be.false; + N3Util.isDefaultGraph(new Literal('"http://example.org/"')).should.be.false; }); it('matches null', function () { @@ -119,57 +125,57 @@ describe('N3Util', function () { describe('inDefaultGraph', function () { it('does not match a blank node', function () { - N3Util.inDefaultGraph({ graph: '_:x' }).should.be.false; + N3Util.inDefaultGraph(new Quad(null, null, null, new BlankNode('x'))).should.be.false; }); it('does not match an IRI', function () { - N3Util.inDefaultGraph({ graph: 'http://example.org/' }).should.be.false; + N3Util.inDefaultGraph(new Quad(null, null, null, new NamedNode('http://example.org/'))).should.be.false; }); it('does not match a literal', function () { - N3Util.inDefaultGraph({ graph: '"http://example.org/"' }).should.be.false; + N3Util.inDefaultGraph(new Quad(null, null, null, new Literal('"http://example.org/"'))).should.be.false; }); it('matches null', function () { - N3Util.inDefaultGraph({ graph: null }).should.be.true; + N3Util.inDefaultGraph(new Quad(null, null, null, null)).should.be.true; }); it('matches undefined', function () { - N3Util.inDefaultGraph({ graph: undefined }).should.be.true; + N3Util.inDefaultGraph(new Quad(null, null, null, undefined)).should.be.true; }); - it('matches the empty string', function () { - N3Util.inDefaultGraph({ graph: '' }).should.be.true; + it('matches the default graph', function () { + N3Util.inDefaultGraph(new Quad(null, null, null, new DefaultGraph())).should.be.true; }); }); describe('getLiteralValue', function () { it('gets the value of a literal', function () { - N3Util.getLiteralValue('"Mickey"').should.equal('Mickey'); + N3Util.getLiteralValue(new Literal('"Mickey"')).should.equal('Mickey'); }); it('gets the value of a literal with a language', function () { - N3Util.getLiteralValue('"English"@en').should.equal('English'); + N3Util.getLiteralValue(new Literal('"English"@en')).should.equal('English'); }); it('gets the value of a literal with a language that contains a number', function () { - N3Util.getLiteralValue('"English"@es-419').should.equal('English'); + N3Util.getLiteralValue(new Literal('"English"@es-419')).should.equal('English'); }); it('gets the value of a literal with a type', function () { - N3Util.getLiteralValue('"3"^^http://www.w3.org/2001/XMLSchema#integer').should.equal('3'); + N3Util.getLiteralValue(new Literal('"3"^^http://www.w3.org/2001/XMLSchema#integer')).should.equal('3'); }); it('gets the value of a literal with a newline', function () { - N3Util.getLiteralValue('"Mickey\nMouse"').should.equal('Mickey\nMouse'); + N3Util.getLiteralValue(new Literal('"Mickey\nMouse"')).should.equal('Mickey\nMouse'); }); it('gets the value of a literal with a cariage return', function () { - N3Util.getLiteralValue('"Mickey\rMouse"').should.equal('Mickey\rMouse'); + N3Util.getLiteralValue(new Literal('"Mickey\rMouse"')).should.equal('Mickey\rMouse'); }); it('does not work with non-literals', function () { - N3Util.getLiteralValue.bind(null, 'http://ex.org/').should.throw('http://ex.org/ is not a literal'); + N3Util.getLiteralValue.bind(null, new NamedNode('http://ex.org/')).should.throw('http://ex.org/ is not a literal'); }); it('does not work with null', function () { @@ -183,31 +189,31 @@ describe('N3Util', function () { describe('getLiteralType', function () { it('gets the type of a literal', function () { - N3Util.getLiteralType('"Mickey"').should.equal('http://www.w3.org/2001/XMLSchema#string'); + N3Util.getLiteralType(new Literal('"Mickey"')).should.deep.equal(new NamedNode('http://www.w3.org/2001/XMLSchema#string')); }); it('gets the type of a literal with a language', function () { - N3Util.getLiteralType('"English"@en').should.equal('http://www.w3.org/1999/02/22-rdf-syntax-ns#langString'); + N3Util.getLiteralType(new Literal('"English"@en')).should.deep.equal(new NamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#langString')); }); it('gets the type of a literal with a language that contains a number', function () { - N3Util.getLiteralType('"English"@es-419').should.equal('http://www.w3.org/1999/02/22-rdf-syntax-ns#langString'); + N3Util.getLiteralType(new Literal('"English"@es-419')).should.deep.equal(new NamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#langString')); }); it('gets the type of a literal with a type', function () { - N3Util.getLiteralType('"3"^^http://www.w3.org/2001/XMLSchema#integer').should.equal('http://www.w3.org/2001/XMLSchema#integer'); + N3Util.getLiteralType(new Literal('"3"^^http://www.w3.org/2001/XMLSchema#integer')).should.deep.equal(new NamedNode('http://www.w3.org/2001/XMLSchema#integer')); }); it('gets the type of a literal with a newline', function () { - N3Util.getLiteralType('"Mickey\nMouse"^^abc').should.equal('abc'); + N3Util.getLiteralType(new Literal('"Mickey\nMouse"^^abc')).should.deep.equal(new NamedNode('abc')); }); it('gets the type of a literal with a cariage return', function () { - N3Util.getLiteralType('"Mickey\rMouse"^^abc').should.equal('abc'); + N3Util.getLiteralType(new Literal('"Mickey\rMouse"^^abc')).should.deep.equal(new NamedNode('abc')); }); it('does not work with non-literals', function () { - N3Util.getLiteralType.bind(null, 'http://example.org/').should.throw('http://example.org/ is not a literal'); + N3Util.getLiteralType.bind(null, new NamedNode('http://example.org/')).should.throw('http://example.org/ is not a literal'); }); it('does not work with null', function () { @@ -221,35 +227,35 @@ describe('N3Util', function () { describe('getLiteralLanguage', function () { it('gets the language of a literal', function () { - N3Util.getLiteralLanguage('"Mickey"').should.equal(''); + N3Util.getLiteralLanguage(new Literal('"Mickey"')).should.equal(''); }); it('gets the language of a literal with a language', function () { - N3Util.getLiteralLanguage('"English"@en').should.equal('en'); + N3Util.getLiteralLanguage(new Literal('"English"@en')).should.equal('en'); }); it('gets the language of a literal with a language that contains a number', function () { - N3Util.getLiteralLanguage('"English"@es-419').should.equal('es-419'); + N3Util.getLiteralLanguage(new Literal('"English"@es-419')).should.equal('es-419'); }); it('normalizes the language to lowercase', function () { - N3Util.getLiteralLanguage('"English"@en-GB').should.equal('en-gb'); + N3Util.getLiteralLanguage(new Literal('"English"@en-GB')).should.equal('en-gb'); }); it('gets the language of a literal with a type', function () { - N3Util.getLiteralLanguage('"3"^^http://www.w3.org/2001/XMLSchema#integer').should.equal(''); + N3Util.getLiteralLanguage(new Literal('"3"^^http://www.w3.org/2001/XMLSchema#integer')).should.equal(''); }); it('gets the language of a literal with a newline', function () { - N3Util.getLiteralLanguage('"Mickey\nMouse"@en').should.equal('en'); + N3Util.getLiteralLanguage(new Literal('"Mickey\nMouse"@en')).should.equal('en'); }); it('gets the language of a literal with a cariage return', function () { - N3Util.getLiteralLanguage('"Mickey\rMouse"@en').should.equal('en'); + N3Util.getLiteralLanguage(new Literal('"Mickey\rMouse"@en')).should.equal('en'); }); it('does not work with non-literals', function () { - N3Util.getLiteralLanguage.bind(null, 'http://example.org/').should.throw('http://example.org/ is not a literal'); + N3Util.getLiteralLanguage.bind(null, new NamedNode('http://example.org/')).should.throw('http://example.org/ is not a literal'); }); it('does not work with null', function () { @@ -289,33 +295,33 @@ describe('N3Util', function () { describe('expandPrefixedName', function () { it('expands a prefixed name', function () { - N3Util.expandPrefixedName('ex:Test', { ex: 'http://ex.org/#' }).should.equal('http://ex.org/#Test'); + N3Util.expandPrefixedName('ex:Test', { ex: 'http://ex.org/#' }).should.deep.equal(new NamedNode('http://ex.org/#Test')); }); it('expands a type with a prefixed name', function () { - N3Util.expandPrefixedName('"a"^^ex:type', { ex: 'http://ex.org/#' }).should.equal('"a"^^http://ex.org/#type'); + N3Util.expandPrefixedName('"a"^^ex:type', { ex: 'http://ex.org/#' }).should.deep.equal(new Literal('"a"^^http://ex.org/#type')); }); it('expands a prefixed name with the empty prefix', function () { - N3Util.expandPrefixedName(':Test', { '': 'http://ex.org/#' }).should.equal('http://ex.org/#Test'); + N3Util.expandPrefixedName(':Test', { '': 'http://ex.org/#' }).should.deep.equal(new NamedNode('http://ex.org/#Test')); }); it('does not expand a prefixed name if the prefix is unknown', function () { - N3Util.expandPrefixedName('a:Test', { b: 'http://ex.org/#' }).should.equal('a:Test'); + N3Util.expandPrefixedName('a:Test', { b: 'http://ex.org/#' }).should.deep.equal('a:Test'); }); it('returns the input if it is not a prefixed name', function () { - N3Util.expandPrefixedName('abc', null).should.equal('abc'); + N3Util.expandPrefixedName('abc', null).should.deep.equal('abc'); }); }); describe('createIRI', function () { it('converts a plain IRI', function () { - N3Util.createIRI('http://ex.org/foo#bar').should.equal('http://ex.org/foo#bar'); + N3Util.createIRI('http://ex.org/foo#bar').should.deep.equal(new NamedNode('http://ex.org/foo#bar')); }); it('converts a literal', function () { - N3Util.createIRI('"http://ex.org/foo#bar"^^uri:type').should.equal('http://ex.org/foo#bar'); + N3Util.createIRI('"http://ex.org/foo#bar"^^uri:type').should.deep.equal(new NamedNode('http://ex.org/foo#bar')); }); it('converts null', function () { @@ -325,55 +331,55 @@ describe('N3Util', function () { describe('createLiteral', function () { it('converts the empty string', function () { - N3Util.createLiteral('').should.equal('""'); + N3Util.createLiteral('').should.deep.equal(new Literal('""')); }); it('converts the empty string with a language', function () { - N3Util.createLiteral('', 'en-GB').should.equal('""@en-gb'); + N3Util.createLiteral('', 'en-GB').should.deep.equal(new Literal('""@en-gb')); }); it('converts the empty string with a type', function () { - N3Util.createLiteral('', 'http://ex.org/type').should.equal('""^^http://ex.org/type'); + N3Util.createLiteral('', 'http://ex.org/type').should.deep.equal(new Literal('""^^http://ex.org/type')); }); it('converts a non-empty string', function () { - N3Util.createLiteral('abc').should.equal('"abc"'); + N3Util.createLiteral('abc').should.deep.equal(new Literal('"abc"')); }); it('converts a non-empty string with a language', function () { - N3Util.createLiteral('abc', 'en-GB').should.equal('"abc"@en-gb'); + N3Util.createLiteral('abc', 'en-GB').should.deep.equal(new Literal('"abc"@en-gb')); }); it('converts a non-empty string with a type', function () { - N3Util.createLiteral('abc', 'http://ex.org/type').should.equal('"abc"^^http://ex.org/type'); + N3Util.createLiteral('abc', 'http://ex.org/type').should.deep.equal(new Literal('"abc"^^http://ex.org/type')); }); it('converts an integer', function () { - N3Util.createLiteral(123).should.equal('"123"^^http://www.w3.org/2001/XMLSchema#integer'); + N3Util.createLiteral(123).should.deep.equal(new Literal('"123"^^http://www.w3.org/2001/XMLSchema#integer')); }); it('converts a double', function () { - N3Util.createLiteral(2.3).should.equal('"2.3"^^http://www.w3.org/2001/XMLSchema#double'); + N3Util.createLiteral(2.3).should.deep.equal(new Literal('"2.3"^^http://www.w3.org/2001/XMLSchema#double')); }); it('converts Infinity', function () { - N3Util.createLiteral(Infinity).should.equal('"INF"^^http://www.w3.org/2001/XMLSchema#double'); + N3Util.createLiteral(Infinity).should.deep.equal(new Literal('"INF"^^http://www.w3.org/2001/XMLSchema#double')); }); it('converts -Infinity', function () { - N3Util.createLiteral(-Infinity).should.equal('"-INF"^^http://www.w3.org/2001/XMLSchema#double'); + N3Util.createLiteral(-Infinity).should.deep.equal(new Literal('"-INF"^^http://www.w3.org/2001/XMLSchema#double')); }); it('converts NaN', function () { - N3Util.createLiteral(NaN).should.equal('"NaN"^^http://www.w3.org/2001/XMLSchema#double'); + N3Util.createLiteral(NaN).should.deep.equal(new Literal('"NaN"^^http://www.w3.org/2001/XMLSchema#double')); }); it('converts false', function () { - N3Util.createLiteral(false).should.equal('"false"^^http://www.w3.org/2001/XMLSchema#boolean'); + N3Util.createLiteral(false).should.deep.equal(new Literal('"false"^^http://www.w3.org/2001/XMLSchema#boolean')); }); it('converts true', function () { - N3Util.createLiteral(true).should.equal('"true"^^http://www.w3.org/2001/XMLSchema#boolean'); + N3Util.createLiteral(true).should.deep.equal(new Literal('"true"^^http://www.w3.org/2001/XMLSchema#boolean')); }); }); From 5774899f91d196e9e77df1a0faf32912f2d0e949 Mon Sep 17 00:00:00 2001 From: Ruben Taelman Date: Wed, 10 Jan 2018 11:09:57 +0100 Subject: [PATCH 20/34] Implement DataFactory interface in N3Util --- lib/N3Util.js | 58 ++++++++++++--- test/N3Util-test.js | 172 +++++++++++++++++++++++++++++++++++++------- 2 files changed, 194 insertions(+), 36 deletions(-) diff --git a/lib/N3Util.js b/lib/N3Util.js index 91a88b84..64ad8501 100644 --- a/lib/N3Util.js +++ b/lib/N3Util.js @@ -8,22 +8,34 @@ var XsdBoolean = Xsd + 'boolean'; var Datatype = require('./Datatypes'); var Term = Datatype.Term, NamedNode = Datatype.NamedNode, - Literal = Datatype.Literal; + BlankNode = Datatype.BlankNode, + Literal = Datatype.Literal, + Variable = Datatype.Variable, + DefaultGraph = Datatype.DefaultGraph, + Quad = Datatype.Quad; var N3Util = { + // An internal counter for creating anonymous blank node labels + _blankNodeCounter: 0, + // Tests whether the given entity (triple object) represents an IRI - isIRI: function (entity) { + isNamedNode: function (entity) { return !!entity && entity.termType === 'NamedNode'; }, + // Tests whether the given entity (triple object) represents a blank node + isBlank: function (entity) { + return !!entity && entity.termType === 'BlankNode'; + }, + // Tests whether the given entity (triple object) represents a literal isLiteral: function (entity) { return !!entity && entity.termType === 'Literal'; }, - // Tests whether the given entity (triple object) represents a blank node - isBlank: function (entity) { - return !!entity && entity.termType === 'BlankNode'; + // Tests whether the given entity represents a variable + isVariable: function (entity) { + return !!entity && entity.termType === 'Variable'; }, // Tests whether the given entity represents the default graph @@ -76,13 +88,21 @@ var N3Util = { base + prefixedName.substr(index + prefix.length + 4)); }, - // Creates an IRI in N3.js representation - createIRI: function (iri) { + // Creates an IRI + namedNode: function (iri) { return iri && new NamedNode(iri[0] === '"' ? Term.fromId(iri).value : iri); }, - // Creates a literal in N3.js representation - createLiteral: function (value, modifier) { + // Creates a blank node + blankNode: function (name) { + if (!name) + name = 'n3' + N3Util._blankNodeCounter++; + return new BlankNode(name); + }, + + // Creates a literal + literal: function (value, languageOrDataType) { + var modifier = languageOrDataType && languageOrDataType.termType ? languageOrDataType.value : languageOrDataType; if (!modifier) { switch (typeof value) { case 'boolean': @@ -106,6 +126,26 @@ var N3Util = { : '"^^' + modifier)); }, + // Creates a variable + variable: function (name) { + return new Variable(name); + }, + + // Returns the default graph + defaultGraph: function () { + return new DefaultGraph(); + }, + + // Creates a triple + triple: function (subject, predicate, object) { + return N3Util.quad(subject, predicate, object); + }, + + // Creates a quad + quad: function (subject, predicate, object, graph) { + return new Quad(subject, predicate, object, graph); + }, + // Creates a function that prepends the given IRI to a local name prefix: function (iri) { return N3Util.prefixes({ '': iri })(''); diff --git a/test/N3Util-test.js b/test/N3Util-test.js index dc28b11b..35395dd1 100644 --- a/test/N3Util-test.js +++ b/test/N3Util-test.js @@ -3,33 +3,38 @@ var N3Util = require('../N3').Util, var NamedNode = Datatype.NamedNode, Literal = Datatype.Literal, BlankNode = Datatype.BlankNode, + Variable = Datatype.Variable, DefaultGraph = Datatype.DefaultGraph, Quad = Datatype.Quad; describe('N3Util', function () { - describe('isIRI', function () { + describe('isNamedNode', function () { it('matches an IRI', function () { - N3Util.isIRI(new NamedNode('http://example.org/')).should.be.true; + N3Util.isNamedNode(new NamedNode('http://example.org/')).should.be.true; }); it('matches an empty IRI', function () { - N3Util.isIRI(new NamedNode('')).should.be.true; + N3Util.isNamedNode(new NamedNode('')).should.be.true; }); it('does not match a literal', function () { - N3Util.isIRI(new Literal('"http://example.org/"')).should.be.false; + N3Util.isNamedNode(new Literal('"http://example.org/"')).should.be.false; }); it('does not match a blank node', function () { - N3Util.isIRI(new BlankNode('x')).should.be.false; + N3Util.isNamedNode(new BlankNode('x')).should.be.false; + }); + + it('does not match a variable', function () { + N3Util.isNamedNode(new Variable('x')).should.be.false; }); it('does not match null', function () { - expect(N3Util.isIRI(null)).to.be.false; + expect(N3Util.isNamedNode(null)).to.be.false; }); it('does not match undefined', function () { - expect(N3Util.isIRI(undefined)).to.be.false; + expect(N3Util.isNamedNode(undefined)).to.be.false; }); }); @@ -66,6 +71,10 @@ describe('N3Util', function () { N3Util.isLiteral(new BlankNode('_:x')).should.be.false; }); + it('does not match a variable', function () { + N3Util.isLiteral(new Variable('x')).should.be.false; + }); + it('does not match null', function () { expect(N3Util.isLiteral(null)).to.be.false; }); @@ -88,6 +97,10 @@ describe('N3Util', function () { N3Util.isBlank(new Literal('"http://example.org/"')).should.be.false; }); + it('does not match a variable', function () { + N3Util.isBlank(new Variable('x')).should.be.false; + }); + it('does not match null', function () { expect(N3Util.isBlank(null)).to.be.false; }); @@ -97,6 +110,32 @@ describe('N3Util', function () { }); }); + describe('isVariable', function () { + it('matches a variable', function () { + N3Util.isVariable(new Variable('x')).should.be.true; + }); + + it('does not match an IRI', function () { + N3Util.isVariable(new NamedNode('http://example.org/')).should.be.false; + }); + + it('does not match a literal', function () { + N3Util.isVariable(new Literal('"http://example.org/"')).should.be.false; + }); + + it('does not match a blank node', function () { + N3Util.isNamedNode(new BlankNode('x')).should.be.false; + }); + + it('does not match null', function () { + expect(N3Util.isVariable(null)).to.be.false; + }); + + it('does not match undefined', function () { + expect(N3Util.isVariable(undefined)).to.be.false; + }); + }); + describe('isDefaultGraph', function () { it('does not match a blank node', function () { N3Util.isDefaultGraph(new BlankNode('x')).should.be.false; @@ -315,71 +354,150 @@ describe('N3Util', function () { }); }); - describe('createIRI', function () { + describe('namedNode', function () { it('converts a plain IRI', function () { - N3Util.createIRI('http://ex.org/foo#bar').should.deep.equal(new NamedNode('http://ex.org/foo#bar')); + N3Util.namedNode('http://ex.org/foo#bar').should.deep.equal(new NamedNode('http://ex.org/foo#bar')); }); it('converts a literal', function () { - N3Util.createIRI('"http://ex.org/foo#bar"^^uri:type').should.deep.equal(new NamedNode('http://ex.org/foo#bar')); + N3Util.namedNode('"http://ex.org/foo#bar"^^uri:type').should.deep.equal(new NamedNode('http://ex.org/foo#bar')); }); it('converts null', function () { - expect(N3Util.createIRI(null)).to.be.null; + expect(N3Util.namedNode(null)).to.be.null; }); }); - describe('createLiteral', function () { + describe('blankNode', function () { + it('converts a label', function () { + N3Util.blankNode('abc').should.deep.equal(new BlankNode('abc')); + }); + + it('converts an anonymous blank node', function () { + N3Util.blankNode().should.deep.equal(new BlankNode('n30')); + N3Util.blankNode().should.deep.equal(new BlankNode('n31')); + }); + + it('does not create two equal anonymous blank nodes', function () { + N3Util.blankNode().should.not.deep.equal(N3Util.blankNode()); + }); + }); + + describe('literal', function () { it('converts the empty string', function () { - N3Util.createLiteral('').should.deep.equal(new Literal('""')); + N3Util.literal('').should.deep.equal(new Literal('""')); }); it('converts the empty string with a language', function () { - N3Util.createLiteral('', 'en-GB').should.deep.equal(new Literal('""@en-gb')); + N3Util.literal('', 'en-GB').should.deep.equal(new Literal('""@en-gb')); + }); + + it('converts the empty string with a named node type', function () { + N3Util.literal('', new NamedNode('http://ex.org/type')).should.deep.equal(new Literal('""^^http://ex.org/type')); }); - it('converts the empty string with a type', function () { - N3Util.createLiteral('', 'http://ex.org/type').should.deep.equal(new Literal('""^^http://ex.org/type')); + it('converts the empty string with a string type', function () { + N3Util.literal('', 'http://ex.org/type').should.deep.equal(new Literal('""^^http://ex.org/type')); }); it('converts a non-empty string', function () { - N3Util.createLiteral('abc').should.deep.equal(new Literal('"abc"')); + N3Util.literal('abc').should.deep.equal(new Literal('"abc"')); }); it('converts a non-empty string with a language', function () { - N3Util.createLiteral('abc', 'en-GB').should.deep.equal(new Literal('"abc"@en-gb')); + N3Util.literal('abc', 'en-GB').should.deep.equal(new Literal('"abc"@en-gb')); }); - it('converts a non-empty string with a type', function () { - N3Util.createLiteral('abc', 'http://ex.org/type').should.deep.equal(new Literal('"abc"^^http://ex.org/type')); + it('converts a non-empty string with a named node type', function () { + N3Util.literal('abc', new NamedNode('http://ex.org/type')).should.deep.equal(new Literal('"abc"^^http://ex.org/type')); + }); + + it('converts a non-empty string with a string type', function () { + N3Util.literal('abc', 'http://ex.org/type').should.deep.equal(new Literal('"abc"^^http://ex.org/type')); }); it('converts an integer', function () { - N3Util.createLiteral(123).should.deep.equal(new Literal('"123"^^http://www.w3.org/2001/XMLSchema#integer')); + N3Util.literal(123).should.deep.equal(new Literal('"123"^^http://www.w3.org/2001/XMLSchema#integer')); }); it('converts a double', function () { - N3Util.createLiteral(2.3).should.deep.equal(new Literal('"2.3"^^http://www.w3.org/2001/XMLSchema#double')); + N3Util.literal(2.3).should.deep.equal(new Literal('"2.3"^^http://www.w3.org/2001/XMLSchema#double')); }); it('converts Infinity', function () { - N3Util.createLiteral(Infinity).should.deep.equal(new Literal('"INF"^^http://www.w3.org/2001/XMLSchema#double')); + N3Util.literal(Infinity).should.deep.equal(new Literal('"INF"^^http://www.w3.org/2001/XMLSchema#double')); }); it('converts -Infinity', function () { - N3Util.createLiteral(-Infinity).should.deep.equal(new Literal('"-INF"^^http://www.w3.org/2001/XMLSchema#double')); + N3Util.literal(-Infinity).should.deep.equal(new Literal('"-INF"^^http://www.w3.org/2001/XMLSchema#double')); }); it('converts NaN', function () { - N3Util.createLiteral(NaN).should.deep.equal(new Literal('"NaN"^^http://www.w3.org/2001/XMLSchema#double')); + N3Util.literal(NaN).should.deep.equal(new Literal('"NaN"^^http://www.w3.org/2001/XMLSchema#double')); }); it('converts false', function () { - N3Util.createLiteral(false).should.deep.equal(new Literal('"false"^^http://www.w3.org/2001/XMLSchema#boolean')); + N3Util.literal(false).should.deep.equal(new Literal('"false"^^http://www.w3.org/2001/XMLSchema#boolean')); }); it('converts true', function () { - N3Util.createLiteral(true).should.deep.equal(new Literal('"true"^^http://www.w3.org/2001/XMLSchema#boolean')); + N3Util.literal(true).should.deep.equal(new Literal('"true"^^http://www.w3.org/2001/XMLSchema#boolean')); + }); + }); + + describe('variable', function () { + it('converts a label', function () { + N3Util.variable('abc').should.deep.equal(new Variable('abc')); + }); + }); + + describe('defaultGraph', function () { + it('returns the default graph', function () { + N3Util.defaultGraph().should.deep.equal(new DefaultGraph()); + }); + }); + + describe('triple', function () { + it('returns a quad in the default graph', function () { + N3Util.triple( + new NamedNode('http://ex.org/a'), + new NamedNode('http://ex.org/b'), + new Literal('abc') + ).should.deep.equal(new Quad( + new NamedNode('http://ex.org/a'), + new NamedNode('http://ex.org/b'), + new Literal('abc'), + new DefaultGraph() + )); + }); + }); + + describe('quad', function () { + it('returns a quad', function () { + N3Util.quad( + new NamedNode('http://ex.org/a'), + new NamedNode('http://ex.org/b'), + new Literal('abc'), + new NamedNode('http://ex.org/d') + ).should.deep.equal(new Quad( + new NamedNode('http://ex.org/a'), + new NamedNode('http://ex.org/b'), + new Literal('abc'), + new NamedNode('http://ex.org/d') + )); + }); + + it('without graph parameter returns a quad in the default graph', function () { + N3Util.quad( + new NamedNode('http://ex.org/a'), + new NamedNode('http://ex.org/b'), + new Literal('abc') + ).should.deep.equal(new Quad( + new NamedNode('http://ex.org/a'), + new NamedNode('http://ex.org/b'), + new Literal('abc'), + new DefaultGraph() + )); }); }); From 90a7e06d6d9ba3edfcb3915bd1e54fd200114b14 Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Tue, 10 Apr 2018 18:08:11 +0200 Subject: [PATCH 21/34] Add dedicated DataFactory interface. --- N3.js | 6 +- lib/{Datatypes.js => N3DataFactory.js} | 77 +++++++++++- lib/N3Parser.js | 14 +-- lib/N3Store.js | 8 +- lib/N3Util.js | 75 +---------- lib/N3Writer.js | 8 +- test/BlankNode-test.js | 5 +- test/DefaultGraph-test.js | 5 +- test/Literal-test.js | 7 +- test/N3DataFactory-test.js | 149 ++++++++++++++++++++++ test/N3Parser-test.js | 5 +- test/N3Store-test.js | 17 +-- test/N3StreamWriter-test.js | 6 +- test/N3Util-test.js | 164 ++----------------------- test/N3Writer-test.js | 15 +-- test/NamedNode-test.js | 5 +- test/Quad-test.js | 9 +- test/Term-test.js | 15 +-- test/Variable-test.js | 5 +- 19 files changed, 301 insertions(+), 294 deletions(-) rename lib/{Datatypes.js => N3DataFactory.js} (78%) create mode 100644 test/N3DataFactory-test.js diff --git a/N3.js b/N3.js index 4646847f..08112e13 100644 --- a/N3.js +++ b/N3.js @@ -4,6 +4,7 @@ require = function () {}; // Expose submodules var exports = module.exports = { + DataFactory: require('./lib/N3DataFactory'), Lexer: require('./lib/N3Lexer'), Parser: require('./lib/N3Parser'), Writer: require('./lib/N3Writer'), @@ -24,8 +25,3 @@ Object.keys(exports).forEach(function (submodule) { }, }); }); - -// Load data types directly -var Core = globalRequire('./lib/Datatypes'); -for (var type in Core) - exports[type] = Core[type]; diff --git a/lib/Datatypes.js b/lib/N3DataFactory.js similarity index 78% rename from lib/Datatypes.js rename to lib/N3DataFactory.js index 5cf5c9de..8c047de8 100644 --- a/lib/Datatypes.js +++ b/lib/N3DataFactory.js @@ -3,9 +3,14 @@ var DEFAULTGRAPH; -var STRING = Literal.STRING = 'http://www.w3.org/2001/XMLSchema#string', +var XSD = 'http://www.w3.org/2001/XMLSchema#', + XSD_INTEGER = Literal.INTEGER = XSD + 'integer', + XSD_DOUBLE = Literal.DOUBLE = XSD + 'double', + XSD_BOOLEAN = Literal.BOOLEAN = XSD + 'boolean', + XSD_STRING = Literal.STRING = XSD + 'string', LANG_STRING = Literal.LANG_STRING = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString'; +var _blankNodeCounter = 0; // ## Term constructor function Term(id) { @@ -54,7 +59,7 @@ Term.toId = function (term) { case 'DefaultGraph': return ''; case 'Literal': return '"' + term.value + '"' + (term.language ? '@' + term.language : - (term.datatype && term.datatype.value !== STRING ? '^^' + term.datatype.value : '')); + (term.datatype && term.datatype.value !== XSD_STRING ? '^^' + term.datatype.value : '')); default: throw new Error('Unexpected termType: ' + term.termType); } }; @@ -160,7 +165,7 @@ Object.defineProperty(Literal.prototype, 'datatypeString', { // If "^" it follows, return the remaining substring return dtPos < id.length && (ch = id[dtPos]) === '^' ? id.substr(dtPos + 2) : // If "@" follows, return rdf:langString; xsd:string otherwise - (ch !== '@' ? STRING : LANG_STRING); + (ch !== '@' ? XSD_STRING : LANG_STRING); }, }); @@ -240,8 +245,74 @@ Quad.prototype.equals = function (other) { }; +// ## DataFactory functions + +// ### Creates an IRI +function namedNode(iri) { + return new NamedNode(iri); +} + +// ### Creates a blank node +function blankNode(name) { + if (!name) + name = 'n3-' + _blankNodeCounter++; + return new BlankNode(name); +} + +// ### Creates a literal +function literal(value, languageOrDataType) { + var modifier = languageOrDataType && languageOrDataType.termType ? languageOrDataType.value : languageOrDataType; + if (!modifier) { + switch (typeof value) { + case 'boolean': + modifier = XSD_BOOLEAN; + break; + case 'number': + if (isFinite(value)) + modifier = value % 1 === 0 ? XSD_INTEGER : XSD_DOUBLE; + else { + modifier = XSD_DOUBLE; + if (!isNaN(value)) + value = value > 0 ? 'INF' : '-INF'; + } + break; + default: + return new Literal('"' + value + '"'); + } + } + return new Literal('"' + value + + (/^[a-z]+(-[a-z0-9]+)*$/i.test(modifier) ? '"@' + modifier.toLowerCase() + : '"^^' + modifier)); +} + +// ### Creates a variable +function variable(name) { + return new Variable(name); +} + +// ### Returns the default graph +function defaultGraph() { + return DEFAULTGRAPH; +} + +// ### Creates a quad +function quad(subject, predicate, object, graph) { + return new Quad(subject, predicate, object, graph); +} + + // ## Module exports module.exports = { + // ### Public factory functions + namedNode: namedNode, + blankNode: blankNode, + variable: variable, + literal: literal, + defaultGraph: defaultGraph, + quad: quad, + triple: quad, + + // ### Internal datatype constructors Term: Term, NamedNode: NamedNode, BlankNode: BlankNode, diff --git a/lib/N3Parser.js b/lib/N3Parser.js index 3f543788..046788c6 100644 --- a/lib/N3Parser.js +++ b/lib/N3Parser.js @@ -1,12 +1,12 @@ // **N3Parser** parses N3 documents. var N3Lexer = require('./N3Lexer'), - Datatype = require('./Datatypes'); -var NamedNode = Datatype.NamedNode, - BlankNode = Datatype.BlankNode, - Literal = Datatype.Literal, - Variable = Datatype.Variable, - DefaultGraph = Datatype.DefaultGraph, - Quad = Datatype.Quad; + DataFactory = require('./N3DataFactory'); +var NamedNode = DataFactory.NamedNode, + BlankNode = DataFactory.BlankNode, + Literal = DataFactory.Literal, + Variable = DataFactory.Variable, + DefaultGraph = DataFactory.DefaultGraph, + Quad = DataFactory.Quad; var RDF_PREFIX = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', SWAP_PREFIX = 'http://www.w3.org/2000/10/swap/', diff --git a/lib/N3Store.js b/lib/N3Store.js index 60f33c6e..e8df4a1a 100644 --- a/lib/N3Store.js +++ b/lib/N3Store.js @@ -1,10 +1,10 @@ // **N3Store** objects store N3 triples by graph in memory. var expandPrefixedName = require('./N3Util').expandPrefixedName; -var Datatype = require('./Datatypes'); -var Term = Datatype.Term, - BlankNode = Datatype.BlankNode, - Quad = Datatype.Quad; +var DataFactory = require('./N3DataFactory'); +var Term = DataFactory.Term, + BlankNode = DataFactory.BlankNode, + Quad = DataFactory.Quad; // ## Constructor function N3Store(triples, options) { diff --git a/lib/N3Util.js b/lib/N3Util.js index 64ad8501..d2fac04a 100644 --- a/lib/N3Util.js +++ b/lib/N3Util.js @@ -1,23 +1,8 @@ // **N3Util** provides N3 utility functions. -var Xsd = 'http://www.w3.org/2001/XMLSchema#'; -var XsdInteger = Xsd + 'integer'; -var XsdDouble = Xsd + 'double'; -var XsdBoolean = Xsd + 'boolean'; - -var Datatype = require('./Datatypes'); -var Term = Datatype.Term, - NamedNode = Datatype.NamedNode, - BlankNode = Datatype.BlankNode, - Literal = Datatype.Literal, - Variable = Datatype.Variable, - DefaultGraph = Datatype.DefaultGraph, - Quad = Datatype.Quad; +var Term = require('./N3DataFactory').Term; var N3Util = { - // An internal counter for creating anonymous blank node labels - _blankNodeCounter: 0, - // Tests whether the given entity (triple object) represents an IRI isNamedNode: function (entity) { return !!entity && entity.termType === 'NamedNode'; @@ -88,64 +73,6 @@ var N3Util = { base + prefixedName.substr(index + prefix.length + 4)); }, - // Creates an IRI - namedNode: function (iri) { - return iri && new NamedNode(iri[0] === '"' ? Term.fromId(iri).value : iri); - }, - - // Creates a blank node - blankNode: function (name) { - if (!name) - name = 'n3' + N3Util._blankNodeCounter++; - return new BlankNode(name); - }, - - // Creates a literal - literal: function (value, languageOrDataType) { - var modifier = languageOrDataType && languageOrDataType.termType ? languageOrDataType.value : languageOrDataType; - if (!modifier) { - switch (typeof value) { - case 'boolean': - modifier = XsdBoolean; - break; - case 'number': - if (isFinite(value)) - modifier = value % 1 === 0 ? XsdInteger : XsdDouble; - else { - modifier = XsdDouble; - if (!isNaN(value)) - value = value > 0 ? 'INF' : '-INF'; - } - break; - default: - return new Literal('"' + value + '"'); - } - } - return new Literal('"' + value + - (/^[a-z]+(-[a-z0-9]+)*$/i.test(modifier) ? '"@' + modifier.toLowerCase() - : '"^^' + modifier)); - }, - - // Creates a variable - variable: function (name) { - return new Variable(name); - }, - - // Returns the default graph - defaultGraph: function () { - return new DefaultGraph(); - }, - - // Creates a triple - triple: function (subject, predicate, object) { - return N3Util.quad(subject, predicate, object); - }, - - // Creates a quad - quad: function (subject, predicate, object, graph) { - return new Quad(subject, predicate, object, graph); - }, - // Creates a function that prepends the given IRI to a local name prefix: function (iri) { return N3Util.prefixes({ '': iri })(''); diff --git a/lib/N3Writer.js b/lib/N3Writer.js index a75efc86..a66e99e5 100644 --- a/lib/N3Writer.js +++ b/lib/N3Writer.js @@ -1,9 +1,9 @@ // **N3Writer** writes N3 documents. -var Datatype = require('./Datatypes'); -var Term = Datatype.Term, - Literal = Datatype.Literal, - DEFAULTGRAPH = new Datatype.DefaultGraph(); +var DataFactory = require('./N3DataFactory'); +var Term = DataFactory.Term, + Literal = DataFactory.Literal, + DEFAULTGRAPH = DataFactory.defaultGraph(); // rdf:type predicate (for 'a' abbreviation) var RDF_PREFIX = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', diff --git a/test/BlankNode-test.js b/test/BlankNode-test.js index 5333b81a..4abc4de1 100644 --- a/test/BlankNode-test.js +++ b/test/BlankNode-test.js @@ -1,6 +1,7 @@ -var BlankNode = require('../N3').BlankNode; +var DataFactory = require('../N3').DataFactory; -var Term = require('../N3').Term; +var BlankNode = DataFactory.BlankNode, + Term = DataFactory.Term; describe('BlankNode', function () { describe('The BlankNode module', function () { diff --git a/test/DefaultGraph-test.js b/test/DefaultGraph-test.js index 56c4facd..22d14d9d 100644 --- a/test/DefaultGraph-test.js +++ b/test/DefaultGraph-test.js @@ -1,6 +1,7 @@ -var DefaultGraph = require('../N3').DefaultGraph; +var DataFactory = require('../N3').DataFactory; -var Term = require('../N3').Term; +var DefaultGraph = DataFactory.DefaultGraph, + Term = DataFactory.Term; describe('DefaultGraph', function () { describe('The DefaultGraph module', function () { diff --git a/test/Literal-test.js b/test/Literal-test.js index cf9dde4d..bc2fff6a 100644 --- a/test/Literal-test.js +++ b/test/Literal-test.js @@ -1,7 +1,8 @@ -var Literal = require('../N3').Literal; +var DataFactory = require('../N3').DataFactory; -var Term = require('../N3').Term; -var NamedNode = require('../N3').NamedNode; +var Literal = DataFactory.Literal, + NamedNode = DataFactory.NamedNode, + Term = DataFactory.Term; describe('Literal', function () { describe('The Literal module', function () { diff --git a/test/N3DataFactory-test.js b/test/N3DataFactory-test.js new file mode 100644 index 00000000..f98cb197 --- /dev/null +++ b/test/N3DataFactory-test.js @@ -0,0 +1,149 @@ +var DataFactory = require('../lib/N3DataFactory'); + +var NamedNode = DataFactory.NamedNode, + Literal = DataFactory.Literal, + BlankNode = DataFactory.BlankNode, + Variable = DataFactory.Variable, + DefaultGraph = DataFactory.DefaultGraph, + Quad = DataFactory.Quad; + +describe('DataFactory', function () { + describe('namedNode', function () { + it('converts a plain IRI', function () { + DataFactory.namedNode('http://ex.org/foo#bar').should.deep.equal(new NamedNode('http://ex.org/foo#bar')); + }); + }); + + describe('blankNode', function () { + it('converts a label', function () { + DataFactory.blankNode('abc').should.deep.equal(new BlankNode('abc')); + }); + + it('creates an anonymous blank node', function () { + DataFactory.blankNode().should.deep.equal(new BlankNode('n3-0')); + DataFactory.blankNode().should.deep.equal(new BlankNode('n3-1')); + }); + + it('does not create two equal anonymous blank nodes', function () { + DataFactory.blankNode().should.not.deep.equal(DataFactory.blankNode()); + }); + }); + + describe('literal', function () { + it('converts the empty string', function () { + DataFactory.literal('').should.deep.equal(new Literal('""')); + }); + + it('converts the empty string with a language', function () { + DataFactory.literal('', 'en-GB').should.deep.equal(new Literal('""@en-gb')); + }); + + it('converts the empty string with a named node type', function () { + DataFactory.literal('', new NamedNode('http://ex.org/type')).should.deep.equal(new Literal('""^^http://ex.org/type')); + }); + + it('converts the empty string with a string type', function () { + DataFactory.literal('', 'http://ex.org/type').should.deep.equal(new Literal('""^^http://ex.org/type')); + }); + + it('converts a non-empty string', function () { + DataFactory.literal('abc').should.deep.equal(new Literal('"abc"')); + }); + + it('converts a non-empty string with a language', function () { + DataFactory.literal('abc', 'en-GB').should.deep.equal(new Literal('"abc"@en-gb')); + }); + + it('converts a non-empty string with a named node type', function () { + DataFactory.literal('abc', new NamedNode('http://ex.org/type')).should.deep.equal(new Literal('"abc"^^http://ex.org/type')); + }); + + it('converts a non-empty string with a string type', function () { + DataFactory.literal('abc', 'http://ex.org/type').should.deep.equal(new Literal('"abc"^^http://ex.org/type')); + }); + + it('converts an integer', function () { + DataFactory.literal(123).should.deep.equal(new Literal('"123"^^http://www.w3.org/2001/XMLSchema#integer')); + }); + + it('converts a double', function () { + DataFactory.literal(2.3).should.deep.equal(new Literal('"2.3"^^http://www.w3.org/2001/XMLSchema#double')); + }); + + it('converts Infinity', function () { + DataFactory.literal(Infinity).should.deep.equal(new Literal('"INF"^^http://www.w3.org/2001/XMLSchema#double')); + }); + + it('converts -Infinity', function () { + DataFactory.literal(-Infinity).should.deep.equal(new Literal('"-INF"^^http://www.w3.org/2001/XMLSchema#double')); + }); + + it('converts NaN', function () { + DataFactory.literal(NaN).should.deep.equal(new Literal('"NaN"^^http://www.w3.org/2001/XMLSchema#double')); + }); + + it('converts false', function () { + DataFactory.literal(false).should.deep.equal(new Literal('"false"^^http://www.w3.org/2001/XMLSchema#boolean')); + }); + + it('converts true', function () { + DataFactory.literal(true).should.deep.equal(new Literal('"true"^^http://www.w3.org/2001/XMLSchema#boolean')); + }); + }); + + describe('variable', function () { + it('converts a label', function () { + DataFactory.variable('abc').should.deep.equal(new Variable('abc')); + }); + }); + + describe('defaultGraph', function () { + it('returns the default graph', function () { + DataFactory.defaultGraph().should.deep.equal(new DefaultGraph()); + }); + }); + + describe('triple', function () { + it('returns a quad in the default graph', function () { + DataFactory.triple( + new NamedNode('http://ex.org/a'), + new NamedNode('http://ex.org/b'), + new Literal('abc') + ).should.deep.equal(new Quad( + new NamedNode('http://ex.org/a'), + new NamedNode('http://ex.org/b'), + new Literal('abc'), + new DefaultGraph() + )); + }); + }); + + describe('quad', function () { + it('returns a quad', function () { + DataFactory.quad( + new NamedNode('http://ex.org/a'), + new NamedNode('http://ex.org/b'), + new Literal('abc'), + new NamedNode('http://ex.org/d') + ).should.deep.equal(new Quad( + new NamedNode('http://ex.org/a'), + new NamedNode('http://ex.org/b'), + new Literal('abc'), + new NamedNode('http://ex.org/d') + )); + }); + + it('without graph parameter returns a quad in the default graph', function () { + DataFactory.quad( + new NamedNode('http://ex.org/a'), + new NamedNode('http://ex.org/b'), + new Literal('abc') + ).should.deep.equal(new Quad( + new NamedNode('http://ex.org/a'), + new NamedNode('http://ex.org/b'), + new Literal('abc'), + new DefaultGraph() + )); + }); + }); +}); diff --git a/test/N3Parser-test.js b/test/N3Parser-test.js index 566c83f7..4a4a7ef8 100644 --- a/test/N3Parser-test.js +++ b/test/N3Parser-test.js @@ -1,7 +1,8 @@ var N3Parser = require('../N3').Parser; -var Term = require('../N3').Term, - Quad = require('../N3').Quad; +var DataFactory = require('../N3').DataFactory; +var Term = DataFactory.Term, + Quad = DataFactory.Quad; describe('N3Parser', function () { describe('The N3Parser module', function () { diff --git a/test/N3Store-test.js b/test/N3Store-test.js index 4bc04c68..91d11784 100644 --- a/test/N3Store-test.js +++ b/test/N3Store-test.js @@ -1,11 +1,12 @@ -var N3Store = require('../N3').Store, - Datatype = require('../lib/Datatypes'); -var Term = Datatype.Term, - NamedNode = Datatype.NamedNode, - Literal = Datatype.Literal, - DefaultGraph = Datatype.DefaultGraph, - Quad = Datatype.Quad, - Triple = Datatype.Triple; +var N3Store = require('../N3').Store; + +var DataFactory = require('../N3').DataFactory; +var Term = DataFactory.Term, + NamedNode = DataFactory.NamedNode, + Literal = DataFactory.Literal, + DefaultGraph = DataFactory.DefaultGraph, + Quad = DataFactory.Quad, + Triple = DataFactory.Triple; describe('N3Store', function () { describe('The N3Store module', function () { diff --git a/test/N3StreamWriter-test.js b/test/N3StreamWriter-test.js index cb252c77..ab9fae87 100644 --- a/test/N3StreamWriter-test.js +++ b/test/N3StreamWriter-test.js @@ -2,9 +2,9 @@ var N3StreamWriter = require('../N3').StreamWriter; var Readable = require('stream').Readable, Writable = require('stream').Writable, - Datatype = require('../lib/Datatypes'); -var Term = Datatype.Term, - Quad = Datatype.Quad; + DataFactory = require('../N3').DataFactory; +var Term = DataFactory.Term, + Quad = DataFactory.Quad; describe('N3StreamWriter', function () { describe('The N3StreamWriter module', function () { diff --git a/test/N3Util-test.js b/test/N3Util-test.js index 35395dd1..79310fc6 100644 --- a/test/N3Util-test.js +++ b/test/N3Util-test.js @@ -1,11 +1,12 @@ -var N3Util = require('../N3').Util, - Datatype = require('../lib/Datatypes'); -var NamedNode = Datatype.NamedNode, - Literal = Datatype.Literal, - BlankNode = Datatype.BlankNode, - Variable = Datatype.Variable, - DefaultGraph = Datatype.DefaultGraph, - Quad = Datatype.Quad; +var N3Util = require('../N3').Util; + +var DataFactory = require('../N3').DataFactory; +var NamedNode = DataFactory.NamedNode, + Literal = DataFactory.Literal, + BlankNode = DataFactory.BlankNode, + Variable = DataFactory.Variable, + DefaultGraph = DataFactory.DefaultGraph, + Quad = DataFactory.Quad; describe('N3Util', function () { describe('isNamedNode', function () { @@ -354,153 +355,6 @@ describe('N3Util', function () { }); }); - describe('namedNode', function () { - it('converts a plain IRI', function () { - N3Util.namedNode('http://ex.org/foo#bar').should.deep.equal(new NamedNode('http://ex.org/foo#bar')); - }); - - it('converts a literal', function () { - N3Util.namedNode('"http://ex.org/foo#bar"^^uri:type').should.deep.equal(new NamedNode('http://ex.org/foo#bar')); - }); - - it('converts null', function () { - expect(N3Util.namedNode(null)).to.be.null; - }); - }); - - describe('blankNode', function () { - it('converts a label', function () { - N3Util.blankNode('abc').should.deep.equal(new BlankNode('abc')); - }); - - it('converts an anonymous blank node', function () { - N3Util.blankNode().should.deep.equal(new BlankNode('n30')); - N3Util.blankNode().should.deep.equal(new BlankNode('n31')); - }); - - it('does not create two equal anonymous blank nodes', function () { - N3Util.blankNode().should.not.deep.equal(N3Util.blankNode()); - }); - }); - - describe('literal', function () { - it('converts the empty string', function () { - N3Util.literal('').should.deep.equal(new Literal('""')); - }); - - it('converts the empty string with a language', function () { - N3Util.literal('', 'en-GB').should.deep.equal(new Literal('""@en-gb')); - }); - - it('converts the empty string with a named node type', function () { - N3Util.literal('', new NamedNode('http://ex.org/type')).should.deep.equal(new Literal('""^^http://ex.org/type')); - }); - - it('converts the empty string with a string type', function () { - N3Util.literal('', 'http://ex.org/type').should.deep.equal(new Literal('""^^http://ex.org/type')); - }); - - it('converts a non-empty string', function () { - N3Util.literal('abc').should.deep.equal(new Literal('"abc"')); - }); - - it('converts a non-empty string with a language', function () { - N3Util.literal('abc', 'en-GB').should.deep.equal(new Literal('"abc"@en-gb')); - }); - - it('converts a non-empty string with a named node type', function () { - N3Util.literal('abc', new NamedNode('http://ex.org/type')).should.deep.equal(new Literal('"abc"^^http://ex.org/type')); - }); - - it('converts a non-empty string with a string type', function () { - N3Util.literal('abc', 'http://ex.org/type').should.deep.equal(new Literal('"abc"^^http://ex.org/type')); - }); - - it('converts an integer', function () { - N3Util.literal(123).should.deep.equal(new Literal('"123"^^http://www.w3.org/2001/XMLSchema#integer')); - }); - - it('converts a double', function () { - N3Util.literal(2.3).should.deep.equal(new Literal('"2.3"^^http://www.w3.org/2001/XMLSchema#double')); - }); - - it('converts Infinity', function () { - N3Util.literal(Infinity).should.deep.equal(new Literal('"INF"^^http://www.w3.org/2001/XMLSchema#double')); - }); - - it('converts -Infinity', function () { - N3Util.literal(-Infinity).should.deep.equal(new Literal('"-INF"^^http://www.w3.org/2001/XMLSchema#double')); - }); - - it('converts NaN', function () { - N3Util.literal(NaN).should.deep.equal(new Literal('"NaN"^^http://www.w3.org/2001/XMLSchema#double')); - }); - - it('converts false', function () { - N3Util.literal(false).should.deep.equal(new Literal('"false"^^http://www.w3.org/2001/XMLSchema#boolean')); - }); - - it('converts true', function () { - N3Util.literal(true).should.deep.equal(new Literal('"true"^^http://www.w3.org/2001/XMLSchema#boolean')); - }); - }); - - describe('variable', function () { - it('converts a label', function () { - N3Util.variable('abc').should.deep.equal(new Variable('abc')); - }); - }); - - describe('defaultGraph', function () { - it('returns the default graph', function () { - N3Util.defaultGraph().should.deep.equal(new DefaultGraph()); - }); - }); - - describe('triple', function () { - it('returns a quad in the default graph', function () { - N3Util.triple( - new NamedNode('http://ex.org/a'), - new NamedNode('http://ex.org/b'), - new Literal('abc') - ).should.deep.equal(new Quad( - new NamedNode('http://ex.org/a'), - new NamedNode('http://ex.org/b'), - new Literal('abc'), - new DefaultGraph() - )); - }); - }); - - describe('quad', function () { - it('returns a quad', function () { - N3Util.quad( - new NamedNode('http://ex.org/a'), - new NamedNode('http://ex.org/b'), - new Literal('abc'), - new NamedNode('http://ex.org/d') - ).should.deep.equal(new Quad( - new NamedNode('http://ex.org/a'), - new NamedNode('http://ex.org/b'), - new Literal('abc'), - new NamedNode('http://ex.org/d') - )); - }); - - it('without graph parameter returns a quad in the default graph', function () { - N3Util.quad( - new NamedNode('http://ex.org/a'), - new NamedNode('http://ex.org/b'), - new Literal('abc') - ).should.deep.equal(new Quad( - new NamedNode('http://ex.org/a'), - new NamedNode('http://ex.org/b'), - new Literal('abc'), - new DefaultGraph() - )); - }); - }); - describe('prefix', function () { var baz = N3Util.prefix('http://ex.org/baz#'); it('should return a function', function () { diff --git a/test/N3Writer-test.js b/test/N3Writer-test.js index 99bc9099..1c7cb66a 100644 --- a/test/N3Writer-test.js +++ b/test/N3Writer-test.js @@ -1,10 +1,11 @@ -var N3Writer = require('../N3').Writer, - Datatype = require('../lib/Datatypes'); -var Term = Datatype.Term, - NamedNode = Datatype.NamedNode, - Literal = Datatype.Literal, - Quad = Datatype.Quad, - Triple = Datatype.Triple; +var N3Writer = require('../N3').Writer; + +var DataFactory = require('../N3').DataFactory; +var Term = DataFactory.Term, + NamedNode = DataFactory.NamedNode, + Literal = DataFactory.Literal, + Quad = DataFactory.Quad, + Triple = DataFactory.Triple; describe('N3Writer', function () { describe('The N3Writer module', function () { diff --git a/test/NamedNode-test.js b/test/NamedNode-test.js index 6ec1aa50..4a0c1fab 100644 --- a/test/NamedNode-test.js +++ b/test/NamedNode-test.js @@ -1,6 +1,7 @@ -var NamedNode = require('../N3').NamedNode; +var DataFactory = require('../N3').DataFactory; -var Term = require('../N3').Term; +var NamedNode = DataFactory.NamedNode, + Term = DataFactory.Term; describe('NamedNode', function () { describe('The NamedNode module', function () { diff --git a/test/Quad-test.js b/test/Quad-test.js index 72399724..cbd86a72 100644 --- a/test/Quad-test.js +++ b/test/Quad-test.js @@ -1,8 +1,9 @@ -var Quad = require('../N3').Quad; +var DataFactory = require('../N3').DataFactory; -var Triple = require('../N3').Triple, - Term = require('../N3').Term, - DefaultGraph = require('../N3').DefaultGraph; +var Quad = DataFactory.Quad, + Triple = DataFactory.Triple, + Term = DataFactory.Term, + DefaultGraph = DataFactory.DefaultGraph; describe('Quad', function () { describe('The Quad module', function () { diff --git a/test/Term-test.js b/test/Term-test.js index 0c774a50..b63ff50f 100644 --- a/test/Term-test.js +++ b/test/Term-test.js @@ -1,10 +1,11 @@ -var Datatype = require('../lib/Datatypes'); -var Term = Datatype.Term, - NamedNode = Datatype.NamedNode, - BlankNode = Datatype.BlankNode, - Literal = Datatype.Literal, - Variable = Datatype.Variable, - DefaultGraph = Datatype.DefaultGraph; +var DataFactory = require('../N3').DataFactory; + +var Term = DataFactory.Term, + NamedNode = DataFactory.NamedNode, + BlankNode = DataFactory.BlankNode, + Literal = DataFactory.Literal, + Variable = DataFactory.Variable, + DefaultGraph = DataFactory.DefaultGraph; describe('Term', function () { describe('The Term module', function () { diff --git a/test/Variable-test.js b/test/Variable-test.js index ff627043..48d66f88 100644 --- a/test/Variable-test.js +++ b/test/Variable-test.js @@ -1,6 +1,7 @@ -var Variable = require('../N3').Variable; +var DataFactory = require('../N3').DataFactory; -var Term = require('../N3').Term; +var Variable = DataFactory.Variable, + Term = DataFactory.Term; describe('Variable', function () { describe('The Variable module', function () { From 0fda24ef0264fc49896d8ca8540d7b40463e1f24 Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Tue, 10 Apr 2018 20:16:36 +0200 Subject: [PATCH 22/34] Always use base IRI in parser tests. --- test/N3Parser-test.js | 73 +++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/test/N3Parser-test.js b/test/N3Parser-test.js index 4a4a7ef8..df67ad18 100644 --- a/test/N3Parser-test.js +++ b/test/N3Parser-test.js @@ -4,6 +4,8 @@ var DataFactory = require('../N3').DataFactory; var Term = DataFactory.Term, Quad = DataFactory.Quad; +var BASE_IRI = 'http://example.org/'; + describe('N3Parser', function () { describe('The N3Parser module', function () { it('should be a function', function () { @@ -70,11 +72,11 @@ describe('N3Parser', function () { it('should parse a triple with a literal and an IRI type', shouldParse(' "string"^^.', - ['a', 'b', '"string"^^type'])); + ['a', 'b', '"string"^^http://example.org/type'])); it('should parse a triple with a literal and a prefixed name type', - shouldParse('@prefix x: . "string"^^x:z.', - ['a', 'b', '"string"^^y#z'])); + shouldParse('@prefix x: . "string"^^x:z.', + ['a', 'b', '"string"^^urn:x:y#z'])); it('should differentiate between IRI and prefixed name types', shouldParse('@prefix : . :a :b "x"^^. :a :b "x"^^:urn:foo.', @@ -213,11 +215,11 @@ describe('N3Parser', function () { it('should parse diamonds', shouldParse('<> <> <> <>.\n(<>) <> (<>) <>.', - ['', '', '', ''], - ['_:b0', '', '_:b1', ''], - ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', ''], + [BASE_IRI, BASE_IRI, BASE_IRI, BASE_IRI], + ['_:b0', BASE_IRI, '_:b1', BASE_IRI], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', BASE_IRI], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'], - ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', ''], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', BASE_IRI], ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); it('should parse statements with named blank nodes', @@ -307,13 +309,13 @@ describe('N3Parser', function () { shouldParse(' [ ; "z"^^ ].', ['a', 'b', '_:b0'], ['_:b0', 'u', 'v'], - ['_:b0', 'w', '"z"^^t'])); + ['_:b0', 'w', '"z"^^http://example.org/t'])); it('should parse a multi-statement blank node ending with a string with language', shouldParse(' [ ; "z"^^ ].', ['a', 'b', '_:b0'], ['_:b0', 'u', 'v'], - ['_:b0', 'w', '"z"^^t'])); + ['_:b0', 'w', '"z"^^http://example.org/t'])); it('should parse a multi-statement blank node with trailing semicolon', shouldParse(' [ ; ; ].', @@ -340,7 +342,7 @@ describe('N3Parser', function () { it('should not parse an invalid blank node', shouldNotParse('[ .', - 'Expected punctuation to follow "b" on line 1.')); + 'Expected punctuation to follow "http://example.org/b" on line 1.')); it('should parse a statements with only an anonymous node', shouldParse('[

].', @@ -383,7 +385,7 @@ describe('N3Parser', function () { it('should parse a list with a typed literal', shouldParse(' ("x"^^).', ['a', 'b', '_:b0'], - ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', '"x"^^y'], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', '"x"^^http://example.org/y'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); it('should parse a list with a language-tagged literal', @@ -415,7 +417,7 @@ describe('N3Parser', function () { ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', '_:b1'], ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', '"y"@en-gb'], ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', '_:b2'], - ['_:b2', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', '"z"^^t'], + ['_:b2', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', '"z"^^http://example.org/t'], ['_:b2', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); it('should parse statements with prefixed names in lists', @@ -674,7 +676,7 @@ describe('N3Parser', function () { it('should parse a graph with 8-bit unicode escape sequences', shouldParse('<\\U0001d400> {\n<\\U0001d400> <\\U0001d400> "\\U0001d400"^^<\\U0001d400>\n}\n', - ['\ud835\udC00', '\ud835\udc00', '"\ud835\udc00"^^\ud835\udc00', '\ud835\udc00'])); + ['\ud835\udC00', '\ud835\udc00', '"\ud835\udc00"^^http://example.org/\ud835\udc00', '\ud835\udc00'])); it('should not parse a single closing brace', shouldNotParse('}', @@ -734,15 +736,15 @@ describe('N3Parser', function () { it('should parse a quad with 3 IRIs and a literal', shouldParse(' "c"^^ .', - ['a', 'b', '"c"^^d', 'g'])); + ['a', 'b', '"c"^^http://example.org/d', 'g'])); it('should parse a quad with 2 blank nodes and a literal', shouldParse('_:a "c"^^ _:g.', - ['_:b0_a', 'b', '"c"^^d', '_:b0_g'])); + ['_:b0_a', 'b', '"c"^^http://example.org/d', '_:b0_g'])); it('should not parse a quad in a graph', shouldNotParse('{ .}', - 'Expected punctuation to follow "c" on line 1.')); + 'Expected punctuation to follow "http://example.org/c" on line 1.')); it('should not parse a quad with different punctuation', shouldNotParse(' ;', @@ -949,7 +951,7 @@ describe('N3Parser', function () { }); describe('An N3Parser instance with a blank node prefix', function () { - function parser() { return new N3Parser({ blankNodePrefix: '_:blank' }); } + function parser() { return new N3Parser({ documentIRI: BASE_IRI, blankNodePrefix: '_:blank' }); } it('should use the given prefix for blank nodes', shouldParse(parser, @@ -958,7 +960,7 @@ describe('N3Parser', function () { }); describe('An N3Parser instance with an empty blank node prefix', function () { - function parser() { return new N3Parser({ blankNodePrefix: '' }); } + function parser() { return new N3Parser({ documentIRI: BASE_IRI, blankNodePrefix: '' }); } it('should not use a prefix for blank nodes', shouldParse(parser, @@ -967,7 +969,7 @@ describe('N3Parser', function () { }); describe('An N3Parser instance with a non-string format', function () { - function parser() { return new N3Parser({ format: 1 }); } + function parser() { return new N3Parser({ documentIRI: BASE_IRI, format: 1 }); } it('should parse a single triple', shouldParse(parser, ' .', ['a', 'b', 'c'])); @@ -977,7 +979,7 @@ describe('N3Parser', function () { }); describe('An N3Parser instance for the Turtle format', function () { - function parser() { return new N3Parser({ format: 'Turtle' }); } + function parser() { return new N3Parser({ documentIRI: BASE_IRI, format: 'Turtle' }); } it('should parse a single triple', shouldParse(parser, ' .', ['a', 'b', 'c'])); @@ -992,7 +994,7 @@ describe('N3Parser', function () { shouldNotParse(parser, 'GRAPH {}', 'Expected entity but got GRAPH on line 1.')); it('should not parse a quad', - shouldNotParse(parser, ' .', 'Expected punctuation to follow "c" on line 1.')); + shouldNotParse(parser, ' .', 'Expected punctuation to follow "http://example.org/c" on line 1.')); it('should not parse a variable', shouldNotParse(parser, '?a ?b ?c.', 'Unexpected "?a" on line 1.')); @@ -1017,7 +1019,7 @@ describe('N3Parser', function () { }); describe('An N3Parser instance for the TriG format', function () { - function parser() { return new N3Parser({ format: 'TriG' }); } + function parser() { return new N3Parser({ documentIRI: BASE_IRI, format: 'TriG' }); } it('should parse a single triple', shouldParse(parser, ' .', ['a', 'b', 'c'])); @@ -1032,7 +1034,7 @@ describe('N3Parser', function () { shouldParse(parser, 'GRAPH {}')); it('should not parse a quad', - shouldNotParse(parser, ' .', 'Expected punctuation to follow "c" on line 1.')); + shouldNotParse(parser, ' .', 'Expected punctuation to follow "http://example.org/c" on line 1.')); it('should not parse a variable', shouldNotParse(parser, '?a ?b ?c.', 'Unexpected "?a" on line 1.')); @@ -1057,7 +1059,7 @@ describe('N3Parser', function () { }); describe('An N3Parser instance for the N-Triples format', function () { - function parser() { return new N3Parser({ format: 'N-Triples' }); } + function parser() { return new N3Parser({ documentIRI: BASE_IRI, format: 'N-Triples' }); } it('should parse a single triple', shouldParse(parser, '_:a "c".', @@ -1096,7 +1098,7 @@ describe('N3Parser', function () { }); describe('An N3Parser instance for the N-Quads format', function () { - function parser() { return new N3Parser({ format: 'N-Quads' }); } + function parser() { return new N3Parser({ documentIRI: BASE_IRI, format: 'N-Quads' }); } it('should parse a single triple', shouldParse(parser, '_:a "c".', @@ -1135,7 +1137,7 @@ describe('N3Parser', function () { }); describe('An N3Parser instance for the N3 format', function () { - function parser() { return new N3Parser({ format: 'N3' }); } + function parser() { return new N3Parser({ documentIRI: BASE_IRI, format: 'N3' }); } it('should parse a single triple', shouldParse(parser, ' .', ['a', 'b', 'c'])); @@ -1150,7 +1152,7 @@ describe('N3Parser', function () { shouldNotParse(parser, 'GRAPH {}', 'Expected entity but got GRAPH on line 1.')); it('should not parse a quad', - shouldNotParse(parser, ' .', 'Expected punctuation to follow "c" on line 1.')); + shouldNotParse(parser, ' .', 'Expected punctuation to follow "http://example.org/c" on line 1.')); it('allows a blank node label in predicate position', shouldParse(parser, ' _:b .', ['a', '_:b0_b', 'c'])); @@ -1437,7 +1439,7 @@ describe('N3Parser', function () { }); describe('An N3Parser instance for the N3 format with the explicitQuantifiers option', function () { - function parser() { return new N3Parser({ format: 'N3', explicitQuantifiers: true }); } + function parser() { return new N3Parser({ documentIRI: BASE_IRI, format: 'N3', explicitQuantifiers: true }); } it('should parse a @forSome statement', shouldParse(parser, '@forSome . .', @@ -1940,13 +1942,16 @@ function shouldParse(createParser, input) { return function (done) { var results = []; var items = expected.map(function (item) { - return new Quad( - Term.fromId(item[0]), Term.fromId(item[1]), - Term.fromId(item[2]), Term.fromId(item[3] || '') - ); + item = item.map(function (t) { + // Append base to relative IRIs + if (!/^$|^["?]|:/.test(t)) + t = BASE_IRI + t; + return Term.fromId(t); + }); + return new Quad(item[0], item[1], item[2], item[3]); }); N3Parser._resetBlankNodeIds(); - createParser().parse(input, function (error, triple) { + createParser({ documentIRI: BASE_IRI }).parse(input, function (error, triple) { expect(error).not.to.exist; if (triple) results.push(triple); @@ -1972,7 +1977,7 @@ function shouldNotParse(createParser, input, expectedError, expectedContext) { expectedContext = expectedError, expectedError = input, input = createParser, createParser = N3Parser; return function (done) { - createParser().parse(input, function (error, triple) { + createParser({ documentIRI: BASE_IRI }).parse(input, function (error, triple) { if (error) { expect(triple).not.to.exist; error.should.be.an.instanceof(Error); From 155ffc3a5beba57d655e90ac9eac266cebfee647 Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Tue, 10 Apr 2018 21:17:41 +0200 Subject: [PATCH 23/34] Correctly emit parsed blank nodes. --- lib/N3Parser.js | 14 +++++++++----- test/N3Parser-test.js | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/N3Parser.js b/lib/N3Parser.js index 046788c6..c0d5c80c 100644 --- a/lib/N3Parser.js +++ b/lib/N3Parser.js @@ -60,7 +60,7 @@ function N3Parser(options) { }; } this._blankNodePrefix = typeof options.blankNodePrefix !== 'string' ? '' : - '_:' + options.blankNodePrefix.replace(/^_:/, ''); + options.blankNodePrefix.replace(/^(?!_:)/, '_:'); this._lexer = options.lexer || new N3Lexer({ lineMode: isLineMode, n3: isN3 }); // Disable explicit quantifiers by default this._explicitQuantifiers = !!options.explicitQuantifiers; @@ -117,7 +117,7 @@ N3Parser.prototype = { this._inversePredicate = false; // In N3, blank nodes are scoped to a formula // (using a dot as separator, as a blank node label cannot start with it) - this._prefixes._ = (this._graph ? this._graph.id + '.' : '.'); + this._prefixes._ = (this._graph ? this._graph.id.substr(2) + '.' : '.'); // Quantifiers are scoped to a formula this._quantified = Object.create(this._quantified); } @@ -184,15 +184,18 @@ N3Parser.prototype = { value = new NamedNode(this._base === null || absoluteIRI.test(token.value) ? token.value : this._resolveIRI(token)); break; - // Read a blank node or prefixed name + // Read a prefixed name case 'type': - case 'blank': case 'prefixed': var prefix = this._prefixes[token.prefix]; if (prefix === undefined) return this._error('Undefined prefix "' + token.prefix + ':"', token); value = new NamedNode(prefix + token.value); break; + // Read a blank node + case 'blank': + value = new BlankNode(this._prefixes[token.prefix] + token.value); + break; // Read a variable case 'var': value = new Variable(token.value.substr(1)); @@ -907,7 +910,8 @@ N3Parser.prototype = { this._readCallback = this._readInTopContext; this._sparqlStyle = false; this._prefixes = Object.create(null); - this._prefixes._ = this._blankNodePrefix || '_:b' + blankNodePrefix++ + '_'; + this._prefixes._ = this._blankNodePrefix ? this._blankNodePrefix.substr(2) + : 'b' + blankNodePrefix++ + '_'; this._prefixCallback = prefixCallback || noop; this._inversePredicate = false; this._quantified = Object.create(null); diff --git a/test/N3Parser-test.js b/test/N3Parser-test.js index df67ad18..d0e0eb5c 100644 --- a/test/N3Parser-test.js +++ b/test/N3Parser-test.js @@ -1964,7 +1964,7 @@ function shouldParse(createParser, input) { function toSortedJSON(triples) { triples = triples.map(function (t) { return JSON.stringify([ - t.subject.id, t.predicate.id, t.object.id, t.graph.id, + t.subject.toJSON(), t.predicate.toJSON(), t.object.toJSON(), t.graph.toJSON(), ]); }); triples.sort(); From 0d5bc24a805836d66da6160d46254c265c550df8 Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Tue, 10 Apr 2018 19:24:13 +0200 Subject: [PATCH 24/34] Migrate spec tester to RDF/JS interface. --- spec/SpecTester.js | 123 ++++++++++++++++++++++++--------------------- 1 file changed, 65 insertions(+), 58 deletions(-) diff --git a/spec/SpecTester.js b/spec/SpecTester.js index 9f4f1f97..2852fd4e 100755 --- a/spec/SpecTester.js +++ b/spec/SpecTester.js @@ -8,6 +8,9 @@ var N3 = require('../N3.js'), async = require('async'); require('colors'); +var DataFactory = N3.DataFactory, + Term = DataFactory.Term; + // How many test cases may run in parallel? var workers = 1; @@ -129,15 +132,15 @@ SpecTester.prototype._parseManifest = function (manifestContents, callback) { skipped = manifest.skipped = [], itemHead = testStore.getObjects('', prefixes.mf + 'entries')[0]; // Loop through all test items - while (itemHead && itemHead !== nil) { + while (itemHead && itemHead.value !== nil) { // Find and store the item's properties var itemValue = testStore.getObjects(itemHead, first)[0], itemTriples = testStore.getTriples(itemValue, null, null), - test = { id: itemValue.replace(/^#/, '') }; + test = { id: itemValue.value.replace(/^#/, '') }; itemTriples.forEach(function (triple) { - var propertyMatch = triple.predicate.match(/#(.+)/); + var propertyMatch = triple.predicate.value.match(/#(.+)/); if (propertyMatch) - test[propertyMatch[1]] = triple.object; + test[propertyMatch[1]] = triple.object.value; }); test.negative = /Negative/.test(test.type); test.skipped = self._skipNegative && test.negative; @@ -189,8 +192,7 @@ SpecTester.prototype._verifyResult = function (test, resultFile, correctFile, ca // Display the test result function displayResult(error, success, comparison) { - console.log(N3.Util.getLiteralValue(test.name).bold + ':', - N3.Util.getLiteralValue(test.comment), + console.log(test.name.bold + ':', test.comment, (test.skipped ? 'SKIP'.yellow : (success ? 'ok'.green : 'FAIL'.red)).bold); if (!test.skipped && (error || !success)) { console.log((correctFile ? fs.readFileSync(correctFile, 'utf8') : '(empty)').grey); @@ -246,62 +248,67 @@ SpecTester.prototype._generateEarlReport = function (tests, callback) { developer = 'http://ruben.verborgh.org/#me', manifest = this._manifest + '#'; report.addPrefix('manifest', manifest); - report.addTriple('', prefixes.foaf + 'primaryTopic', app); - report.addTriple('', prefixes.dc + 'issued', date); - report.addTriple('', prefixes.foaf + 'maker', developer); - - report.addTriple(app, prefixes.rdf + 'type', prefixes.earl + 'Software'); - report.addTriple(app, prefixes.rdf + 'type', prefixes.earl + 'TestSubject'); - report.addTriple(app, prefixes.rdf + 'type', prefixes.doap + 'Project'); - report.addTriple(app, prefixes.doap + 'name', '"N3.js"'); - report.addTriple(app, prefixes.doap + 'homepage', homepage); - report.addTriple(app, prefixes.doap + 'license', 'http://opensource.org/licenses/MIT'); - report.addTriple(app, prefixes.doap + 'programming-language', '"JavaScript"'); - report.addTriple(app, prefixes.doap + 'implements', 'http://www.w3.org/TR/turtle/'); - report.addTriple(app, prefixes.doap + 'implements', 'http://www.w3.org/TR/trig/'); - report.addTriple(app, prefixes.doap + 'implements', 'http://www.w3.org/TR/n-triples/'); - report.addTriple(app, prefixes.doap + 'implements', 'http://www.w3.org/TR/n-quads/'); - report.addTriple(app, prefixes.doap + 'category', 'http://dbpedia.org/resource/Resource_Description_Framework'); - report.addTriple(app, prefixes.doap + 'download-page', 'https://npmjs.org/package/n3'); - report.addTriple(app, prefixes.doap + 'bug-database', homepage + '/issues'); - report.addTriple(app, prefixes.doap + 'blog', 'http://ruben.verborgh.org/blog/'); - report.addTriple(app, prefixes.doap + 'developer', developer); - report.addTriple(app, prefixes.doap + 'maintainer', developer); - report.addTriple(app, prefixes.doap + 'documenter', developer); - report.addTriple(app, prefixes.doap + 'maker', developer); - report.addTriple(app, prefixes.dc + 'title', '"N3.js"'); - report.addTriple(app, prefixes.dc + 'description', '"N3.js is an asynchronous, streaming RDF parser for JavaScript."@en'); - report.addTriple(app, prefixes.doap + 'description', '"N3.js is an asynchronous, streaming RDF parser for JavaScript."@en'); - report.addTriple(app, prefixes.dc + 'creator', developer); - - report.addTriple(developer, prefixes.rdf + 'type', prefixes.foaf + 'Person'); - report.addTriple(developer, prefixes.rdf + 'type', prefixes.earl + 'Assertor'); - report.addTriple(developer, prefixes.foaf + 'name', '"Ruben Verborgh"'); - report.addTriple(developer, prefixes.foaf + 'homepage', 'http://ruben.verborgh.org/'); - report.addTriple(developer, prefixes.foaf + 'primaryTopicOf', 'http://ruben.verborgh.org/profile/'); - report.addTriple(developer, prefixes.rdfs + 'isDefinedBy', 'http://ruben.verborgh.org/profile/'); + + function addTriple(s, p, o) { + report.addTriple(Term.fromId(s), Term.fromId(p), Term.fromId(o)); + } + + addTriple(reportFile, prefixes.foaf + 'primaryTopic', app); + addTriple(reportFile, prefixes.dc + 'issued', date); + addTriple(reportFile, prefixes.foaf + 'maker', developer); + + addTriple(app, prefixes.rdf + 'type', prefixes.earl + 'Software'); + addTriple(app, prefixes.rdf + 'type', prefixes.earl + 'TestSubject'); + addTriple(app, prefixes.rdf + 'type', prefixes.doap + 'Project'); + addTriple(app, prefixes.doap + 'name', '"N3.js"'); + addTriple(app, prefixes.doap + 'homepage', homepage); + addTriple(app, prefixes.doap + 'license', 'http://opensource.org/licenses/MIT'); + addTriple(app, prefixes.doap + 'programming-language', '"JavaScript"'); + addTriple(app, prefixes.doap + 'implements', 'http://www.w3.org/TR/turtle/'); + addTriple(app, prefixes.doap + 'implements', 'http://www.w3.org/TR/trig/'); + addTriple(app, prefixes.doap + 'implements', 'http://www.w3.org/TR/n-triples/'); + addTriple(app, prefixes.doap + 'implements', 'http://www.w3.org/TR/n-quads/'); + addTriple(app, prefixes.doap + 'category', 'http://dbpedia.org/resource/Resource_Description_Framework'); + addTriple(app, prefixes.doap + 'download-page', 'https://npmjs.org/package/n3'); + addTriple(app, prefixes.doap + 'bug-database', homepage + '/issues'); + addTriple(app, prefixes.doap + 'blog', 'http://ruben.verborgh.org/blog/'); + addTriple(app, prefixes.doap + 'developer', developer); + addTriple(app, prefixes.doap + 'maintainer', developer); + addTriple(app, prefixes.doap + 'documenter', developer); + addTriple(app, prefixes.doap + 'maker', developer); + addTriple(app, prefixes.dc + 'title', '"N3.js"'); + addTriple(app, prefixes.dc + 'description', '"N3.js is an asynchronous, streaming RDF parser for JavaScript."@en'); + addTriple(app, prefixes.doap + 'description', '"N3.js is an asynchronous, streaming RDF parser for JavaScript."@en'); + addTriple(app, prefixes.dc + 'creator', developer); + + addTriple(developer, prefixes.rdf + 'type', prefixes.foaf + 'Person'); + addTriple(developer, prefixes.rdf + 'type', prefixes.earl + 'Assertor'); + addTriple(developer, prefixes.foaf + 'name', '"Ruben Verborgh"'); + addTriple(developer, prefixes.foaf + 'homepage', 'http://ruben.verborgh.org/'); + addTriple(developer, prefixes.foaf + 'primaryTopicOf', 'http://ruben.verborgh.org/profile/'); + addTriple(developer, prefixes.rdfs + 'isDefinedBy', 'http://ruben.verborgh.org/profile/'); tests.forEach(function (test, id) { var testUrl = manifest + test.id; - report.addTriple(testUrl, prefixes.rdf + 'type', prefixes.earl + 'TestCriterion'); - report.addTriple(testUrl, prefixes.rdf + 'type', prefixes.earl + 'TestCase'); - report.addTriple(testUrl, prefixes.dc + 'title', test.name); - report.addTriple(testUrl, prefixes.dc + 'description', test.comment); - report.addTriple(testUrl, prefixes.mf + 'action', url.resolve(manifest, test.action)); + addTriple(testUrl, prefixes.rdf + 'type', prefixes.earl + 'TestCriterion'); + addTriple(testUrl, prefixes.rdf + 'type', prefixes.earl + 'TestCase'); + addTriple(testUrl, prefixes.dc + 'title', test.name); + addTriple(testUrl, prefixes.dc + 'description', test.comment); + addTriple(testUrl, prefixes.mf + 'action', url.resolve(manifest, test.action)); if (test.result) - report.addTriple(testUrl, prefixes.mf + 'result', url.resolve(manifest, test.result)); - report.addTriple(testUrl, prefixes.earl + 'assertions', '_:assertions' + id); - report.addTriple('_:assertions' + id, prefixes.rdf + 'first', '_:assertion' + id); - report.addTriple('_:assertions' + id, prefixes.rdf + 'rest', prefixes.rdf + 'nil'); - report.addTriple('_:assertion' + id, prefixes.rdf + 'type', prefixes.earl + 'Assertion'); - report.addTriple('_:assertion' + id, prefixes.earl + 'assertedBy', developer); - report.addTriple('_:assertion' + id, prefixes.earl + 'test', manifest + test.id); - report.addTriple('_:assertion' + id, prefixes.earl + 'subject', app); - report.addTriple('_:assertion' + id, prefixes.earl + 'mode', prefixes.earl + 'automatic'); - report.addTriple('_:assertion' + id, prefixes.earl + 'result', '_:result' + id); - report.addTriple('_:result' + id, prefixes.rdf + 'type', prefixes.earl + 'TestResult'); - report.addTriple('_:result' + id, prefixes.earl + 'outcome', prefixes.earl + (test.success ? 'passed' : 'failed')); - report.addTriple('_:result' + id, prefixes.dc + 'date', date); + addTriple(testUrl, prefixes.mf + 'result', url.resolve(manifest, test.result)); + addTriple(testUrl, prefixes.earl + 'assertions', '_:assertions' + id); + addTriple('_:assertions' + id, prefixes.rdf + 'first', '_:assertion' + id); + addTriple('_:assertions' + id, prefixes.rdf + 'rest', prefixes.rdf + 'nil'); + addTriple('_:assertion' + id, prefixes.rdf + 'type', prefixes.earl + 'Assertion'); + addTriple('_:assertion' + id, prefixes.earl + 'assertedBy', developer); + addTriple('_:assertion' + id, prefixes.earl + 'test', manifest + test.id); + addTriple('_:assertion' + id, prefixes.earl + 'subject', app); + addTriple('_:assertion' + id, prefixes.earl + 'mode', prefixes.earl + 'automatic'); + addTriple('_:assertion' + id, prefixes.earl + 'result', '_:result' + id); + addTriple('_:result' + id, prefixes.rdf + 'type', prefixes.earl + 'TestResult'); + addTriple('_:result' + id, prefixes.earl + 'outcome', prefixes.earl + (test.success ? 'passed' : 'failed')); + addTriple('_:result' + id, prefixes.dc + 'date', date); }); report.end(function () { callback(null, tests); }); }; From 142befeaa27df337a0c887592a334613dd061118 Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Wed, 11 Apr 2018 20:42:14 +0200 Subject: [PATCH 25/34] Update EARL URLs. --- spec/SpecTester.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/spec/SpecTester.js b/spec/SpecTester.js index 2852fd4e..41422023 100755 --- a/spec/SpecTester.js +++ b/spec/SpecTester.js @@ -245,7 +245,7 @@ SpecTester.prototype._generateEarlReport = function (tests, callback) { report = new N3.Writer(fs.createWriteStream(reportFile), { prefixes: prefixes }), date = '"' + new Date().toISOString() + '"^^' + prefixes.xsd + 'dateTime', homepage = 'https://github.com/RubenVerborgh/N3.js', app = homepage + '#n3js', - developer = 'http://ruben.verborgh.org/#me', manifest = this._manifest + '#'; + developer = 'https://ruben.verborgh.org/profile/#me', manifest = this._manifest + '#'; report.addPrefix('manifest', manifest); @@ -264,14 +264,14 @@ SpecTester.prototype._generateEarlReport = function (tests, callback) { addTriple(app, prefixes.doap + 'homepage', homepage); addTriple(app, prefixes.doap + 'license', 'http://opensource.org/licenses/MIT'); addTriple(app, prefixes.doap + 'programming-language', '"JavaScript"'); - addTriple(app, prefixes.doap + 'implements', 'http://www.w3.org/TR/turtle/'); - addTriple(app, prefixes.doap + 'implements', 'http://www.w3.org/TR/trig/'); - addTriple(app, prefixes.doap + 'implements', 'http://www.w3.org/TR/n-triples/'); - addTriple(app, prefixes.doap + 'implements', 'http://www.w3.org/TR/n-quads/'); + addTriple(app, prefixes.doap + 'implements', 'https://www.w3.org/TR/turtle/'); + addTriple(app, prefixes.doap + 'implements', 'https://www.w3.org/TR/trig/'); + addTriple(app, prefixes.doap + 'implements', 'https://www.w3.org/TR/n-triples/'); + addTriple(app, prefixes.doap + 'implements', 'https://www.w3.org/TR/n-quads/'); addTriple(app, prefixes.doap + 'category', 'http://dbpedia.org/resource/Resource_Description_Framework'); addTriple(app, prefixes.doap + 'download-page', 'https://npmjs.org/package/n3'); addTriple(app, prefixes.doap + 'bug-database', homepage + '/issues'); - addTriple(app, prefixes.doap + 'blog', 'http://ruben.verborgh.org/blog/'); + addTriple(app, prefixes.doap + 'blog', 'https://ruben.verborgh.org/blog/'); addTriple(app, prefixes.doap + 'developer', developer); addTriple(app, prefixes.doap + 'maintainer', developer); addTriple(app, prefixes.doap + 'documenter', developer); @@ -284,9 +284,8 @@ SpecTester.prototype._generateEarlReport = function (tests, callback) { addTriple(developer, prefixes.rdf + 'type', prefixes.foaf + 'Person'); addTriple(developer, prefixes.rdf + 'type', prefixes.earl + 'Assertor'); addTriple(developer, prefixes.foaf + 'name', '"Ruben Verborgh"'); - addTriple(developer, prefixes.foaf + 'homepage', 'http://ruben.verborgh.org/'); - addTriple(developer, prefixes.foaf + 'primaryTopicOf', 'http://ruben.verborgh.org/profile/'); - addTriple(developer, prefixes.rdfs + 'isDefinedBy', 'http://ruben.verborgh.org/profile/'); + addTriple(developer, prefixes.foaf + 'homepage', 'https://ruben.verborgh.org/'); + addTriple(developer, prefixes.foaf + 'primaryTopicOf', 'https://ruben.verborgh.org/profile/'); tests.forEach(function (test, id) { var testUrl = manifest + test.id; From c700d8608488478bbc704168ce88aca7bc31f67a Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Wed, 11 Apr 2018 21:14:57 +0200 Subject: [PATCH 26/34] Remove prefix support from N3Store. Doesn't make sense with RDF/JS. --- README.md | 4 - lib/N3Store.js | 192 ++----------------------------------- test/N3Store-test.js | 223 +++---------------------------------------- 3 files changed, 21 insertions(+), 398 deletions(-) diff --git a/README.md b/README.md index f1edef39..2430fc06 100644 --- a/README.md +++ b/README.md @@ -327,10 +327,6 @@ The store provides the following search methods - `getGraphs` returns an array of unique graphs occurring in matching triple - `forGraphs` executes a callback on unique graphs occurring in matching triples -All of the above methods also have a variant with the `byIRI` suffix -(e.g., `getTriplesByIRI`), -which skips prefix expansion and is thus faster. - ## Utility `N3.Util` offers helpers for IRI and literal representations. diff --git a/lib/N3Store.js b/lib/N3Store.js index e8df4a1a..2af7ef45 100644 --- a/lib/N3Store.js +++ b/lib/N3Store.js @@ -1,6 +1,5 @@ // **N3Store** objects store N3 triples by graph in memory. -var expandPrefixedName = require('./N3Util').expandPrefixedName; var DataFactory = require('./N3DataFactory'); var Term = DataFactory.Term, BlankNode = DataFactory.BlankNode, @@ -29,10 +28,7 @@ function N3Store(triples, options) { options = triples, triples = null; options = options || {}; - // Add triples and prefixes if passed - this._prefixes = Object.create(null); - if (options.prefixes) - this.addPrefixes(options.prefixes); + // Add triples if passed if (triples) this.addTriples(triples); } @@ -263,17 +259,6 @@ N3Store.prototype = { this.addTriple(triples[i]); }, - // ### `addPrefix` adds support for querying with the given prefix - addPrefix: function (prefix, iri) { - this._prefixes[prefix] = iri; - }, - - // ### `addPrefixes` adds support for querying with the given prefixes - addPrefixes: function (prefixes) { - for (var prefix in prefixes) - this.addPrefix(prefix, prefixes[prefix]); - }, - // ### `removeTriple` removes a triple from the store if it exists removeTriple: function (subject, predicate, object, graph) { // Shift arguments if a triple object is given instead of components @@ -315,21 +300,9 @@ N3Store.prototype = { this.removeTriple(triples[i]); }, - // ### `getTriples` returns an array of triples matching a pattern, expanding prefixes as necessary. + // ### `getTriples` returns an array of triples matching a pattern. // Setting any field to `undefined` or `null` indicates a wildcard. getTriples: function (subject, predicate, object, graph) { - var prefixes = this._prefixes; - return this.getTriplesByIRI( - expandPrefixedName(subject, prefixes), - expandPrefixedName(predicate, prefixes), - expandPrefixedName(object, prefixes), - expandPrefixedName(graph, prefixes) - ); - }, - - // ### `getTriplesByIRI` returns an array of triples matching a pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - getTriplesByIRI: function (subject, predicate, object, graph) { // Convert terms to internal string representation subject = subject && Term.toId(subject); predicate = predicate && Term.toId(predicate); @@ -376,21 +349,9 @@ N3Store.prototype = { return quads; }, - // ### `countTriples` returns the number of triples matching a pattern, expanding prefixes as necessary. + // ### `countTriples` returns the number of triples matching a pattern. // Setting any field to `undefined` or `null` indicates a wildcard. countTriples: function (subject, predicate, object, graph) { - var prefixes = this._prefixes; - return this.countTriplesByIRI( - expandPrefixedName(subject, prefixes), - expandPrefixedName(predicate, prefixes), - expandPrefixedName(object, prefixes), - expandPrefixedName(graph, prefixes) - ); - }, - - // ### `countTriplesByIRI` returns the number of triples matching a pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - countTriplesByIRI: function (subject, predicate, object, graph) { // Convert terms to internal string representation subject = subject && Term.toId(subject); predicate = predicate && Term.toId(predicate); @@ -434,20 +395,7 @@ N3Store.prototype = { // ### `forEach` executes the callback on all triples. // Setting any field to `undefined` or `null` indicates a wildcard. forEach: function (callback, subject, predicate, object, graph) { - var prefixes = this._prefixes; - this.forEachByIRI( - callback, - expandPrefixedName(subject, prefixes), - expandPrefixedName(predicate, prefixes), - expandPrefixedName(object, prefixes), - expandPrefixedName(graph, prefixes) - ); - }, - - // ### `forEachByIRI` executes the callback on all triples. - // Setting any field to `undefined` or `null` indicates a wildcard. - forEachByIRI: function (callback, subject, predicate, object, graph) { - this.someByIRI(function (quad) { + this.some(function (quad) { callback(quad); return false; }, subject, predicate, object, graph); @@ -457,22 +405,8 @@ N3Store.prototype = { // and returns `true` if it returns truthy for all them. // Setting any field to `undefined` or `null` indicates a wildcard. every: function (callback, subject, predicate, object, graph) { - var prefixes = this._prefixes; - return this.everyByIRI( - callback, - expandPrefixedName(subject, prefixes), - expandPrefixedName(predicate, prefixes), - expandPrefixedName(object, prefixes), - expandPrefixedName(graph, prefixes) - ); - }, - - // ### `everyByIRI` executes the callback on all triples, - // and returns `true` if it returns truthy for all them. - // Setting any field to `undefined` or `null` indicates a wildcard. - everyByIRI: function (callback, subject, predicate, object, graph) { var some = false; - var every = !this.someByIRI(function (quad) { + var every = !this.some(function (quad) { some = true; return !callback(quad); }, subject, predicate, object, graph); @@ -483,20 +417,6 @@ N3Store.prototype = { // and returns `true` if it returns truthy for any of them. // Setting any field to `undefined` or `null` indicates a wildcard. some: function (callback, subject, predicate, object, graph) { - var prefixes = this._prefixes; - return this.someByIRI( - callback, - expandPrefixedName(subject, prefixes), - expandPrefixedName(predicate, prefixes), - expandPrefixedName(object, prefixes), - expandPrefixedName(graph, prefixes) - ); - }, - - // ### `someByIRI` executes the callback on all triples, - // and returns `true` if it returns truthy for any of them. - // Setting any field to `undefined` or `null` indicates a wildcard. - someByIRI: function (callback, subject, predicate, object, graph) { // Convert terms to internal string representation subject = subject && Term.toId(subject); predicate = predicate && Term.toId(predicate); @@ -557,37 +477,14 @@ N3Store.prototype = { // ### `getSubjects` returns all subjects that match the pattern. // Setting any field to `undefined` or `null` indicates a wildcard. getSubjects: function (predicate, object, graph) { - var prefixes = this._prefixes; - return this.getSubjectsByIRI( - expandPrefixedName(predicate, prefixes), - expandPrefixedName(object, prefixes), - expandPrefixedName(graph, prefixes) - ); - }, - - // ### `getSubjectsByIRI` returns all subjects that match the pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - getSubjectsByIRI: function (predicate, object, graph) { var results = []; - this.forSubjectsByIRI(function (s) { results.push(s); }, predicate, object, graph); + this.forSubjects(function (s) { results.push(s); }, predicate, object, graph); return results; }, // ### `forSubjects` executes the callback on all subjects that match the pattern. // Setting any field to `undefined` or `null` indicates a wildcard. forSubjects: function (callback, predicate, object, graph) { - var prefixes = this._prefixes; - this.forSubjectsByIRI( - callback, - expandPrefixedName(predicate, prefixes), - expandPrefixedName(object, prefixes), - expandPrefixedName(graph, prefixes) - ); - }, - - // ### `forSubjectsByIRI` executes the callback on all subjects that match the pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - forSubjectsByIRI: function (callback, predicate, object, graph) { // Convert terms to internal string representation predicate = predicate && Term.toId(predicate); object = object && Term.toId(object); @@ -626,37 +523,14 @@ N3Store.prototype = { // ### `getPredicates` returns all predicates that match the pattern. // Setting any field to `undefined` or `null` indicates a wildcard. getPredicates: function (subject, object, graph) { - var prefixes = this._prefixes; - return this.getPredicatesByIRI( - expandPrefixedName(subject, prefixes), - expandPrefixedName(object, prefixes), - expandPrefixedName(graph, prefixes) - ); - }, - - // ### `getPredicatesByIRI` returns all predicates that match the pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - getPredicatesByIRI: function (subject, object, graph) { var results = []; - this.forPredicatesByIRI(function (p) { results.push(p); }, subject, object, graph); + this.forPredicates(function (p) { results.push(p); }, subject, object, graph); return results; }, // ### `forPredicates` executes the callback on all predicates that match the pattern. // Setting any field to `undefined` or `null` indicates a wildcard. forPredicates: function (callback, subject, object, graph) { - var prefixes = this._prefixes; - this.forPredicatesByIRI( - callback, - expandPrefixedName(subject, prefixes), - expandPrefixedName(object, prefixes), - expandPrefixedName(graph, prefixes) - ); - }, - - // ### `forPredicatesByIRI` executes the callback on all predicates that match the pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - forPredicatesByIRI: function (callback, subject, object, graph) { // Convert terms to internal string representation subject = subject && Term.toId(subject); object = object && Term.toId(object); @@ -695,37 +569,14 @@ N3Store.prototype = { // ### `getObjects` returns all objects that match the pattern. // Setting any field to `undefined` or `null` indicates a wildcard. getObjects: function (subject, predicate, graph) { - var prefixes = this._prefixes; - return this.getObjectsByIRI( - expandPrefixedName(subject, prefixes), - expandPrefixedName(predicate, prefixes), - expandPrefixedName(graph, prefixes) - ); - }, - - // ### `getObjectsByIRI` returns all objects that match the pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - getObjectsByIRI: function (subject, predicate, graph) { var results = []; - this.forObjectsByIRI(function (o) { results.push(o); }, subject, predicate, graph); + this.forObjects(function (o) { results.push(o); }, subject, predicate, graph); return results; }, // ### `forObjects` executes the callback on all objects that match the pattern. // Setting any field to `undefined` or `null` indicates a wildcard. forObjects: function (callback, subject, predicate, graph) { - var prefixes = this._prefixes; - this.forObjectsByIRI( - callback, - expandPrefixedName(subject, prefixes), - expandPrefixedName(predicate, prefixes), - expandPrefixedName(graph, prefixes) - ); - }, - - // ### `forObjectsByIRI` executes the callback on all objects that match the pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - forObjectsByIRI: function (callback, subject, predicate, graph) { // Convert terms to internal string representation subject = subject && Term.toId(subject); predicate = predicate && Term.toId(predicate); @@ -764,39 +615,16 @@ N3Store.prototype = { // ### `getGraphs` returns all graphs that match the pattern. // Setting any field to `undefined` or `null` indicates a wildcard. getGraphs: function (subject, predicate, object) { - var prefixes = this._prefixes; - return this.getGraphsByIRI( - expandPrefixedName(subject, prefixes), - expandPrefixedName(predicate, prefixes), - expandPrefixedName(object, prefixes) - ); - }, - - // ### `getGraphsByIRI` returns all graphs that match the pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - getGraphsByIRI: function (subject, predicate, object) { var results = []; - this.forGraphsByIRI(function (g) { results.push(g); }, subject, predicate, object); + this.forGraphs(function (g) { results.push(g); }, subject, predicate, object); return results; }, // ### `forGraphs` executes the callback on all graphs that match the pattern. // Setting any field to `undefined` or `null` indicates a wildcard. forGraphs: function (callback, subject, predicate, object) { - var prefixes = this._prefixes; - this.forGraphsByIRI( - callback, - expandPrefixedName(subject, prefixes), - expandPrefixedName(predicate, prefixes), - expandPrefixedName(object, prefixes) - ); - }, - - // ### `forGraphsByIRI` executes the callback on all graphs that match the pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - forGraphsByIRI: function (callback, subject, predicate, object) { for (var graph in this._graphs) { - this.someByIRI(function (quad) { + this.some(function (quad) { callback(quad.graph); return true; // Halt iteration of some() }, subject, predicate, object, graph); diff --git a/test/N3Store-test.js b/test/N3Store-test.js index 91d11784..94c0f923 100644 --- a/test/N3Store-test.js +++ b/test/N3Store-test.js @@ -3,7 +3,6 @@ var N3Store = require('../N3').Store; var DataFactory = require('../N3').DataFactory; var Term = DataFactory.Term, NamedNode = DataFactory.NamedNode, - Literal = DataFactory.Literal, DefaultGraph = DataFactory.DefaultGraph, Quad = DataFactory.Quad, Triple = DataFactory.Triple; @@ -24,7 +23,7 @@ describe('N3Store', function () { }); describe('An empty N3Store', function () { - var store = new N3Store(); + var store = new N3Store({}); it('should have size 0', function () { expect(store.size).to.eql(0); @@ -706,27 +705,6 @@ describe('N3Store', function () { }); }); - describe('everyByIRI', function () { - var count = 3; - function thirdTimeFalse() { return count-- === 0; } - - describe('with no parameters and a callback always returning true', function () { - it('should return true', function () { - store.everyByIRI(alwaysTrue, null, null, null, null).should.be.true; - }); - }); - describe('with no parameters and a callback always returning false', function () { - it('should return false', function () { - store.everyByIRI(alwaysFalse, null, null, null, null).should.be.false; - }); - }); - describe('with no parameters and a callback that returns false after 3 calls', function () { - it('should return false', function () { - store.everyByIRI(thirdTimeFalse, null, null, null, null).should.be.false; - }); - }); - }); - describe('some', function () { var count = 3; function thirdTimeFalse() { return count-- !== 0; } @@ -748,100 +726,59 @@ describe('N3Store', function () { }); describe('with a non-existing subject', function () { it('should return true', function () { - store.some(null, 's3', null, null, null).should.be.false; - }); - }); - describe('with a non-existing predicate', function () { - it('should return false', function () { - store.some(null, null, 'p3', null, null).should.be.false; - }); - }); - describe('with a non-existing object', function () { - it('should return false', function () { - store.some(null, null, null, 'o4', null).should.be.false; - }); - }); - describe('with a non-existing graph', function () { - it('should return false', function () { - store.some(null, null, null, null, 'g2').should.be.false; - }); - }); - }); - - describe('someByIRI', function () { - var count = 3; - function thirdTimeFalse() { return count-- !== 0; } - - describe('with no parameters and a callback always returning true', function () { - it('should return true', function () { - store.someByIRI(alwaysTrue, null, null, null, null).should.be.true; - }); - }); - describe('with no parameters and a callback always returning false', function () { - it('should return false', function () { - store.someByIRI(alwaysFalse, null, null, null, null).should.be.false; - }); - }); - describe('with no parameters and a callback that returns true after 3 calls', function () { - it('should return false', function () { - store.someByIRI(thirdTimeFalse, null, null, null, null).should.be.true; - }); - }); - describe('with a non-existing subject', function () { - it('should return true', function () { - store.someByIRI(null, new NamedNode('s3'), null, null, null).should.be.false; + store.some(null, new NamedNode('s3'), null, null, null).should.be.false; }); }); describe('with a non-existing predicate', function () { it('should return false', function () { - store.someByIRI(null, null, new NamedNode('p3'), null, null).should.be.false; + store.some(null, null, new NamedNode('p3'), null, null).should.be.false; }); }); describe('with a non-existing object', function () { it('should return false', function () { - store.someByIRI(null, null, null, new NamedNode('o4'), null).should.be.false; + store.some(null, null, null, new NamedNode('o4'), null).should.be.false; }); }); describe('with a non-existing graph', function () { it('should return false', function () { - store.someByIRI(null, null, null, null, new NamedNode('g2')).should.be.false; + store.some(null, null, null, null, new NamedNode('g2')).should.be.false; }); }); }); describe('when counted without parameters', function () { it('should count all items in all graphs', function () { - store.countTriplesByIRI().should.equal(5); + store.countTriples().should.equal(5); }); }); describe('when counted with an existing subject parameter', function () { it('should count all items with this subject in all graphs', function () { - store.countTriplesByIRI(new NamedNode('s1'), null, null).should.equal(4); + store.countTriples(new NamedNode('s1'), null, null).should.equal(4); }); }); describe('when counted with a non-existing subject parameter', function () { it('should be empty', function () { - store.countTriplesByIRI(new NamedNode('s3'), null, null).should.equal(0); + store.countTriples(new NamedNode('s3'), null, null).should.equal(0); }); }); describe('when counted with a non-existing subject parameter that exists elsewhere', function () { it('should be empty', function () { - store.countTriplesByIRI(new NamedNode('p1'), null, null).should.equal(0); + store.countTriples(new NamedNode('p1'), null, null).should.equal(0); }); }); describe('when counted with an existing predicate parameter', function () { it('should count all items with this predicate in all graphs', function () { - store.countTriplesByIRI(null, new NamedNode('p1'), null).should.equal(4); + store.countTriples(null, new NamedNode('p1'), null).should.equal(4); }); }); describe('when counted with a non-existing predicate parameter', function () { it('should be empty', function () { - store.countTriplesByIRI(null, new NamedNode('p3'), null).should.equal(0); + store.countTriples(null, new NamedNode('p3'), null).should.equal(0); }); }); @@ -1014,144 +951,6 @@ describe('N3Store', function () { }); }); - describe('An N3Store initialized with prefixes', function () { - var store = new N3Store([ - new Triple(new NamedNode('http://foo.org/#s1'), new NamedNode('http://bar.org/p1'), new NamedNode('http://foo.org/#o1')), - new Triple(new NamedNode('http://foo.org/#s1'), new NamedNode('http://bar.org/p2'), new NamedNode('http://foo.org/#o1')), - new Triple(new NamedNode('http://foo.org/#s2'), new NamedNode('http://bar.org/p1'), new NamedNode('http://foo.org/#o2')), - new Triple(new NamedNode('http://foo.org/#s3'), new NamedNode('http://bar.org/p3'), new Literal('"a"^^http://foo.org/#t1')), - new Triple(new NamedNode('http://foo.org/#s1'), new NamedNode('http://bar.org/p1'), new NamedNode('http://foo.org/#o1'), new NamedNode('http://graphs.org/#g1')), - ], - { prefixes: { a: 'http://foo.org/#', b: 'http://bar.org/', g: 'http://graphs.org/#' } }); - - describe('should allow to query subjects with prefixes', function () { - it('should return all triples with that subject', - shouldIncludeAll(store.getTriples('a:s1', null, null), - ['http://foo.org/#s1', 'http://bar.org/p1', 'http://foo.org/#o1'], - ['http://foo.org/#s1', 'http://bar.org/p2', 'http://foo.org/#o1'], - ['http://foo.org/#s1', 'http://bar.org/p1', 'http://foo.org/#o1', 'http://graphs.org/#g1'])); - }); - - describe('should allow to query subjects with prefixes', function () { - it('should return all triples with that subject in the default graph', - shouldIncludeAll(store.getTriples('a:s1', null, null, new DefaultGraph()), - ['http://foo.org/#s1', 'http://bar.org/p1', 'http://foo.org/#o1'], - ['http://foo.org/#s1', 'http://bar.org/p2', 'http://foo.org/#o1'])); - }); - - describe('should allow to query predicates with prefixes', function () { - it('should return all triples with that predicate', - shouldIncludeAll(store.getTriples(null, 'b:p1', null), - ['http://foo.org/#s1', 'http://bar.org/p1', 'http://foo.org/#o1'], - ['http://foo.org/#s2', 'http://bar.org/p1', 'http://foo.org/#o2'], - ['http://foo.org/#s1', 'http://bar.org/p1', 'http://foo.org/#o1', 'http://graphs.org/#g1'])); - }); - - describe('should allow to query objects with prefixes', function () { - it('should return all triples with that object', - shouldIncludeAll(store.getTriples(null, null, 'a:o1'), - ['http://foo.org/#s1', 'http://bar.org/p1', 'http://foo.org/#o1'], - ['http://foo.org/#s1', 'http://bar.org/p2', 'http://foo.org/#o1'], - ['http://foo.org/#s1', 'http://bar.org/p1', 'http://foo.org/#o1', 'http://graphs.org/#g1'])); - }); - - describe('should allow to query graphs with prefixes', function () { - it('should return all triples with that graph', - shouldIncludeAll(store.getTriples(null, null, null, 'http://graphs.org/#g1'), - ['http://foo.org/#s1', 'http://bar.org/p1', 'http://foo.org/#o1', 'http://graphs.org/#g1'])); - }); - }); - - describe('An N3Store with prefixes added later on', function () { - var store = new N3Store([ - new Triple(new NamedNode('http://foo.org/#s1'), new NamedNode('http://bar.org/p1'), new NamedNode('http://foo.org/#o1')), - new Triple(new NamedNode('http://foo.org/#s1'), new NamedNode('http://bar.org/p2'), new NamedNode('http://foo.org/#o1')), - new Triple(new NamedNode('http://foo.org/#s2'), new NamedNode('http://bar.org/p1'), new NamedNode('http://foo.org/#o2')), - new Triple(new NamedNode('http://foo.org/#s1'), new NamedNode('http://bar.org/p1'), new NamedNode('http://foo.org/#o1'), new NamedNode('http://graphs.org/#g1')), - ]); - - store.addPrefix('a', 'http://foo.org/#'); - store.addPrefixes({ b: 'http://bar.org/', g: 'http://graphs.org/#' }); - - describe('should allow to query subjects with prefixes', function () { - it('should return all triples with that subject in the default graph', - shouldIncludeAll(store.getTriples('a:s1', null, null, new DefaultGraph()), - ['http://foo.org/#s1', 'http://bar.org/p1', 'http://foo.org/#o1'], - ['http://foo.org/#s1', 'http://bar.org/p2', 'http://foo.org/#o1'])); - }); - - describe('should allow to query subjects with prefixes', function () { - it('should return all triples with that subject', - shouldIncludeAll(store.getTriples('a:s1', null, null), - ['http://foo.org/#s1', 'http://bar.org/p1', 'http://foo.org/#o1'], - ['http://foo.org/#s1', 'http://bar.org/p2', 'http://foo.org/#o1'], - ['http://foo.org/#s1', 'http://bar.org/p1', 'http://foo.org/#o1', 'http://graphs.org/#g1'])); - }); - - describe('should allow to query predicates with prefixes', function () { - it('should return all triples with that predicate in the default graph', - shouldIncludeAll(store.getTriples(null, 'b:p1', null, new DefaultGraph()), - ['http://foo.org/#s1', 'http://bar.org/p1', 'http://foo.org/#o1'], - ['http://foo.org/#s2', 'http://bar.org/p1', 'http://foo.org/#o2'])); - }); - - describe('should allow to query predicates with prefixes', function () { - it('should return all triples with that predicate', - shouldIncludeAll(store.getTriples(null, 'b:p1', null), - ['http://foo.org/#s1', 'http://bar.org/p1', 'http://foo.org/#o1'], - ['http://foo.org/#s2', 'http://bar.org/p1', 'http://foo.org/#o2'], - ['http://foo.org/#s1', 'http://bar.org/p1', 'http://foo.org/#o1', 'http://graphs.org/#g1'])); - }); - - describe('should allow to query objects with prefixes', function () { - it('should return all triples with that object in the default graph', - shouldIncludeAll(store.getTriples(null, null, 'a:o1', new DefaultGraph()), - ['http://foo.org/#s1', 'http://bar.org/p1', 'http://foo.org/#o1'], - ['http://foo.org/#s1', 'http://bar.org/p2', 'http://foo.org/#o1'])); - }); - - describe('should allow to query objects with prefixes', function () { - it('should return all triples with that object', - shouldIncludeAll(store.getTriples(null, null, 'a:o1'), - ['http://foo.org/#s1', 'http://bar.org/p1', 'http://foo.org/#o1'], - ['http://foo.org/#s1', 'http://bar.org/p2', 'http://foo.org/#o1'], - ['http://foo.org/#s1', 'http://bar.org/p1', 'http://foo.org/#o1', 'http://graphs.org/#g1'])); - }); - - describe('should allow to query graphs with prefixes', function () { - it('should return all triples with that graph', - shouldIncludeAll(store.getTriples(null, null, null, 'http://graphs.org/#g1'), - ['http://foo.org/#s1', 'http://bar.org/p1', 'http://foo.org/#o1', 'http://graphs.org/#g1'])); - }); - }); - - describe('An N3Store with the http prefix', function () { - var store = new N3Store([ - new Triple(new NamedNode('http://foo.org/#s1'), new NamedNode('http://bar.org/p1'), new NamedNode('http://foo.org/#o1')), - new Triple(new NamedNode('http://foo.org/#s1'), new NamedNode('http://bar.org/p2'), new NamedNode('http://foo.org/#o1')), - new Triple(new NamedNode('http://foo.org/#s2'), new NamedNode('http://bar.org/p1'), new NamedNode('http://foo.org/#o2')), - ], - { prefixes: { http: 'http://www.w3.org/2006/http#' } }); - - describe('should allow to query subjects without prefixes', function () { - it('should return all triples with that subject', - shouldIncludeAll(store.getTriples('http://foo.org/#s1', null, null), - ['http://foo.org/#s1', 'http://bar.org/p1', 'http://foo.org/#o1'], - ['http://foo.org/#s1', 'http://bar.org/p2', 'http://foo.org/#o1'])); - }); - }); - - describe('An N3Store created without triples but with prefixes', function () { - var store = new N3Store({ prefixes: { http: 'http://www.w3.org/2006/http#' } }); - store.addTriple('a', 'http://www.w3.org/2006/http#b', 'c').should.be.true; - - describe('should allow to query predicates with prefixes', function () { - it('should return all triples with that predicate', - shouldIncludeAll(store.getTriples(null, 'http:b', null), - ['a', 'http://www.w3.org/2006/http#b', 'c'])); - }); - }); - describe('An N3Store containing a blank node', function () { var store = new N3Store(); var b1 = store.createBlankNode(); From c3e00c074ee5378c3e87a5d5d0217adf2ed9d292 Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Wed, 11 Apr 2018 21:15:52 +0200 Subject: [PATCH 27/34] Adapt N3Util to RDF/JS. --- README.md | 7 -- lib/N3Util.js | 90 +++++------------- test/N3Util-test.js | 227 +++++++------------------------------------- 3 files changed, 58 insertions(+), 266 deletions(-) diff --git a/README.md b/README.md index 2430fc06..e94f6ef6 100644 --- a/README.md +++ b/README.md @@ -377,13 +377,6 @@ N3Util.isIRI('_:b1'); // false N3Util.isLiteral('_:b1'); // false ``` -**Prefixed names** can be tested and expanded: -``` js -var prefixes = { rdfs: 'http://www.w3.org/2000/01/rdf-schema#' }; -N3Util.isPrefixedName('rdfs:label'); // true; -N3Util.expandPrefixedName('rdfs:label', prefixes); // http://www.w3.org/2000/01/rdf-schema#label -``` - ## Compatibility ### Specifications The N3.js parser and writer is fully compatible with the following W3C specifications: diff --git a/lib/N3Util.js b/lib/N3Util.js index d2fac04a..d888e7f3 100644 --- a/lib/N3Util.js +++ b/lib/N3Util.js @@ -1,76 +1,36 @@ // **N3Util** provides N3 utility functions. -var Term = require('./N3DataFactory').Term; +var DataFactory = require('./N3DataFactory'); var N3Util = { - // Tests whether the given entity (triple object) represents an IRI - isNamedNode: function (entity) { - return !!entity && entity.termType === 'NamedNode'; + // Tests whether the given term represents an IRI + isNamedNode: function (term) { + return !!term && term.termType === 'NamedNode'; }, - // Tests whether the given entity (triple object) represents a blank node - isBlank: function (entity) { - return !!entity && entity.termType === 'BlankNode'; + // Tests whether the given term represents a blank node + isBlankNode: function (term) { + return !!term && term.termType === 'BlankNode'; }, - // Tests whether the given entity (triple object) represents a literal - isLiteral: function (entity) { - return !!entity && entity.termType === 'Literal'; + // Tests whether the given term represents a literal + isLiteral: function (term) { + return !!term && term.termType === 'Literal'; }, - // Tests whether the given entity represents a variable - isVariable: function (entity) { - return !!entity && entity.termType === 'Variable'; + // Tests whether the given term represents a variable + isVariable: function (term) { + return !!term && term.termType === 'Variable'; }, - // Tests whether the given entity represents the default graph - isDefaultGraph: function (entity) { - return !entity || entity.termType === 'DefaultGraph'; + // Tests whether the given term represents the default graph + isDefaultGraph: function (term) { + return !!term && term.termType === 'DefaultGraph'; }, - // Tests whether the given triple is in the default graph - inDefaultGraph: function (triple) { - return N3Util.isDefaultGraph(triple.graph); - }, - - // Gets the string value of a literal in the N3 library - getLiteralValue: function (literal) { - if (!N3Util.isLiteral(literal)) - throw new Error((literal && literal.value ? literal.value : literal) + ' is not a literal.'); - return literal.value; - }, - - // Gets the type of a literal in the N3 library - getLiteralType: function (literal) { - if (!N3Util.isLiteral(literal)) - throw new Error((literal && literal.value ? literal.value : literal) + ' is not a literal.'); - return literal.datatype; - }, - - // Gets the language of a literal in the N3 library - getLiteralLanguage: function (literal) { - if (!N3Util.isLiteral(literal)) - throw new Error((literal && literal.value ? literal.value : literal) + ' is not a literal.'); - return literal.language; - }, - - // Tests whether the given entity (triple object) represents a prefixed name - isPrefixedName: function (entity) { - return typeof entity === 'string' && /^[^:\/"']*:[^:\/"']+$/.test(entity); - }, - - // Expands the prefixed name to a full IRI (also when it occurs as a literal's type) - expandPrefixedName: function (prefixedName, prefixes) { - var match = /(?:^|"\^\^)([^:\/#"'\^_]*):[^\/]*$/.exec(prefixedName), prefix, base, index; - if (match) - prefix = match[1], base = prefixes[prefix], index = match.index; - if (base === undefined) - return prefixedName; - - // The match index is non-zero when expanding a literal's type - return Term.fromId(index === 0 ? base + prefixedName.substr(prefix.length + 1) - : prefixedName.substr(0, index + 3) + - base + prefixedName.substr(index + prefix.length + 4)); + // Tests whether the given quad is in the default graph + inDefaultGraph: function (quad) { + return N3Util.isDefaultGraph(quad.graph); }, // Creates a function that prepends the given IRI to a local name @@ -89,14 +49,16 @@ var N3Util = { // or retrieves a function that expands an existing prefix (if no IRI was specified) function processPrefix(prefix, iri) { // Create a new prefix if an IRI is specified or the prefix doesn't exist - if (iri || !(prefix in prefixes)) { - var cache = Object.create(null); - iri = iri || ''; + if (typeof iri === 'string') { // Create a function that expands the prefix - prefixes[prefix] = function (localName) { - return cache[localName] || (cache[localName] = iri + localName); + var cache = Object.create(null); + prefixes[prefix] = function (local) { + return cache[local] || (cache[local] = DataFactory.namedNode(iri + local)); }; } + else if (!(prefix in prefixes)) { + throw new Error('Unknown prefix: ' + prefix); + } return prefixes[prefix]; } return processPrefix; diff --git a/test/N3Util-test.js b/test/N3Util-test.js index 79310fc6..1548dcce 100644 --- a/test/N3Util-test.js +++ b/test/N3Util-test.js @@ -85,29 +85,29 @@ describe('N3Util', function () { }); }); - describe('isBlank', function () { + describe('isBlankNode', function () { it('matches a blank node', function () { - N3Util.isBlank(new BlankNode('x')).should.be.true; + N3Util.isBlankNode(new BlankNode('x')).should.be.true; }); it('does not match an IRI', function () { - N3Util.isBlank(new NamedNode('http://example.org/')).should.be.false; + N3Util.isBlankNode(new NamedNode('http://example.org/')).should.be.false; }); it('does not match a literal', function () { - N3Util.isBlank(new Literal('"http://example.org/"')).should.be.false; + N3Util.isBlankNode(new Literal('"http://example.org/"')).should.be.false; }); it('does not match a variable', function () { - N3Util.isBlank(new Variable('x')).should.be.false; + N3Util.isBlankNode(new Variable('x')).should.be.false; }); it('does not match null', function () { - expect(N3Util.isBlank(null)).to.be.false; + expect(N3Util.isBlankNode(null)).to.be.false; }); it('does not match undefined', function () { - expect(N3Util.isBlank(undefined)).to.be.false; + expect(N3Util.isBlankNode(undefined)).to.be.false; }); }); @@ -150,16 +150,12 @@ describe('N3Util', function () { N3Util.isDefaultGraph(new Literal('"http://example.org/"')).should.be.false; }); - it('matches null', function () { - expect(N3Util.isDefaultGraph(null)).to.be.true; - }); - - it('matches undefined', function () { - expect(N3Util.isDefaultGraph(undefined)).to.be.true; + it('does not match null', function () { + expect(N3Util.isVariable(null)).to.be.false; }); - it('matches the empty string', function () { - expect(N3Util.isDefaultGraph('')).to.be.true; + it('does not match undefined', function () { + expect(N3Util.isVariable(undefined)).to.be.false; }); }); @@ -189,181 +185,15 @@ describe('N3Util', function () { }); }); - describe('getLiteralValue', function () { - it('gets the value of a literal', function () { - N3Util.getLiteralValue(new Literal('"Mickey"')).should.equal('Mickey'); - }); - - it('gets the value of a literal with a language', function () { - N3Util.getLiteralValue(new Literal('"English"@en')).should.equal('English'); - }); - - it('gets the value of a literal with a language that contains a number', function () { - N3Util.getLiteralValue(new Literal('"English"@es-419')).should.equal('English'); - }); - - it('gets the value of a literal with a type', function () { - N3Util.getLiteralValue(new Literal('"3"^^http://www.w3.org/2001/XMLSchema#integer')).should.equal('3'); - }); - - it('gets the value of a literal with a newline', function () { - N3Util.getLiteralValue(new Literal('"Mickey\nMouse"')).should.equal('Mickey\nMouse'); - }); - - it('gets the value of a literal with a cariage return', function () { - N3Util.getLiteralValue(new Literal('"Mickey\rMouse"')).should.equal('Mickey\rMouse'); - }); - - it('does not work with non-literals', function () { - N3Util.getLiteralValue.bind(null, new NamedNode('http://ex.org/')).should.throw('http://ex.org/ is not a literal'); - }); - - it('does not work with null', function () { - N3Util.getLiteralValue.bind(null, null).should.throw('null is not a literal'); - }); - - it('does not work with undefined', function () { - N3Util.getLiteralValue.bind(null, undefined).should.throw('undefined is not a literal'); - }); - }); - - describe('getLiteralType', function () { - it('gets the type of a literal', function () { - N3Util.getLiteralType(new Literal('"Mickey"')).should.deep.equal(new NamedNode('http://www.w3.org/2001/XMLSchema#string')); - }); - - it('gets the type of a literal with a language', function () { - N3Util.getLiteralType(new Literal('"English"@en')).should.deep.equal(new NamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#langString')); - }); - - it('gets the type of a literal with a language that contains a number', function () { - N3Util.getLiteralType(new Literal('"English"@es-419')).should.deep.equal(new NamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#langString')); - }); - - it('gets the type of a literal with a type', function () { - N3Util.getLiteralType(new Literal('"3"^^http://www.w3.org/2001/XMLSchema#integer')).should.deep.equal(new NamedNode('http://www.w3.org/2001/XMLSchema#integer')); - }); - - it('gets the type of a literal with a newline', function () { - N3Util.getLiteralType(new Literal('"Mickey\nMouse"^^abc')).should.deep.equal(new NamedNode('abc')); - }); - - it('gets the type of a literal with a cariage return', function () { - N3Util.getLiteralType(new Literal('"Mickey\rMouse"^^abc')).should.deep.equal(new NamedNode('abc')); - }); - - it('does not work with non-literals', function () { - N3Util.getLiteralType.bind(null, new NamedNode('http://example.org/')).should.throw('http://example.org/ is not a literal'); - }); - - it('does not work with null', function () { - N3Util.getLiteralType.bind(null, null).should.throw('null is not a literal'); - }); - - it('does not work with undefined', function () { - N3Util.getLiteralType.bind(null, undefined).should.throw('undefined is not a literal'); - }); - }); - - describe('getLiteralLanguage', function () { - it('gets the language of a literal', function () { - N3Util.getLiteralLanguage(new Literal('"Mickey"')).should.equal(''); - }); - - it('gets the language of a literal with a language', function () { - N3Util.getLiteralLanguage(new Literal('"English"@en')).should.equal('en'); - }); - - it('gets the language of a literal with a language that contains a number', function () { - N3Util.getLiteralLanguage(new Literal('"English"@es-419')).should.equal('es-419'); - }); - - it('normalizes the language to lowercase', function () { - N3Util.getLiteralLanguage(new Literal('"English"@en-GB')).should.equal('en-gb'); - }); - - it('gets the language of a literal with a type', function () { - N3Util.getLiteralLanguage(new Literal('"3"^^http://www.w3.org/2001/XMLSchema#integer')).should.equal(''); - }); - - it('gets the language of a literal with a newline', function () { - N3Util.getLiteralLanguage(new Literal('"Mickey\nMouse"@en')).should.equal('en'); - }); - - it('gets the language of a literal with a cariage return', function () { - N3Util.getLiteralLanguage(new Literal('"Mickey\rMouse"@en')).should.equal('en'); - }); - - it('does not work with non-literals', function () { - N3Util.getLiteralLanguage.bind(null, new NamedNode('http://example.org/')).should.throw('http://example.org/ is not a literal'); - }); - - it('does not work with null', function () { - N3Util.getLiteralLanguage.bind(null, null).should.throw('null is not a literal'); - }); - - it('does not work with undefined', function () { - N3Util.getLiteralLanguage.bind(null, undefined).should.throw('undefined is not a literal'); - }); - }); - - describe('isPrefixedName', function () { - it('matches a prefixed name', function () { - N3Util.isPrefixedName('ex:Test').should.be.true; - }); - - it('does not match an IRI', function () { - N3Util.isPrefixedName('http://example.org/').should.be.false; - }); - - it('does not match a literal', function () { - N3Util.isPrefixedName('"http://example.org/"').should.be.false; - }); - - it('does not match a literal with a colon', function () { - N3Util.isPrefixedName('"a:b"').should.be.false; - }); - - it('does not match null', function () { - expect(N3Util.isPrefixedName(null)).to.be.false; - }); - - it('does not match undefined', function () { - expect(N3Util.isPrefixedName(undefined)).to.be.false; - }); - }); - - describe('expandPrefixedName', function () { - it('expands a prefixed name', function () { - N3Util.expandPrefixedName('ex:Test', { ex: 'http://ex.org/#' }).should.deep.equal(new NamedNode('http://ex.org/#Test')); - }); - - it('expands a type with a prefixed name', function () { - N3Util.expandPrefixedName('"a"^^ex:type', { ex: 'http://ex.org/#' }).should.deep.equal(new Literal('"a"^^http://ex.org/#type')); - }); - - it('expands a prefixed name with the empty prefix', function () { - N3Util.expandPrefixedName(':Test', { '': 'http://ex.org/#' }).should.deep.equal(new NamedNode('http://ex.org/#Test')); - }); - - it('does not expand a prefixed name if the prefix is unknown', function () { - N3Util.expandPrefixedName('a:Test', { b: 'http://ex.org/#' }).should.deep.equal('a:Test'); - }); - - it('returns the input if it is not a prefixed name', function () { - N3Util.expandPrefixedName('abc', null).should.deep.equal('abc'); - }); - }); - describe('prefix', function () { - var baz = N3Util.prefix('http://ex.org/baz#'); + var rdfs = N3Util.prefix('http://www.w3.org/2000/01/rdf-schema#'); it('should return a function', function () { - expect(baz).to.be.an.instanceof(Function); + expect(rdfs).to.be.an.instanceof(Function); }); describe('the function', function () { it('should expand the prefix', function () { - expect(baz('bar')).to.equal('http://ex.org/baz#bar'); + expect(rdfs('label')).to.deep.equal(new NamedNode('http://www.w3.org/2000/01/rdf-schema#label')); }); }); }); @@ -377,45 +207,52 @@ describe('N3Util', function () { describe('the function', function () { it('should not expand non-registered prefixes', function () { - expect(prefixes('baz')('bar')).to.equal('bar'); + expect(function () { prefixes('foo'); }).to.throw('Unknown prefix: foo'); }); it('should allow registering prefixes', function () { - var p = prefixes('baz', 'http://ex.org/baz#'); + var p = prefixes('rdfs', 'http://www.w3.org/2000/01/rdf-schema#'); + var rdfs = prefixes('rdfs'); expect(p).to.exist; - expect(p).to.equal(prefixes('baz')); + expect(p).to.equal(rdfs); }); it('should expand the newly registered prefix', function () { - expect(prefixes('baz')('bar')).to.equal('http://ex.org/baz#bar'); + var rdfs = prefixes('rdfs'); + expect(rdfs('label')).to.deep.equal(new NamedNode('http://www.w3.org/2000/01/rdf-schema#label')); }); }); }); describe('called with a hash of prefixes', function () { - var prefixes = N3Util.prefixes({ foo: 'http://ex.org/foo#', bar: 'http://ex.org/bar#' }); + var prefixes = N3Util.prefixes({ + rdfs: 'http://www.w3.org/2000/01/rdf-schema#', + owl: 'http://www.w3.org/2002/07/owl#', + }); it('should return a function', function () { expect(prefixes).to.be.an.instanceof(Function); }); describe('the function', function () { it('should expand registered prefixes', function () { - expect(prefixes('foo')('bar')).to.equal('http://ex.org/foo#bar'); - expect(prefixes('bar')('bar')).to.equal('http://ex.org/bar#bar'); + expect(prefixes('rdfs')('label')).to.deep.equal(new NamedNode('http://www.w3.org/2000/01/rdf-schema#label')); + expect(prefixes('owl')('sameAs')).to.deep.equal(new NamedNode('http://www.w3.org/2002/07/owl#sameAs')); }); it('should not expand non-registered prefixes', function () { - expect(prefixes('baz')('bar')).to.equal('bar'); + expect(function () { prefixes('foo'); }).to.throw('Unknown prefix: foo'); }); it('should allow registering prefixes', function () { - var p = prefixes('baz', 'http://ex.org/baz#'); + var p = prefixes('my', 'http://example.org/#'); + var my = prefixes('my'); expect(p).to.exist; - expect(p).to.equal(prefixes('baz')); + expect(p).to.equal(my); }); it('should expand the newly registered prefix', function () { - expect(prefixes('baz')('bar')).to.equal('http://ex.org/baz#bar'); + var my = prefixes('my'); + expect(my('me')).to.deep.equal(new NamedNode('http://example.org/#me')); }); }); }); From b8ab3812b4d73f4e6479fe0659df4a158d0eea15 Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Wed, 11 Apr 2018 21:36:11 +0200 Subject: [PATCH 28/34] Emit prefixes as named nodes. --- lib/N3Parser.js | 2 +- test/N3Parser-test.js | 9 ++++++--- test/N3StreamParser-test.js | 7 ++++--- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/N3Parser.js b/lib/N3Parser.js index c0d5c80c..25b31179 100644 --- a/lib/N3Parser.js +++ b/lib/N3Parser.js @@ -624,7 +624,7 @@ N3Parser.prototype = { return this._error('Expected IRI to follow prefix "' + this._prefix + ':"', token); var prefixIRI = this._readEntity(token).id; this._prefixes[this._prefix] = prefixIRI; - this._prefixCallback(this._prefix, prefixIRI); + this._prefixCallback(this._prefix, new NamedNode(prefixIRI)); return this._readDeclarationPunctuation; }, diff --git a/test/N3Parser-test.js b/test/N3Parser-test.js index d0e0eb5c..b917b4db 100644 --- a/test/N3Parser-test.js +++ b/test/N3Parser-test.js @@ -2,6 +2,7 @@ var N3Parser = require('../N3').Parser; var DataFactory = require('../N3').DataFactory; var Term = DataFactory.Term, + NamedNode = DataFactory.NamedNode, Quad = DataFactory.Quad; var BASE_IRI = 'http://example.org/'; @@ -801,15 +802,17 @@ describe('N3Parser', function () { it('should return prefixes through a callback', function (done) { var prefixes = {}; - new N3Parser().parse('@prefix a: . a:a a:b a:c. @prefix b: .', + new N3Parser().parse('@prefix a: . a:a a:b a:c. @prefix b: .', tripleCallback, prefixCallback); function tripleCallback(error, triple) { expect(error).not.to.exist; if (!triple) { Object.keys(prefixes).should.have.length(2); - expect(prefixes).to.have.property('a', 'IRIa'); - expect(prefixes).to.have.property('b', 'IRIb'); + expect(prefixes).to.have.property('a'); + expect(prefixes.a).to.deep.equal(new NamedNode('http://a.org/#')); + expect(prefixes).to.have.property('b'); + expect(prefixes.b).to.deep.equal(new NamedNode('http://b.org/#')); done(); } } diff --git a/test/N3StreamParser-test.js b/test/N3StreamParser-test.js index 5b0e9cc3..99c11618 100644 --- a/test/N3StreamParser-test.js +++ b/test/N3StreamParser-test.js @@ -1,7 +1,8 @@ var N3StreamParser = require('../N3').StreamParser; var Readable = require('stream').Readable, - Writable = require('stream').Writable; + Writable = require('stream').Writable, + NamedNode = require('../N3').DataFactory.NamedNode; describe('N3StreamParser', function () { describe('The N3StreamParser module', function () { @@ -34,8 +35,8 @@ describe('N3StreamParser', function () { shouldNotParse(['z.'], 'Unexpected "z." on line 1.'), { token: undefined, line: 1, previousToken: undefined }); it('emits "prefix" events', - shouldEmitPrefixes(['@prefix a: . a:a a:b a:c. @prefix b: .'], - { a: 'IRIa', b: 'IRIb' })); + shouldEmitPrefixes(['@prefix a: . a:a a:b a:c. @prefix b: .'], + { a: new NamedNode('http://a.org/#'), b: new NamedNode('http://b.org/#') })); }); }); From 14e24cce2d2bdcf6c7667a943f2d5bac9046c26e Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Wed, 11 Apr 2018 21:37:16 +0200 Subject: [PATCH 29/34] Accept NamedNode prefixes in writer. --- lib/N3Writer.js | 2 ++ test/N3StreamWriter-test.js | 5 +++-- test/N3Writer-test.js | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/N3Writer.js b/lib/N3Writer.js index a66e99e5..cc51e6be 100644 --- a/lib/N3Writer.js +++ b/lib/N3Writer.js @@ -198,6 +198,8 @@ N3Writer.prototype = { for (var prefix in prefixes) { // Verify whether the prefix can be used and does not exist yet var iri = prefixes[prefix]; + if (typeof iri !== 'string') + iri = iri.value; if (/[#\/]$/.test(iri) && prefixIRIs[iri] !== (prefix += ':')) { hasPrefixes = true; prefixIRIs[iri] = prefix; diff --git a/test/N3StreamWriter-test.js b/test/N3StreamWriter-test.js index ab9fae87..272d1c05 100644 --- a/test/N3StreamWriter-test.js +++ b/test/N3StreamWriter-test.js @@ -4,7 +4,8 @@ var Readable = require('stream').Readable, Writable = require('stream').Writable, DataFactory = require('../N3').DataFactory; var Term = DataFactory.Term, - Quad = DataFactory.Quad; + Quad = DataFactory.Quad, + NamedNode = DataFactory.NamedNode; describe('N3StreamWriter', function () { describe('The N3StreamWriter module', function () { @@ -44,7 +45,7 @@ describe('N3StreamWriter', function () { ' .\n')); it('should use prefixes when possible', - shouldSerialize({ prefixes: { a: 'http://a.org/', b: 'http://a.org/b#', c: 'http://a.org/b' } }, + shouldSerialize({ prefixes: { a: 'http://a.org/', b: new NamedNode('http://a.org/b#'), c: 'http://a.org/b' } }, ['http://a.org/bc', 'http://a.org/b#ef', 'http://a.org/bhi'], ['http://a.org/bc/de', 'http://a.org/b#e#f', 'http://a.org/b#x/t'], ['http://a.org/3a', 'http://a.org/b#3a', 'http://a.org/b#a3'], diff --git a/test/N3Writer-test.js b/test/N3Writer-test.js index 1c7cb66a..d3fee928 100644 --- a/test/N3Writer-test.js +++ b/test/N3Writer-test.js @@ -133,7 +133,7 @@ describe('N3Writer', function () { ' .\n')); it('should serialize valid prefixes', - shouldSerialize({ prefixes: { a: 'http://a.org/', b: 'http://a.org/b#', c: 'http://a.org/b' } }, + shouldSerialize({ prefixes: { a: 'http://a.org/', b: new NamedNode('http://a.org/b#'), c: 'http://a.org/b' } }, '@prefix a: .\n' + '@prefix b: .\n\n')); From 07591acbe67252062c26005a9c682477f58ba1ce Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Wed, 11 Apr 2018 22:04:38 +0200 Subject: [PATCH 30/34] Add import method to stream reader and writer. Adds compatibility with the RDF/JS Sink interface. --- lib/N3StreamParser.js | 10 +++++++- lib/N3StreamWriter.js | 12 ++++++++-- test/N3StreamParser-test.js | 46 ++++++++++++++++++++++--------------- test/N3StreamWriter-test.js | 20 ++++++++++++---- 4 files changed, 62 insertions(+), 26 deletions(-) diff --git a/lib/N3StreamParser.js b/lib/N3StreamParser.js index b0ffc669..ea4abdd0 100644 --- a/lib/N3StreamParser.js +++ b/lib/N3StreamParser.js @@ -1,4 +1,4 @@ -// **N3StreamParser** parses an N3 stream into a triple stream. +// **N3StreamParser** parses a text stream into a quad stream. var Transform = require('stream').Transform, util = require('util'), N3Parser = require('./N3Parser.js'); @@ -34,5 +34,13 @@ function N3StreamParser(options) { } util.inherits(N3StreamParser, Transform); +// ### Parses a stream of strings +N3StreamParser.prototype.import = function (stream) { + var self = this; + stream.on('data', function (chunk) { self.write(chunk); }); + stream.on('end', function () { self.end(); }); + stream.on('error', function (error) { self.emit('error', error); }); +}; + // ## Exports module.exports = N3StreamParser; diff --git a/lib/N3StreamWriter.js b/lib/N3StreamWriter.js index add623ce..1c11720d 100644 --- a/lib/N3StreamWriter.js +++ b/lib/N3StreamWriter.js @@ -1,4 +1,4 @@ -// **N3StreamWriter** serializes a triple stream into an N3 stream. +// **N3StreamWriter** serializes a quad stream into a text stream. var Transform = require('stream').Transform, util = require('util'), N3Writer = require('./N3Writer.js'); @@ -15,7 +15,7 @@ function N3StreamWriter(options) { // Set up writer with a dummy stream object var self = this; var writer = new N3Writer({ - write: function (chunk, encoding, callback) { self.push(chunk); callback && callback(); }, + write: function (quad, encoding, callback) { self.push(quad); callback && callback(); }, end: function (callback) { self.push(null); callback && callback(); }, }, options); @@ -25,5 +25,13 @@ function N3StreamWriter(options) { } util.inherits(N3StreamWriter, Transform); +// ### Serializes a stream of quads +N3StreamWriter.prototype.import = function (stream) { + var self = this; + stream.on('data', function (quad) { self.write(quad); }); + stream.on('end', function () { self.end(); }); + stream.on('error', function (error) { self.emit('error', error); }); +}; + // ## Exports module.exports = N3StreamWriter; diff --git a/test/N3StreamParser-test.js b/test/N3StreamParser-test.js index 99c11618..49634db7 100644 --- a/test/N3StreamParser-test.js +++ b/test/N3StreamParser-test.js @@ -37,6 +37,16 @@ describe('N3StreamParser', function () { it('emits "prefix" events', shouldEmitPrefixes(['@prefix a: . a:a a:b a:c. @prefix b: .'], { a: new NamedNode('http://a.org/#'), b: new NamedNode('http://b.org/#') })); + + it('passes an error', function () { + var input = new Readable(), + parser = new N3StreamParser(), + error = null; + parser.on('error', function (e) { error = e; }); + parser.import(input); + input.emit('error', new Error()); + expect(error).to.be.an.instanceof(Error); + }); }); }); @@ -45,12 +55,12 @@ function shouldParse(chunks, expectedLength) { return function (done) { var triples = [], inputStream = new ArrayReader(chunks), - outputStream = new ArrayWriter(triples), - transform = new N3StreamParser(); - inputStream.pipe(transform); - transform.pipe(outputStream); - transform.on('error', done); - transform.on('end', function () { + parser = new N3StreamParser(), + outputStream = new ArrayWriter(triples); + parser.import(inputStream); + parser.pipe(outputStream); + parser.on('error', done); + parser.on('end', function () { triples.should.have.length(expectedLength); done(); }); @@ -60,11 +70,11 @@ function shouldParse(chunks, expectedLength) { function shouldNotParse(chunks, expectedMessage, expectedContext) { return function (done) { var inputStream = new ArrayReader(chunks), - outputStream = new ArrayWriter([]), - transform = N3StreamParser(); - inputStream.pipe(transform); - transform.pipe(outputStream); - transform.on('error', function (error) { + parser = N3StreamParser(), + outputStream = new ArrayWriter([]); + inputStream.pipe(parser); + parser.pipe(outputStream); + parser.on('error', function (error) { error.should.be.an.instanceof(Error); error.message.should.equal(expectedMessage); if (expectedContext) error.context.should.deep.equal(expectedContext); @@ -76,13 +86,13 @@ function shouldNotParse(chunks, expectedMessage, expectedContext) { function shouldEmitPrefixes(chunks, expectedPrefixes) { return function (done) { var prefixes = {}, - inputStream = new ArrayReader(chunks), - transform = N3StreamParser(); - inputStream.pipe(transform); - transform.on('data', function () {}); - transform.on('prefix', function (prefix, iri) { prefixes[prefix] = iri; }); - transform.on('error', done); - transform.on('end', function (error) { + parser = N3StreamParser(), + inputStream = new ArrayReader(chunks); + inputStream.pipe(parser); + parser.on('data', function () {}); + parser.on('prefix', function (prefix, iri) { prefixes[prefix] = iri; }); + parser.on('error', done); + parser.on('end', function (error) { prefixes.should.deep.equal(expectedPrefixes); done(error); }); diff --git a/test/N3StreamWriter-test.js b/test/N3StreamWriter-test.js index 272d1c05..c4ac0c99 100644 --- a/test/N3StreamWriter-test.js +++ b/test/N3StreamWriter-test.js @@ -55,6 +55,16 @@ describe('N3StreamWriter', function () { ' .\n' + ' b:a3.\n')); }); + + it('passes an error', function () { + var input = new Readable(), + writer = new N3StreamWriter(), + error = null; + writer.on('error', function (e) { error = e; }); + writer.import(input); + input.emit('error', new Error()); + expect(error).to.be.an.instanceof(Error); + }); }); @@ -65,12 +75,12 @@ function shouldSerialize(/* options?, tripleArrays..., expectedResult */) { return function (done) { var inputStream = new ArrayReader(tripleArrays), - transform = new N3StreamWriter(options), + writer = new N3StreamWriter(options), outputStream = new StringWriter(); - inputStream.pipe(transform); - transform.pipe(outputStream); - transform.on('error', done); - transform.on('end', function () { + writer.import(inputStream); + writer.pipe(outputStream); + writer.on('error', done); + writer.on('end', function () { outputStream.result.should.equal(expectedResult); done(); }); From a435548d1debaa5dff98bf4c9aeecf2723c2e3be Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Wed, 11 Apr 2018 22:27:43 +0200 Subject: [PATCH 31/34] Add import and remove methods to store. Adds compatibility with the RDF/JS Sink interface. --- lib/N3Store.js | 14 ++++++++++++++ test/N3Store-test.js | 35 ++++++++++++++++++++++++++++++++++- test/N3StreamWriter-test.js | 5 ++++- 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/lib/N3Store.js b/lib/N3Store.js index 2af7ef45..e5e2a258 100644 --- a/lib/N3Store.js +++ b/lib/N3Store.js @@ -259,6 +259,13 @@ N3Store.prototype = { this.addTriple(triples[i]); }, + // ### `import` adds a stream of quads to the store + import: function (stream) { + var self = this; + stream.on('data', function (quad) { self.addTriple(quad); }); + return stream; + }, + // ### `removeTriple` removes a triple from the store if it exists removeTriple: function (subject, predicate, object, graph) { // Shift arguments if a triple object is given instead of components @@ -300,6 +307,13 @@ N3Store.prototype = { this.removeTriple(triples[i]); }, + // ### `remove` removes a stream of quads from the store + remove: function (stream) { + var self = this; + stream.on('data', function (quad) { self.removeTriple(quad); }); + return stream; + }, + // ### `getTriples` returns an array of triples matching a pattern. // Setting any field to `undefined` or `null` indicates a wildcard. getTriples: function (subject, predicate, object, graph) { diff --git a/test/N3Store-test.js b/test/N3Store-test.js index 94c0f923..8a84535a 100644 --- a/test/N3Store-test.js +++ b/test/N3Store-test.js @@ -1,6 +1,7 @@ var N3Store = require('../N3').Store; -var DataFactory = require('../N3').DataFactory; +var Readable = require('stream').Readable, + DataFactory = require('../N3').DataFactory; var Term = DataFactory.Term, NamedNode = DataFactory.NamedNode, DefaultGraph = DataFactory.DefaultGraph, @@ -33,6 +34,32 @@ describe('N3Store', function () { store.getTriples().should.be.empty; }); + describe('when importing a stream of 2 quads', function () { + before(function (done) { + var stream = new ArrayReader([ + new Triple(new NamedNode('s1'), new NamedNode('p2'), new NamedNode('o2')), + new Triple(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o1')), + ]); + var events = store.import(stream); + events.on('end', done); + }); + + it('should have size 2', function () { store.size.should.eql(2); }); + }); + + describe('when removing a stream of 2 quads', function () { + before(function (done) { + var stream = new ArrayReader([ + new Triple(new NamedNode('s1'), new NamedNode('p2'), new NamedNode('o2')), + new Triple(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o1')), + ]); + var events = store.remove(stream); + events.on('end', done); + }); + + it('should have size 0', function () { store.size.should.eql(0); }); + }); + describe('every', function () { describe('with no parameters and a callback always returning true', function () { it('should return false', function () { @@ -1015,3 +1042,9 @@ function shouldIncludeAll(result) { result.should.include.something.that.deep.equals(items[i].toJSON()); }; } + +function ArrayReader(items) { + var reader = new Readable({ objectMode: true }); + reader._read = function () { this.push(items.shift() || null); }; + return reader; +} diff --git a/test/N3StreamWriter-test.js b/test/N3StreamWriter-test.js index c4ac0c99..e6acf27b 100644 --- a/test/N3StreamWriter-test.js +++ b/test/N3StreamWriter-test.js @@ -73,6 +73,10 @@ function shouldSerialize(/* options?, tripleArrays..., expectedResult */) { expectedResult = tripleArrays.pop(), options = tripleArrays[0] instanceof Array ? null : tripleArrays.shift(); + tripleArrays = tripleArrays.map(function (i) { + return new Quad(Term.fromId(i[0]), Term.fromId(i[1]), Term.fromId(i[2])); + }); + return function (done) { var inputStream = new ArrayReader(tripleArrays), writer = new N3StreamWriter(options), @@ -89,7 +93,6 @@ function shouldSerialize(/* options?, tripleArrays..., expectedResult */) { function ArrayReader(items) { var reader = new Readable({ objectMode: true }); - items = items.map(function (i) { return new Quad(Term.fromId(i[0]), Term.fromId(i[1]), Term.fromId(i[2])); }); reader._read = function () { this.push(items.shift() || null); }; return reader; } From b8f621ba93dcca6ed830452ab39f531333d8970d Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Wed, 11 Apr 2018 22:35:30 +0200 Subject: [PATCH 32/34] Remove browser version generation. It's up to webpack or browserify to do that. --- .travis.yml | 1 - appveyor.yml | 1 - browser/build-browser-versions | 74 --- package-lock.json | 1092 -------------------------------- package.json | 18 +- 5 files changed, 1 insertion(+), 1185 deletions(-) delete mode 100755 browser/build-browser-versions diff --git a/.travis.yml b/.travis.yml index babd1729..25410c4f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,7 +30,6 @@ script: - npm run lint - npm test - npm run spec - - npm run browser - npm run docs after_success: - npm run coveralls diff --git a/appveyor.yml b/appveyor.yml index 66b96544..04eb06b4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -13,7 +13,6 @@ test_script: - npm --version - npm run lint - npm test - - npm run browser cache: - node_modules diff --git a/browser/build-browser-versions b/browser/build-browser-versions deleted file mode 100755 index c533a088..00000000 --- a/browser/build-browser-versions +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env node -/* build-browser-versions.js builds a browserify version and a minimal browser version */ -var fs = require('fs'), - path = require('path'), - spawn = require('cross-spawn').spawn; - -// Modules to be included in the minimal browser version -var submodules = [ - 'Util', - 'Lexer', - 'Parser', - 'Writer', - 'Store', -]; - - -/* Set up paths */ -var rootPath = path.join(__dirname, '../'), - sourcePath = path.join(rootPath, 'lib/'), - destinationPath = path.join(rootPath, 'browser/'), - uglifyjsPath = path.join(rootPath, 'node_modules/.bin/uglifyjs'), - browserifyPath = path.join(rootPath, 'node_modules/.bin/browserify'); - -if (!fs.existsSync(destinationPath)) - fs.mkdirSync(destinationPath); - - -/* Create minimal browser version */ - -var scriptFile = destinationPath + 'n3-browser.js', - minifiedFile = destinationPath + 'n3-browser.min.js', - script = fs.createWriteStream(scriptFile, { encoding: 'utf8' }); - -// Add license information -var package = JSON.parse(fs.readFileSync(path.join(rootPath, 'package.json'))); -script.write('/** @license MIT - N3.js ' + package.version + - ' (browser build) - ©Ruben Verborgh */\n'); - -// Start main wrapping function -script.write('(function (N3) {\n'); - -// Add modules -submodules.forEach(function (name) { - var submodule = fs.readFileSync(sourcePath + 'N3' + name + '.js', { encoding: 'utf8' }); - // Remove imports - submodule = submodule.replace(/require\(['"]\.\/N3([^'"]+)['"]\)/g, 'N3.$1'); - // Replace exports by assignments on the N3 object - submodule = submodule.replace(/module.exports/g, '\nN3.' + name); - script.write('(function () {\n' + submodule + '\n})();\n'); -}); - -// End and execute main wrapping function -script.write('})(typeof exports !== "undefined" ? exports : this.N3 = {});\n'); -script.end(function () { - console.log('minimal browser version written to', scriptFile); - // Write minified file - var minifier = spawn(uglifyjsPath, - [ scriptFile, '--comments', '-m', '-c', '-o', minifiedFile ], - { stdio: 'inherit' }); - minifier.on('exit', function () { - console.log('minimal browser version (minified) written to', minifiedFile); - }); -}); - - -/* Build browserify version */ - -var browserifiedFile = destinationPath + 'n3-browserify.js', - browserify = spawn(browserifyPath, - [ rootPath + 'N3.js', '-s', 'N3', '-o', browserifiedFile ], - { stdio: 'inherit' }); -browserify.on('exit', function () { - console.log('browserify version written to', browserifiedFile); -}); diff --git a/package-lock.json b/package-lock.json index 1afbfbd7..cab8d70c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,22 +4,6 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "JSONStream": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.2.tgz", - "integrity": "sha1-wQI3G27Dp887hHygDCC7D85Mbeo=", - "dev": true, - "requires": { - "jsonparse": "1.3.1", - "through": "2.3.8" - } - }, - "acorn": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", - "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", - "dev": true - }, "acorn-jsx": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", @@ -37,24 +21,6 @@ } } }, - "acorn-node": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.3.0.tgz", - "integrity": "sha512-efP54n3d1aLfjL2UMdaXa6DsswwzJeI5rqhbFvXMrKiJ6eJFpf+7R0zN7t8IC+XKn2YOAFAv6xbBNgHUkoHWLw==", - "dev": true, - "requires": { - "acorn": "5.5.3", - "xtend": "4.0.1" - }, - "dependencies": { - "acorn": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.5.3.tgz", - "integrity": "sha512-jd5MkIUlbbmb07nXH0DT3y7rDVtkzDi4XZOUVWAer8ajmF/DTSSbl5oNFyDOl/OXA33Bl79+ypHhl2pN20VeOQ==", - "dev": true - } - } - }, "ajv": { "version": "5.5.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", @@ -100,24 +66,6 @@ "sprintf-js": "1.0.3" } }, - "array-filter": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", - "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=", - "dev": true - }, - "array-map": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", - "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=", - "dev": true - }, - "array-reduce": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", - "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=", - "dev": true - }, "array-union": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", @@ -145,26 +93,6 @@ "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", "dev": true }, - "asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", - "dev": true, - "requires": { - "bn.js": "4.11.8", - "inherits": "2.0.3", - "minimalistic-assert": "1.0.0" - } - }, - "assert": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", - "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", - "dev": true, - "requires": { - "util": "0.10.3" - } - }, "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", @@ -177,15 +105,6 @@ "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true }, - "astw": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/astw/-/astw-2.2.0.tgz", - "integrity": "sha1-e9QXhNMkk5h66yOba04cV6hzuRc=", - "dev": true, - "requires": { - "acorn": "4.0.13" - } - }, "async": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", @@ -254,12 +173,6 @@ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, - "base64-js": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.3.tgz", - "integrity": "sha512-MsAhsUW1GxCdgYSO6tAfZrNapmUKk7mWx/k5mFY/A1gBtkaCaNapTg+FExCw1r9yeaZhqx/xPg43xgTFH6KL5w==", - "dev": true - }, "bcrypt-pbkdf": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", @@ -270,12 +183,6 @@ "tweetnacl": "0.14.5" } }, - "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", - "dev": true - }, "boom": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", @@ -295,209 +202,18 @@ "concat-map": "0.0.1" } }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", - "dev": true - }, - "browser-pack": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.0.4.tgz", - "integrity": "sha512-Q4Rvn7P6ObyWfc4stqLWHtG1MJ8vVtjgT24Zbu+8UTzxYuZouqZsmNRRTFVMY/Ux0eIKv1d+JWzsInTX+fdHPQ==", - "dev": true, - "requires": { - "JSONStream": "1.3.2", - "combine-source-map": "0.8.0", - "defined": "1.0.0", - "safe-buffer": "5.1.1", - "through2": "2.0.3", - "umd": "3.0.3" - } - }, - "browser-resolve": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz", - "integrity": "sha1-j/CbCixCFxihBRwmCzLkj0QpOM4=", - "dev": true, - "requires": { - "resolve": "1.1.7" - }, - "dependencies": { - "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", - "dev": true - } - } - }, "browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, - "browserify": { - "version": "16.1.1", - "resolved": "https://registry.npmjs.org/browserify/-/browserify-16.1.1.tgz", - "integrity": "sha512-iSH21jK0+IApV8YHOfmGt1qsGd74oflQ1Ko/28JOkWLFNBngAQfKb6WYIJ9CufH8vycqKX1sYU3y7ZrVhwevAg==", - "dev": true, - "requires": { - "JSONStream": "1.3.2", - "assert": "1.4.1", - "browser-pack": "6.0.4", - "browser-resolve": "1.11.2", - "browserify-zlib": "0.2.0", - "buffer": "5.1.0", - "cached-path-relative": "1.0.1", - "concat-stream": "1.6.2", - "console-browserify": "1.1.0", - "constants-browserify": "1.0.0", - "crypto-browserify": "3.12.0", - "defined": "1.0.0", - "deps-sort": "2.0.0", - "domain-browser": "1.2.0", - "duplexer2": "0.1.4", - "events": "2.0.0", - "glob": "7.1.2", - "has": "1.0.1", - "htmlescape": "1.1.1", - "https-browserify": "1.0.0", - "inherits": "2.0.3", - "insert-module-globals": "7.0.4", - "labeled-stream-splicer": "2.0.1", - "mkdirp": "0.5.1", - "module-deps": "6.0.0", - "os-browserify": "0.3.0", - "parents": "1.0.1", - "path-browserify": "0.0.0", - "process": "0.11.10", - "punycode": "1.4.1", - "querystring-es3": "0.2.1", - "read-only-stream": "2.0.0", - "readable-stream": "2.3.5", - "resolve": "1.6.0", - "shasum": "1.0.2", - "shell-quote": "1.6.1", - "stream-browserify": "2.0.1", - "stream-http": "2.8.1", - "string_decoder": "1.0.3", - "subarg": "1.0.0", - "syntax-error": "1.4.0", - "through2": "2.0.3", - "timers-browserify": "1.4.2", - "tty-browserify": "0.0.1", - "url": "0.11.0", - "util": "0.10.3", - "vm-browserify": "0.0.4", - "xtend": "4.0.1" - } - }, - "browserify-aes": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.1.1.tgz", - "integrity": "sha512-UGnTYAnB2a3YuYKIRy1/4FB2HdM866E0qC46JXvVTYKlBlZlnvfpSfY6OKfXZAkv70eJ2a1SqzpAo5CRhZGDFg==", - "dev": true, - "requires": { - "buffer-xor": "1.0.3", - "cipher-base": "1.0.4", - "create-hash": "1.1.3", - "evp_bytestokey": "1.0.3", - "inherits": "2.0.3", - "safe-buffer": "5.1.1" - } - }, - "browserify-cipher": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.0.tgz", - "integrity": "sha1-mYgkSHS/XtTijalWZtzWasj8Njo=", - "dev": true, - "requires": { - "browserify-aes": "1.1.1", - "browserify-des": "1.0.0", - "evp_bytestokey": "1.0.3" - } - }, - "browserify-des": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.0.tgz", - "integrity": "sha1-2qJ3cXRwki7S/hhZQRihdUOXId0=", - "dev": true, - "requires": { - "cipher-base": "1.0.4", - "des.js": "1.0.0", - "inherits": "2.0.3" - } - }, - "browserify-rsa": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", - "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", - "dev": true, - "requires": { - "bn.js": "4.11.8", - "randombytes": "2.0.6" - } - }, - "browserify-sign": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", - "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", - "dev": true, - "requires": { - "bn.js": "4.11.8", - "browserify-rsa": "4.0.1", - "create-hash": "1.1.3", - "create-hmac": "1.1.6", - "elliptic": "6.4.0", - "inherits": "2.0.3", - "parse-asn1": "5.1.0" - } - }, - "browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", - "dev": true, - "requires": { - "pako": "1.0.6" - } - }, - "buffer": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.1.0.tgz", - "integrity": "sha512-YkIRgwsZwJWTnyQrsBTWefizHh+8GYj3kbL1BTiAQ/9pwpino0G7B2gp5tx/FUBqUlvtxV85KNR3mwfAtv15Yw==", - "dev": true, - "requires": { - "base64-js": "1.2.3", - "ieee754": "1.1.10" - } - }, "buffer-from": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz", "integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA==", "dev": true }, - "buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", - "dev": true - }, - "builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", - "dev": true - }, - "cached-path-relative": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.1.tgz", - "integrity": "sha1-0JxLUoAKpMB44t2BqGmqyQ0uVOc=", - "dev": true - }, "caller-path": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", @@ -582,16 +298,6 @@ "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", "dev": true }, - "cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "dev": true, - "requires": { - "inherits": "2.0.3", - "safe-buffer": "5.1.1" - } - }, "circular-json": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", @@ -640,18 +346,6 @@ "integrity": "sha512-s8+wktIuDSLffCywiwSxQOMqtPxML11a/dtHE17tMn4B1MSWw/C22EKf7M2KGUBcDaVFEGT+S8N02geDXeuNKg==", "dev": true }, - "combine-source-map": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz", - "integrity": "sha1-pY0N8ELBhvz4IqjoAV9UUNLXmos=", - "dev": true, - "requires": { - "convert-source-map": "1.1.3", - "inline-source-map": "0.6.2", - "lodash.memoize": "3.0.4", - "source-map": "0.5.7" - } - }, "combined-stream": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", @@ -685,27 +379,6 @@ "typedarray": "0.0.6" } }, - "console-browserify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", - "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", - "dev": true, - "requires": { - "date-now": "0.1.4" - } - }, - "constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", - "dev": true - }, - "convert-source-map": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", - "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=", - "dev": true - }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -725,55 +398,6 @@ "request": "2.85.0" } }, - "create-ecdh": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz", - "integrity": "sha1-iIxyNZbN92EvZJgjPuvXo1MBc30=", - "dev": true, - "requires": { - "bn.js": "4.11.8", - "elliptic": "6.4.0" - } - }, - "create-hash": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz", - "integrity": "sha1-YGBCrIuSYnUPSDyt2rD1gZFy2P0=", - "dev": true, - "requires": { - "cipher-base": "1.0.4", - "inherits": "2.0.3", - "ripemd160": "2.0.1", - "sha.js": "2.4.11" - } - }, - "create-hmac": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.6.tgz", - "integrity": "sha1-rLniIaThe9sHbpBlfEK5PjcmzwY=", - "dev": true, - "requires": { - "cipher-base": "1.0.4", - "create-hash": "1.1.3", - "inherits": "2.0.3", - "ripemd160": "2.0.1", - "safe-buffer": "5.1.1", - "sha.js": "2.4.11" - } - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "1.0.4", - "path-key": "2.0.1", - "semver": "5.5.0", - "shebang-command": "1.2.0", - "which": "1.3.0" - } - }, "cryptiles": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", @@ -794,25 +418,6 @@ } } }, - "crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "dev": true, - "requires": { - "browserify-cipher": "1.0.0", - "browserify-sign": "4.0.4", - "create-ecdh": "4.0.0", - "create-hash": "1.1.3", - "create-hmac": "1.1.6", - "diffie-hellman": "5.0.2", - "inherits": "2.0.3", - "pbkdf2": "3.0.14", - "public-encrypt": "4.0.0", - "randombytes": "2.0.6", - "randomfill": "1.0.4" - } - }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -822,12 +427,6 @@ "assert-plus": "1.0.0" } }, - "date-now": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", - "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", - "dev": true - }, "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", @@ -852,12 +451,6 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, - "defined": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", - "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", - "dev": true - }, "del": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", @@ -879,56 +472,12 @@ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "dev": true }, - "deps-sort": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.0.tgz", - "integrity": "sha1-CRckkC6EZYJg65EHSMzNGvbiH7U=", - "dev": true, - "requires": { - "JSONStream": "1.3.2", - "shasum": "1.0.2", - "subarg": "1.0.0", - "through2": "2.0.3" - } - }, - "des.js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", - "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", - "dev": true, - "requires": { - "inherits": "2.0.3", - "minimalistic-assert": "1.0.0" - } - }, - "detective": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/detective/-/detective-5.1.0.tgz", - "integrity": "sha512-TFHMqfOvxlgrfVzTEkNBSh9SvSNX/HfF4OFI2QFGCyPm02EsyILqnUeb5P6q7JZ3SFNTBL5t2sePRgrN4epUWQ==", - "dev": true, - "requires": { - "acorn-node": "1.3.0", - "defined": "1.0.0", - "minimist": "1.2.0" - } - }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", "dev": true }, - "diffie-hellman": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.2.tgz", - "integrity": "sha1-tYNXOScM/ias9jIJn97SoH8gnl4=", - "dev": true, - "requires": { - "bn.js": "4.11.8", - "miller-rabin": "4.0.1", - "randombytes": "2.0.6" - } - }, "docco": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/docco/-/docco-0.7.0.tgz", @@ -951,21 +500,6 @@ "esutils": "2.0.2" } }, - "domain-browser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", - "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", - "dev": true - }, - "duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", - "dev": true, - "requires": { - "readable-stream": "2.3.5" - } - }, "ecc-jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", @@ -976,21 +510,6 @@ "jsbn": "0.1.1" } }, - "elliptic": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", - "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", - "dev": true, - "requires": { - "bn.js": "4.11.8", - "brorand": "1.1.0", - "hash.js": "1.1.3", - "hmac-drbg": "1.0.1", - "inherits": "2.0.3", - "minimalistic-assert": "1.0.0", - "minimalistic-crypto-utils": "1.0.1" - } - }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -1126,22 +645,6 @@ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, - "events": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/events/-/events-2.0.0.tgz", - "integrity": "sha512-r/M5YkNg9zwI8QbSf7tsDWWJvO3PGwZXyG7GpFAxtMASnHL2eblFd7iHiGPtyGKKFPZ59S63NeX10Ws6WqGDcg==", - "dev": true - }, - "evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "dev": true, - "requires": { - "md5.js": "1.3.4", - "safe-buffer": "5.1.1" - } - }, "extend": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", @@ -1248,12 +751,6 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, "functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", @@ -1337,15 +834,6 @@ "har-schema": "2.0.0" } }, - "has": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", - "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", - "dev": true, - "requires": { - "function-bind": "1.1.1" - } - }, "has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", @@ -1361,25 +849,6 @@ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, - "hash-base": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz", - "integrity": "sha1-ZuodhW206KVHDK32/OI65SRO8uE=", - "dev": true, - "requires": { - "inherits": "2.0.3" - } - }, - "hash.js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", - "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", - "dev": true, - "requires": { - "inherits": "2.0.3", - "minimalistic-assert": "1.0.0" - } - }, "hawk": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", @@ -1404,29 +873,12 @@ "integrity": "sha1-5tnb5Xy+/mB1HwKvM2GVhwyQwB4=", "dev": true }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "dev": true, - "requires": { - "hash.js": "1.1.3", - "minimalistic-assert": "1.0.0", - "minimalistic-crypto-utils": "1.0.1" - } - }, "hoek": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==", "dev": true }, - "htmlescape": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", - "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=", - "dev": true - }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -1438,24 +890,12 @@ "sshpk": "1.14.1" } }, - "https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", - "dev": true - }, "iconv-lite": { "version": "0.4.19", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", "dev": true }, - "ieee754": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.10.tgz", - "integrity": "sha512-byWFX8OyW/qeVxcY21r6Ncxl0ZYHgnf0cPup2h34eHXrCJbOp7IuqnJ4Q0omfyWl6Z++BTI6bByf31pZt7iRLg==", - "dev": true - }, "ignore": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.7.tgz", @@ -1468,12 +908,6 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, - "indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", - "dev": true - }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -1490,15 +924,6 @@ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, - "inline-source-map": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz", - "integrity": "sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=", - "dev": true, - "requires": { - "source-map": "0.5.7" - } - }, "inquirer": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", @@ -1521,42 +946,6 @@ "through": "2.3.8" } }, - "insert-module-globals": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.0.4.tgz", - "integrity": "sha512-Z/sfx2KOKyHQ3U4X3fnXn4Ms1Opa9pGvEfm8j6xKHE6oVqc1dMwVgBVxmj3yIrMtWTl8HYoy12rkhrR8MYym6A==", - "dev": true, - "requires": { - "JSONStream": "1.3.2", - "combine-source-map": "0.7.2", - "concat-stream": "1.6.2", - "is-buffer": "1.1.6", - "lexical-scope": "1.2.0", - "process": "0.11.10", - "through2": "2.0.3", - "xtend": "4.0.1" - }, - "dependencies": { - "combine-source-map": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.7.2.tgz", - "integrity": "sha1-CHAxKFazB6h8xKxIbzqaYq7MwJ4=", - "dev": true, - "requires": { - "convert-source-map": "1.1.3", - "inline-source-map": "0.6.2", - "lodash.memoize": "3.0.4", - "source-map": "0.5.7" - } - } - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", @@ -1658,15 +1047,6 @@ "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", "dev": true }, - "json-stable-stringify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz", - "integrity": "sha1-YRwj6BTbN1Un34URk9tZ3Sryf0U=", - "dev": true, - "requires": { - "jsonify": "0.0.0" - } - }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", @@ -1688,18 +1068,6 @@ "graceful-fs": "4.1.11" } }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", - "dev": true - }, - "jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", - "dev": true - }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -1712,25 +1080,6 @@ "verror": "1.10.0" } }, - "labeled-stream-splicer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.1.tgz", - "integrity": "sha512-MC94mHZRvJ3LfykJlTUipBqenZz1pacOZEMhhQ8dMGcDHs0SBE5GbsavUXV7YtP3icBW17W0Zy1I0lfASmo9Pg==", - "dev": true, - "requires": { - "inherits": "2.0.3", - "isarray": "2.0.4", - "stream-splicer": "2.0.0" - }, - "dependencies": { - "isarray": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.4.tgz", - "integrity": "sha512-GMxXOiUirWg1xTKRipM0Ek07rX+ubx4nNVElTJdNLYmNO/2YrDkgJGw9CljXn+r4EWiDQg/8lsRdHyg2PJuUaA==", - "dev": true - } - } - }, "lcov-parse": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.10.tgz", @@ -1747,27 +1096,12 @@ "type-check": "0.3.2" } }, - "lexical-scope": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/lexical-scope/-/lexical-scope-1.2.0.tgz", - "integrity": "sha1-/Ope3HBKSzqHls3KQZw6CvryLfQ=", - "dev": true, - "requires": { - "astw": "2.2.0" - } - }, "lodash": { "version": "4.17.5", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==", "dev": true }, - "lodash.memoize": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", - "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=", - "dev": true - }, "log-driver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", @@ -1790,38 +1124,6 @@ "integrity": "sha512-+AKbNsjZl6jFfLPwHhWmGTqE009wTKn3RTmn9K8oUKHrX/abPJjtcRtXpYB/FFrwPJRUA86LX/de3T0knkPCmQ==", "dev": true }, - "md5.js": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", - "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", - "dev": true, - "requires": { - "hash-base": "3.0.4", - "inherits": "2.0.3" - }, - "dependencies": { - "hash-base": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", - "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", - "dev": true, - "requires": { - "inherits": "2.0.3", - "safe-buffer": "5.1.1" - } - } - } - }, - "miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "dev": true, - "requires": { - "bn.js": "4.11.8", - "brorand": "1.1.0" - } - }, "mime-db": { "version": "1.33.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", @@ -1843,18 +1145,6 @@ "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", "dev": true }, - "minimalistic-assert": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz", - "integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M=", - "dev": true - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", - "dev": true - }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -1928,29 +1218,6 @@ } } }, - "module-deps": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.0.0.tgz", - "integrity": "sha512-BKsMhJJENEM4dTgqq2MDTTHXRHcNUFegoAwlG4HO4VMdUyMcJDKgfgI+MOv6tR5Iv8G3MKZFgsSiyP3ZoosRMw==", - "dev": true, - "requires": { - "JSONStream": "1.3.2", - "browser-resolve": "1.11.2", - "cached-path-relative": "1.0.1", - "concat-stream": "1.6.2", - "defined": "1.0.0", - "detective": "5.1.0", - "duplexer2": "0.1.4", - "inherits": "2.0.3", - "parents": "1.0.1", - "readable-stream": "2.3.5", - "resolve": "1.6.0", - "stream-combiner2": "1.1.1", - "subarg": "1.0.0", - "through2": "2.0.3", - "xtend": "4.0.1" - } - }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -1969,12 +1236,6 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "nice-try": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz", - "integrity": "sha512-2NpiFHqC87y/zFke0fC0spBXL3bBsoh/p5H1EFhshxjCR5+0g2d6BiXbUFz9v1sAcxsk2htp2eQnNIci2dIYcA==", - "dev": true - }, "nyc": { "version": "11.6.0", "resolved": "https://registry.npmjs.org/nyc/-/nyc-11.6.0.tgz", @@ -4790,12 +4051,6 @@ "wordwrap": "1.0.0" } }, - "os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", - "dev": true - }, "os-shim": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz", @@ -4808,40 +4063,6 @@ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, - "pako": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", - "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==", - "dev": true - }, - "parents": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", - "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=", - "dev": true, - "requires": { - "path-platform": "0.11.15" - } - }, - "parse-asn1": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.0.tgz", - "integrity": "sha1-N8T5t+06tlx0gXtfJICTf7+XxxI=", - "dev": true, - "requires": { - "asn1.js": "4.10.1", - "browserify-aes": "1.1.1", - "create-hash": "1.1.3", - "evp_bytestokey": "1.0.3", - "pbkdf2": "3.0.14" - } - }, - "path-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", - "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", - "dev": true - }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -4854,43 +4075,12 @@ "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", "dev": true }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", - "dev": true - }, - "path-platform": { - "version": "0.11.15", - "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", - "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=", - "dev": true - }, "pathval": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", "dev": true }, - "pbkdf2": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.14.tgz", - "integrity": "sha512-gjsZW9O34fm0R7PaLHRJmLLVfSoesxztjPjE9o6R+qtVJij90ltg1joIovN9GKrRW3t1PzhDDG3UMEMFfZ+1wA==", - "dev": true, - "requires": { - "create-hash": "1.1.3", - "create-hmac": "1.1.6", - "ripemd160": "2.0.1", - "safe-buffer": "5.1.1", - "sha.js": "2.4.11" - } - }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -4963,12 +4153,6 @@ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", "dev": true }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", - "dev": true - }, "process-nextick-args": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", @@ -4987,19 +4171,6 @@ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, - "public-encrypt": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.0.tgz", - "integrity": "sha1-OfaZ86RlYN1eusvKaTyvfGXBjMY=", - "dev": true, - "requires": { - "bn.js": "4.11.8", - "browserify-rsa": "4.0.1", - "create-hash": "1.1.3", - "parse-asn1": "5.1.0", - "randombytes": "2.0.6" - } - }, "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", @@ -5012,46 +4183,6 @@ "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", "dev": true }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "dev": true - }, - "querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", - "dev": true - }, - "randombytes": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", - "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", - "dev": true, - "requires": { - "safe-buffer": "5.1.1" - } - }, - "randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "dev": true, - "requires": { - "randombytes": "2.0.6", - "safe-buffer": "5.1.1" - } - }, - "read-only-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", - "integrity": "sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=", - "dev": true, - "requires": { - "readable-stream": "2.3.5" - } - }, "readable-stream": { "version": "2.3.5", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.5.tgz", @@ -5113,15 +4244,6 @@ "resolve-from": "1.0.1" } }, - "resolve": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.6.0.tgz", - "integrity": "sha512-mw7JQNu5ExIkcw4LPih0owX/TZXjD/ZUF/ZQ/pDnkw3ZKhDcZZw5klmBlj6gVMwjQ3Pz5Jgu7F3d0jcDVuEWdw==", - "dev": true, - "requires": { - "path-parse": "1.0.5" - } - }, "resolve-from": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", @@ -5147,16 +4269,6 @@ "glob": "7.1.2" } }, - "ripemd160": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz", - "integrity": "sha1-D0WEKVxTo2KK9+bXmsohzlfRxuc=", - "dev": true, - "requires": { - "hash-base": "2.0.2", - "inherits": "2.0.3" - } - }, "run-async": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", @@ -5193,26 +4305,6 @@ "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", "dev": true }, - "sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dev": true, - "requires": { - "inherits": "2.0.3", - "safe-buffer": "5.1.1" - } - }, - "shasum": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz", - "integrity": "sha1-5wEjENj0F/TetXEhUOVni4euVl8=", - "dev": true, - "requires": { - "json-stable-stringify": "0.0.1", - "sha.js": "2.4.11" - } - }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -5228,18 +4320,6 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, - "shell-quote": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", - "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", - "dev": true, - "requires": { - "array-filter": "0.0.1", - "array-map": "0.0.0", - "array-reduce": "0.0.0", - "jsonify": "0.0.0" - } - }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", @@ -5264,12 +4344,6 @@ "hoek": "4.2.1" } }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, "spawn-sync": { "version": "1.0.15", "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz", @@ -5302,49 +4376,6 @@ "tweetnacl": "0.14.5" } }, - "stream-browserify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", - "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", - "dev": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.5" - } - }, - "stream-combiner2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", - "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", - "dev": true, - "requires": { - "duplexer2": "0.1.4", - "readable-stream": "2.3.5" - } - }, - "stream-http": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.1.tgz", - "integrity": "sha512-cQ0jo17BLca2r0GfRdZKYAGLU6JRoIWxqSOakUMuKOT6MOK7AAlE856L33QuDmAy/eeOrhLee3dZKX0Uadu93A==", - "dev": true, - "requires": { - "builtin-status-codes": "3.0.0", - "inherits": "2.0.3", - "readable-stream": "2.3.5", - "to-arraybuffer": "1.0.1", - "xtend": "4.0.1" - } - }, - "stream-splicer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.0.tgz", - "integrity": "sha1-G2O+Q4oTPktnHMGTUZdgAXWRDYM=", - "dev": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.5" - } - }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -5393,30 +4424,12 @@ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true }, - "subarg": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", - "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=", - "dev": true, - "requires": { - "minimist": "1.2.0" - } - }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true }, - "syntax-error": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", - "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", - "dev": true, - "requires": { - "acorn-node": "1.3.0" - } - }, "table": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", @@ -5443,25 +4456,6 @@ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, - "through2": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", - "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", - "dev": true, - "requires": { - "readable-stream": "2.3.5", - "xtend": "4.0.1" - } - }, - "timers-browserify": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", - "integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=", - "dev": true, - "requires": { - "process": "0.11.10" - } - }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -5471,12 +4465,6 @@ "os-tmpdir": "1.0.2" } }, - "to-arraybuffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", - "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", - "dev": true - }, "tough-cookie": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", @@ -5486,12 +4474,6 @@ "punycode": "1.4.1" } }, - "tty-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", - "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", - "dev": true - }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -5529,30 +4511,6 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, - "uglify-js": { - "version": "3.3.16", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.16.tgz", - "integrity": "sha512-FMh5SRqJRGhv9BbaTffENIpDDQIoPDR8DBraunGORGhySArsXlw9++CN+BWzPBLpoI4RcSnpfGPnilTxWL3Vvg==", - "dev": true, - "requires": { - "commander": "2.15.1", - "source-map": "0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "umd": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz", - "integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==", - "dev": true - }, "underscore": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", @@ -5565,41 +4523,6 @@ "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=", "dev": true }, - "url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "dev": true, - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", - "dev": true - } - } - }, - "util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", - "dev": true, - "requires": { - "inherits": "2.0.1" - }, - "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", - "dev": true - } - } - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -5623,15 +4546,6 @@ "extsprintf": "1.3.0" } }, - "vm-browserify": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", - "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", - "dev": true, - "requires": { - "indexof": "0.0.1" - } - }, "which": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", @@ -5662,12 +4576,6 @@ "mkdirp": "0.5.1" } }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", - "dev": true - }, "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", diff --git a/package.json b/package.json index 4b8a716c..b3f2c275 100644 --- a/package.json +++ b/package.json @@ -21,24 +21,20 @@ ], "devDependencies": { "async": "^2.0.1", - "browserify": "^16.1.0", "chai": "^4.0.2", "chai-things": "^0.2.0", "colors": "^1.1.2", "coveralls": "^3.0.0", - "cross-spawn": "^6.0.4", "docco": "^0.7.0", "eslint": "^4.1.1", "mocha": "^5.0.1", "nyc": "^11.0.3", "pre-commit": "^1.2.2", - "request": "^2.74.0", - "uglify-js": "^3.0.24" + "request": "^2.74.0" }, "scripts": { "test": "nyc mocha", "lint": "eslint lib perf test spec", - "browser": "node browser/build-browser-versions", "coveralls": "nyc --reporter=text-lcov mocha | coveralls", "spec": "node spec/turtle-spec && node spec/trig-spec && node spec/ntriples-spec && node spec/nquads-spec", "spec-clean": "rm -r spec/turtle spec/trig", @@ -51,18 +47,6 @@ "bugs": { "url": "https://github.com/RubenVerborgh/N3.js/issues" }, - "testling": { - "files": "test/*.js", - "harness": "mocha", - "browsers": [ - "ie/9..latest", - "firefox/24..latest", - "chrome/29..latest", - "safari/6..latest", - "iphone/6..latest", - "ipad/6..latest" - ] - }, "pre-commit": [ "lint", "test" From 2a942e314fe651c45fe8b59f71ceab6683f4efb4 Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Thu, 12 Apr 2018 00:04:19 +0200 Subject: [PATCH 33/34] Update README for RDF/JS. --- README.md | 415 +++++++++++++++++++++++------------------------------- 1 file changed, 177 insertions(+), 238 deletions(-) diff --git a/README.md b/README.md index e94f6ef6..975b3197 100644 --- a/README.md +++ b/README.md @@ -1,129 +1,81 @@ # Lightning fast, asynchronous, streaming RDF for JavaScript [![Build Status](https://travis-ci.org/RubenVerborgh/N3.js.svg?branch=master)](https://travis-ci.org/RubenVerborgh/N3.js) -[![Build status](https://ci.appveyor.com/api/projects/status/ede443yeiq3syhyg/branch/master?svg=true)](https://ci.appveyor.com/project/RubenVerborgh/n3-js/branch/master) [![Coverage Status](https://coveralls.io/repos/github/RubenVerborgh/N3.js/badge.svg)](https://coveralls.io/github/RubenVerborgh/N3.js) [![npm version](https://badge.fury.io/js/n3.svg)](https://www.npmjs.com/package/n3) [![DOI](https://zenodo.org/badge/3058202.svg)](https://zenodo.org/badge/latestdoi/3058202) -The N3.js library lets you handle [RDF](http://www.w3.org/TR/rdf-primer/) in JavaScript easily, in [Node.js](http://nodejs.org/) and the browser. +The N3.js library is an implementation of the [RDF.js low-level specification](http://rdf.js.org/) that lets you handle [RDF](https://www.w3.org/TR/rdf-primer/) in JavaScript easily. It offers: - [**Parsing**](#parsing) triples/quads from - [Turtle](http://www.w3.org/TR/turtle/), - [TriG](http://www.w3.org/TR/trig/), - [N-Triples](http://www.w3.org/TR/n-triples/), - [N-Quads](http://www.w3.org/TR/n-quads/), + [Turtle](https://www.w3.org/TR/turtle/), + [TriG](https://www.w3.org/TR/trig/), + [N-Triples](https://www.w3.org/TR/n-triples/), + [N-Quads](https://www.w3.org/TR/n-quads/), and [Notation3 (N3)](https://www.w3.org/TeamSubmission/n3/) - [**Writing**](#writing) triples/quads to - [Turtle](http://www.w3.org/TR/turtle/), - [TriG](http://www.w3.org/TR/trig/), - [N-Triples](http://www.w3.org/TR/n-triples/), - and [N-Quads](http://www.w3.org/TR/n-quads/) + [Turtle](https://www.w3.org/TR/turtle/), + [TriG](https://www.w3.org/TR/trig/), + [N-Triples](https://www.w3.org/TR/n-triples/), + and [N-Quads](https://www.w3.org/TR/n-quads/) - [**Storage**](#storing) of triples/quads in memory Parsing and writing is: - **asynchronous** – triples arrive as soon as possible - **streaming** – streams are parsed as data comes in, so you can parse files larger than memory -- **fast** – by far the [fastest parser in JavaScript](https://github.com/RubenVerborgh/N3.js/tree/master/perf) +- **fast** – by far the [fastest spec-compatible parser in JavaScript](https://github.com/RubenVerborgh/N3.js/tree/master/perf) ## Installation For Node.js, N3.js comes as an [npm package](https://npmjs.org/package/n3). -``` bash +```Bash $ npm install n3 ``` -``` js -var N3 = require('n3'); +```JavaScript +const N3 = require('n3'); ``` -N3.js seamlessly works in browsers. Generate a browser version as follows: - -``` bash -$ cd N3.js -$ npm install -$ npm run browser -``` - -``` html - -``` - -In addition, N3.js is fully compatible with [browserify](http://browserify.org/), -so you can write code for Node.js and deploy it to browsers. - -## Triple representation -For maximum performance and ease of use, -triples are simple objects with string properties. - -**URLs, URIs and IRIs are simple strings.** For example, parsing this RDF document: -``` Turtle -@prefix c: . -c:Tom a c:Cat. -``` -results in this JavaScript object: -``` js -{ - subject: 'http://example.org/cartoons#Tom', - predicate: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', - object: 'http://example.org/cartoons#Cat' -} +N3.js seamlessly works in browsers via [webpack](https://webpack.js.org/) or [browserify](http://browserify.org/). + +## Creating triples/quads +N3.js follows the [RDF.js low-level specification](http://rdf.js.org/). + +`N3.DataFactory` will give you the [factory](http://rdf.js.org/#datafactory-interface) functions to create triples and quads: + +```JavaScript +const { DataFactory } = N3; +const { namedNode, literal, defaultGraph, quad } = DataFactory; +const myQuad = quad( + namedNode('https://ruben.verborgh.org/profile/#me'), + namedNode('http://xmlns.com/foaf/0.1/givenName'), + literal('Ruben', 'en'), + defaultGraph(), +); +console.log(myQuad.subject.value); // https://ruben.verborgh.org/profile/#me +console.log(myQuad.object.value); // Ruben +console.log(myQuad.object.datatype.value); // http://www.w3.org/1999/02/22-rdf-syntax-ns#langString +console.log(myQuad.object.language); // en ``` -**Literals are represented as double quoted strings.** For example, parsing this RDF document: -``` Turtle -c:Tom c:name "Tom". -``` -results in this JavaScript object: -``` js -{ - subject: 'http://example.org/cartoons#Tom', - predicate: 'http://example.org/cartoons#name', - object: '"Tom"' -} -``` - -This allows you to create and compare literals fast and easily: -``` js -triple.object === 'http://example.org/cartoons#Cat' -triple.object === '"Tom"' -``` - -For literals with a language or type, add a marker (`@` or `^^`) and the corresponding value as-is: -``` js -'"Tom"@en-gb' // lowercase language -'"1"^^http://www.w3.org/2001/XMLSchema#integer' // no angular brackets <> -``` - -An optional fourth element signals the graph to which a triple belongs: -``` js -{ - subject: 'http://example.org/cartoons#Tom', - predicate: 'http://example.org/cartoons#name', - object: '"Tom"', - graph: 'http://example.org/mycartoon' -} -``` - -The N3.js [Utility](#utility) (`N3.Util`) can help you with these representations. - ## Parsing ### From an RDF document to triples -`N3.Parser` transforms Turtle, TriG, N-Triples or N-Quads document into triples through a callback: -``` js -var parser = N3.Parser(); -parser.parse('@prefix c: .\n' + - 'c:Tom a c:Cat.\n' + - 'c:Jerry a c:Mouse;\n' + - ' c:smarterThan c:Tom.', - function (error, triple, prefixes) { - if (triple) - console.log(triple.subject, triple.predicate, triple.object, '.'); - else - console.log("# That's all, folks!", prefixes) - }); +`N3.Parser` transforms Turtle, TriG, N-Triples, or N-Quads document into triples through a callback: +```JavaScript +const parser = new N3.Parser(); +parser.parse( + `PREFIX c: + c:Tom a c:Cat. + c:Jerry a c:Mouse; + c:smarterThan c:Tom.`, + (error, quad, prefixes) => { + if (quad) + console.log(quad); + else + console.log("# That's all, folks!", prefixes); + }); ``` The callback's first argument is an error value, the second is a triple. If there are no more triples, @@ -134,50 +86,47 @@ Pass a second callback to `parse` to retrieve prefixes as they are read.
If no callbacks are provided, parsing happens synchronously. -By default, `N3.Parser` parses a permissive superset of Turtle, TriG, N-Triples and N-Quads. +By default, `N3.Parser` parses a permissive superset of Turtle, TriG, N-Triples, and N-Quads.
For strict compatibility with any of those languages, pass a `format` argument upon creation: -``` js -var parser1 = N3.Parser({ format: 'N-Triples' }); -var parser2 = N3.Parser({ format: 'application/trig' }); +```JavaScript +const parser1 = N3.Parser({ format: 'N-Triples' }); +const parser2 = N3.Parser({ format: 'application/trig' }); ``` Notation3 (N3) is supported _only_ through the `format` argument: -``` js -var parser3 = N3.Parser({ format: 'N3' }); -var parser4 = N3.Parser({ format: 'Notation3' }); -var parser5 = N3.Parser({ format: 'text/n3' }); +```JavaScript +const parser3 = N3.Parser({ format: 'N3' }); +const parser4 = N3.Parser({ format: 'Notation3' }); +const parser5 = N3.Parser({ format: 'text/n3' }); ``` ### From an RDF stream to triples `N3.Parser` can parse [Node.js streams](http://nodejs.org/api/stream.html) as they grow, returning triples as soon as they're ready. -
-This behavior sets N3.js apart from most other libraries. -``` js -var parser = N3.Parser(), - rdfStream = fs.createReadStream('cartoons.ttl'); +```JavaScript +const parser = N3.Parser(), + rdfStream = fs.createReadStream('cartoons.ttl'); parser.parse(rdfStream, console.log); ``` -In addition, `N3.StreamParser` offers a [Node.js stream](http://nodejs.org/api/stream.html) implementation, -so you can transform RDF streams and pipe them to anywhere. +`N3.StreamParser` is a [Node.js stream](http://nodejs.org/api/stream.html) and [RDF.js Sink](http://rdf.js.org/#sink-interface) implementation. This solution is ideal if your consumer is slower, since source data is only read when the consumer is ready. -``` js -var streamParser = N3.StreamParser(), - rdfStream = fs.createReadStream('cartoons.ttl'); +```JavaScript +const streamParser = N3.StreamParser(), + rdfStream = fs.createReadStream('cartoons.ttl'); rdfStream.pipe(streamParser); streamParser.pipe(new SlowConsumer()); function SlowConsumer() { - var writer = new require('stream').Writable({ objectMode: true }); - writer._write = function (triple, encoding, done) { + const writer = new require('stream').Writable({ objectMode: true }); + writer._write = (triple, encoding, done) => { console.log(triple); setTimeout(done, 1000); }; @@ -185,7 +134,7 @@ function SlowConsumer() { } ``` -A dedicated `prefix` event signals every prefix with `prefix` and `iri` arguments. +A dedicated `prefix` event signals every prefix with `prefix` and `term` arguments. ## Writing @@ -194,53 +143,57 @@ A dedicated `prefix` event signals every prefix with `prefix` and `iri` argument `N3.Writer` serializes triples as an RDF document. Write triples through `addTriple`. -``` js -var writer = N3.Writer({ prefixes: { c: 'http://example.org/cartoons#' } }); -writer.addTriple('http://example.org/cartoons#Tom', - 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', - 'http://example.org/cartoons#Cat'); -writer.addTriple({ - subject: 'http://example.org/cartoons#Tom', - predicate: 'http://example.org/cartoons#name', - object: '"Tom"' -}); -writer.end(function (error, result) { console.log(result); }); +```JavaScript +const writer = N3.Writer({ prefixes: { c: 'http://example.org/cartoons#' } }); +writer.addTriple( + namedNode('http://example.org/cartoons#Tom'), + namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), + namedNode('http://example.org/cartoons#Cat') +); +writer.addTriple(quad( + namedNode('http://example.org/cartoons#Tom'), + namedNode('http://example.org/cartoons#name'), + literal('Tom') +)); +writer.end((error, result) => console.log(result)); ``` By default, `N3.Writer` writes Turtle (or TriG for triples with a `graph` property).
To write N-Triples (or N-Quads) instead, pass a `format` argument upon creation: -``` js -var writer1 = N3.Writer({ format: 'N-Triples' }); -var writer2 = N3.Writer({ format: 'application/trig' }); +```JavaScript +const writer1 = N3.Writer({ format: 'N-Triples' }); +const writer2 = N3.Writer({ format: 'application/trig' }); ``` ### From triples to an RDF stream `N3.Writer` can also write triples to a Node.js stream. -``` js -var writer = N3.Writer(process.stdout, { end: false, prefixes: { c: 'http://example.org/cartoons#' } }); -writer.addTriple('http://example.org/cartoons#Tom', - 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', - 'http://example.org/cartoons#Cat'); -writer.addTriple({ - subject: 'http://example.org/cartoons#Tom', - predicate: 'http://example.org/cartoons#name', - object: '"Tom"' -}); +```JavaScript +const writer = N3.Writer(process.stdout, { end: false, prefixes: { c: 'http://example.org/cartoons#' } }); +writer.addTriple( + namedNode('http://example.org/cartoons#Tom'), + namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), + namedNode('http://example.org/cartoons#Cat') +); +writer.addTriple(quad( + namedNode('http://example.org/cartoons#Tom'), + namedNode('http://example.org/cartoons#name'), + literal('Tom') +)); writer.end(); ``` ### From a triple stream to an RDF stream -`N3.StreamWriter` is a writer implementation as a Node.js stream. +`N3.StreamWriter` is a [Node.js stream](http://nodejs.org/api/stream.html) and [RDF.js Sink](http://rdf.js.org/#sink-interface) implementation. -``` js -var streamParser = new N3.StreamParser(), - inputStream = fs.createReadStream('cartoons.ttl'), - streamWriter = new N3.StreamWriter({ prefixes: { c: 'http://example.org/cartoons#' } }); +```JavaScript +const streamParser = new N3.StreamParser(), + inputStream = fs.createReadStream('cartoons.ttl'), + streamWriter = new N3.StreamWriter({ prefixes: { c: 'http://example.org/cartoons#' } }); inputStream.pipe(streamParser); streamParser.pipe(streamWriter); streamWriter.pipe(process.stdout); @@ -253,35 +206,38 @@ the shorthand notations are only possible if blank nodes or list heads are not u which can only be determined conclusively at the end of the stream. The `blank` and `list` functions allow you to create them manually instead: -```js -var writer = N3.Writer({ prefixes: { c: 'http://example.org/cartoons#', - foaf: 'http://xmlns.com/foaf/0.1/' } }); -writer.addTriple(writer.blank('http://xmlns.com/foaf/0.1/givenName', '"Tom"@en'), - 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', - 'http://example.org/cartoons#Cat'); -writer.addTriple('http://example.org/cartoons#Jerry', - 'http://xmlns.com/foaf/0.1/knows', - writer.blank([{ - predicate: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', - object: 'http://example.org/cartoons#Cat' - },{ - predicate: 'http://xmlns.com/foaf/0.1/givenName', - object: '"Tom"@en', - }])); -writer.addTriple('http://example.org/cartoons#Mammy', - 'http://example.org/cartoons#hasPets', - writer.list([ - 'http://example.org/cartoons#Tom', - 'http://example.org/cartoons#Jerry' - ])); -writer.end(function (error, result) { console.log(result); }); +```JavaScript +const writer = N3.Writer({ prefixes: { c: 'http://example.org/cartoons#', + foaf: 'http://xmlns.com/foaf/0.1/' } }); +writer.addTriple( + writer.blank( + namedNode('http://xmlns.com/foaf/0.1/givenName'), + literal('Tom', 'en')), + namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), + namedNode('http://example.org/cartoons#Cat') +); +writer.addTriple(quad( + namedNode('http://example.org/cartoons#Jerry'), + namedNode('http://xmlns.com/foaf/0.1/knows'), + writer.blank([{ + predicate: namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), + object: namedNode('http://example.org/cartoons#Cat'), + },{ + predicate: namedNode('http://xmlns.com/foaf/0.1/givenName'), + object: literal('Tom', 'en'), + }]) +)); +writer.addTriple( + namedNode('http://example.org/cartoons#Mammy'), + namedNode('http://example.org/cartoons#hasPets'), + writer.list([ + namedNode('http://example.org/cartoons#Tom'), + namedNode('http://example.org/cartoons#Jerry'), + ]) +); +writer.end((error, result) => console.log(result)); ``` -Be careful to use the output of `blank` and `list` -**only once** and **only as argument to `addTriple`** of the same writer, -as return values of these functions are unspecified. - - ## Storing `N3.Store` allows you to store triples in memory and find them fast. @@ -290,13 +246,21 @@ In this example, we create a new store and add the triples `:Pluto a :Dog.` and
Then, we find triples with `:Mickey` as subject. -``` js -var store = N3.Store(); -store.addTriple('http://ex.org/Pluto', 'http://ex.org/type', 'http://ex.org/Dog'); -store.addTriple('http://ex.org/Mickey', 'http://ex.org/type', 'http://ex.org/Mouse'); - -var mickey = store.getTriples('http://ex.org/Mickey', null, null)[0]; -console.log(mickey.subject, mickey.predicate, mickey.object, '.'); +```JavaScript +const store = N3.Store(); +store.addTriple( + namedNode('http://ex.org/Pluto'), + namedNode('http://ex.org/type'), + namedNode('http://ex.org/Dog') +); +store.addTriple( + namedNode('http://ex.org/Mickey'), + namedNode('http://ex.org/type'), + namedNode('http://ex.org/Mouse') +); + +const mickey = store.getTriples(namedNode('http://ex.org/Mickey'), null, null)[0]; +console.log(mickey); ``` ### Addition and deletion of triples/quads @@ -304,8 +268,6 @@ The store provides the following manipulation methods ([documentation](http://rubenverborgh.github.io/N3.js/docs/N3Store.html)): - `addTriple` to insert one triple/quad - `addTriples` to insert an array of triples/quads -- `addPrefix` to register a prefix (facilitating lookup) -- `addPrefixes` to register an array of prefixes - `removeTriple` to remove one triple/quad - `removeTriples` to remove an array of triples/quads - `createBlankNode` returns an unused blank node identifier @@ -327,66 +289,16 @@ The store provides the following search methods - `getGraphs` returns an array of unique graphs occurring in matching triple - `forGraphs` executes a callback on unique graphs occurring in matching triples - -## Utility -`N3.Util` offers helpers for IRI and literal representations. -
-As IRIs are most common, they are represented as simple strings: -``` js -var N3Util = N3.Util; -N3Util.isIRI('http://example.org/cartoons#Mickey'); // true -``` -**Literals** are represented as double quoted strings: -``` js -N3Util.isLiteral('"Mickey Mouse"'); // true -N3Util.getLiteralValue('"Mickey Mouse"'); // 'Mickey Mouse' -N3Util.isLiteral('"Mickey Mouse"@en'); // true -N3Util.getLiteralLanguage('"Mickey Mouse"@en'); // 'en' -N3Util.isLiteral('"3"^^http://www.w3.org/2001/XMLSchema#integer'); // true -N3Util.getLiteralType('"3"^^http://www.w3.org/2001/XMLSchema#integer'); // 'http://www.w3.org/2001/XMLSchema#integer' -N3Util.isLiteral('"http://example.org/"'); // true -N3Util.getLiteralValue('"http://example.org/"'); // 'http://example.org/' -``` -Note the difference between `'http://example.org/'` (IRI) and `'"http://example.org/"'` (literal). -
-Also note that the double quoted literals are _not_ raw Turtle/TriG syntax: -``` js -N3Util.isLiteral('"This word is "quoted"!"'); // true -N3Util.isLiteral('"3"^^http://www.w3.org/2001/XMLSchema#integer'); // true -``` -The above string represents the string _This word is "quoted"!_, -even though the correct Turtle/TriG syntax for that is `"This word is \"quoted\"!"` -N3.js thus always parses literals, but adds quotes to differentiate from IRIs: -``` js -new N3.Parser().parse('
"This word is \\"quoted\\"!".', console.log); -// { subject: 'a', predicate: 'b', object: '"This word is "quoted"!"' } -``` - -Literals can be created with `createLiteral`: -``` js -N3Util.createLiteral('My text', 'en-gb'); -N3Util.createLiteral('123', 'http://www.w3.org/2001/XMLSchema#integer'); -N3Util.createLiteral(123); -N3Util.createLiteral(false); -``` - -**Blank nodes** start with `_:`, and can be tested for as follows: -``` js -N3Util.isBlank('_:b1'); // true -N3Util.isIRI('_:b1'); // false -N3Util.isLiteral('_:b1'); // false -``` - ## Compatibility -### Specifications +### Format specifications The N3.js parser and writer is fully compatible with the following W3C specifications: -- [RDF 1.1 Turtle](http://www.w3.org/TR/turtle/) +- [RDF 1.1 Turtle](https://www.w3.org/TR/turtle/) – [EARL report](https://raw.githubusercontent.com/RubenVerborgh/N3.js/earl/n3js-earl-report-turtle.ttl) -- [RDF 1.1 TriG](http://www.w3.org/TR/trig/) +- [RDF 1.1 TriG](https://www.w3.org/TR/trig/) – [EARL report](https://raw.githubusercontent.com/RubenVerborgh/N3.js/earl/n3js-earl-report-trig.ttl) -- [RDF 1.1 N-Triples](http://www.w3.org/TR/n-triples/) +- [RDF 1.1 N-Triples](https://www.w3.org/TR/n-triples/) – [EARL report](https://raw.githubusercontent.com/RubenVerborgh/N3.js/earl/n3js-earl-report-ntriples.ttl) -- [RDF 1.1 N-Quads](http://www.w3.org/TR/n-quads/) +- [RDF 1.1 N-Quads](https://www.w3.org/TR/n-quads/) – [EARL report](https://raw.githubusercontent.com/RubenVerborgh/N3.js/earl/n3js-earl-report-nquads.ttl) In addition, the N3.js parser also supports [Notation3 (N3)](https://www.w3.org/TeamSubmission/n3/) (no official specification yet). @@ -394,8 +306,35 @@ In addition, the N3.js parser also supports [Notation3 (N3)](https://www.w3.org/ Pass a `format` option to the constructor with the name or MIME type of a format for strict, fault-intolerant behavior. -## License, status and contributions -The N3.js library is copyrighted by [Ruben Verborgh](http://ruben.verborgh.org/) +### Interface specifications +The N3.js submodules are compatible with the following [RDF.js](http://rdf.js.org) interfaces: + +- `N3.DataFactory` implements + [`DataFactory`](`http://rdf.js.org/#datafactory-interface`) + - the terms it creates implement [`Term`](http://rdf.js.org/#term-interface) + and one of + [`NamedNode`](http://rdf.js.org/#namednode-interface), + [`BlankNode`](http://rdf.js.org/#blanknode-interface), + [`Literal`](http://rdf.js.org/#litereal-interface), + [`Variable`](http://rdf.js.org/#variable-interface), + [`DefaultGraph`](http://rdf.js.org/#defaultgraph-interface) + - the triples/quads it creates implement + [`Triple`](http://rdf.js.org/#triple-interface) + and + [`Quad`](http://rdf.js.org/#quad-interface) +- `N3.StreamParser` implements + [`Stream`](http://rdf.js.org/#stream-interface) + and + [`Sink`](http://rdf.js.org/#sink-interface) +- `N3.StreamWriter` implements + [`Stream`](http://rdf.js.org/#stream-interface) + and + [`Sink`](http://rdf.js.org/#sink-interface) +- `N3.Store` implements + [`Sink`](http://rdf.js.org/#stream-interface) + +## License and contributions +The N3.js library is copyrighted by [Ruben Verborgh](https://ruben.verborgh.org/) and released under the [MIT License](https://github.com/RubenVerborgh/N3.js/blob/master/LICENSE.md). Contributions are welcome, and bug reports or pull requests are always helpful. From c6435ff9831eaf1db129064798371d8aba3774da Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Thu, 12 Apr 2018 00:30:06 +0200 Subject: [PATCH 34/34] Make everything quads. --- LICENSE.md | 2 +- README.md | 93 ++++++++++++----------- lib/N3Parser.js | 52 ++++++------- lib/N3Store.js | 104 ++++++++++++------------- lib/N3StreamParser.js | 10 +-- lib/N3StreamWriter.js | 2 +- lib/N3Writer.js | 52 ++++++------- perf/N3Parser-perf.js | 6 +- perf/N3Store-perf.js | 26 +++---- spec/SpecTester.js | 28 +++---- test/N3Store-test.js | 171 +++++++++++++++++++++--------------------- test/N3Writer-test.js | 107 +++++++++++++------------- 12 files changed, 327 insertions(+), 326 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index 94fe52f4..8f1c08b4 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ # License The MIT License (MIT) -Copyright ©2012–2016 Ruben Verborgh +Copyright ©2012–2018 Ruben Verborgh Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/README.md b/README.md index 975b3197..ad22881b 100644 --- a/README.md +++ b/README.md @@ -58,11 +58,14 @@ console.log(myQuad.object.datatype.value); // http://www.w3.org/1999/02/22-rdf-s console.log(myQuad.object.language); // en ``` +In the rest of this document, we will treat “triples” and “quads” equally: +we assume that a quad is simply a triple in a named or default graph. + ## Parsing -### From an RDF document to triples +### From an RDF document to quads -`N3.Parser` transforms Turtle, TriG, N-Triples, or N-Quads document into triples through a callback: +`N3.Parser` transforms Turtle, TriG, N-Triples, or N-Quads document into quads through a callback: ```JavaScript const parser = new N3.Parser(); parser.parse( @@ -77,9 +80,9 @@ parser.parse( console.log("# That's all, folks!", prefixes); }); ``` -The callback's first argument is an error value, the second is a triple. -If there are no more triples, -the callback is invoked one last time with `null` for `triple` +The callback's first argument is an optional error value, the second is a quad. +If there are no more quads, +the callback is invoked one last time with `null` for `quad` and a hash of prefixes as third argument.
Pass a second callback to `parse` to retrieve prefixes as they are read. @@ -103,10 +106,10 @@ const parser4 = N3.Parser({ format: 'Notation3' }); const parser5 = N3.Parser({ format: 'text/n3' }); ``` -### From an RDF stream to triples +### From an RDF stream to quads `N3.Parser` can parse [Node.js streams](http://nodejs.org/api/stream.html) as they grow, -returning triples as soon as they're ready. +returning quads as soon as they're ready. ```JavaScript const parser = N3.Parser(), @@ -126,8 +129,8 @@ streamParser.pipe(new SlowConsumer()); function SlowConsumer() { const writer = new require('stream').Writable({ objectMode: true }); - writer._write = (triple, encoding, done) => { - console.log(triple); + writer._write = (quad, encoding, done) => { + console.log(quad); setTimeout(done, 1000); }; return writer; @@ -138,19 +141,19 @@ A dedicated `prefix` event signals every prefix with `prefix` and `term` argumen ## Writing -### From triples to a string +### From quads to a string -`N3.Writer` serializes triples as an RDF document. -Write triples through `addTriple`. +`N3.Writer` serializes quads as an RDF document. +Write quads through `addQuad`. ```JavaScript const writer = N3.Writer({ prefixes: { c: 'http://example.org/cartoons#' } }); -writer.addTriple( +writer.addQuad( namedNode('http://example.org/cartoons#Tom'), namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), namedNode('http://example.org/cartoons#Cat') ); -writer.addTriple(quad( +writer.addQuad(quad( namedNode('http://example.org/cartoons#Tom'), namedNode('http://example.org/cartoons#name'), literal('Tom') @@ -158,7 +161,7 @@ writer.addTriple(quad( writer.end((error, result) => console.log(result)); ``` -By default, `N3.Writer` writes Turtle (or TriG for triples with a `graph` property). +By default, `N3.Writer` writes Turtle (or TriG if some quads are in a named graph).
To write N-Triples (or N-Quads) instead, pass a `format` argument upon creation: @@ -167,18 +170,18 @@ const writer1 = N3.Writer({ format: 'N-Triples' }); const writer2 = N3.Writer({ format: 'application/trig' }); ``` -### From triples to an RDF stream +### From quads to an RDF stream -`N3.Writer` can also write triples to a Node.js stream. +`N3.Writer` can also write quads to a Node.js stream. ```JavaScript const writer = N3.Writer(process.stdout, { end: false, prefixes: { c: 'http://example.org/cartoons#' } }); -writer.addTriple( +writer.addQuad( namedNode('http://example.org/cartoons#Tom'), namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), namedNode('http://example.org/cartoons#Cat') ); -writer.addTriple(quad( +writer.addQuad(quad( namedNode('http://example.org/cartoons#Tom'), namedNode('http://example.org/cartoons#name'), literal('Tom') @@ -186,7 +189,7 @@ writer.addTriple(quad( writer.end(); ``` -### From a triple stream to an RDF stream +### From a quad stream to an RDF stream `N3.StreamWriter` is a [Node.js stream](http://nodejs.org/api/stream.html) and [RDF.js Sink](http://rdf.js.org/#sink-interface) implementation. @@ -209,14 +212,14 @@ The `blank` and `list` functions allow you to create them manually instead: ```JavaScript const writer = N3.Writer({ prefixes: { c: 'http://example.org/cartoons#', foaf: 'http://xmlns.com/foaf/0.1/' } }); -writer.addTriple( +writer.addQuad( writer.blank( namedNode('http://xmlns.com/foaf/0.1/givenName'), literal('Tom', 'en')), namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), namedNode('http://example.org/cartoons#Cat') ); -writer.addTriple(quad( +writer.addQuad(quad( namedNode('http://example.org/cartoons#Jerry'), namedNode('http://xmlns.com/foaf/0.1/knows'), writer.blank([{ @@ -227,7 +230,7 @@ writer.addTriple(quad( object: literal('Tom', 'en'), }]) )); -writer.addTriple( +writer.addQuad( namedNode('http://example.org/cartoons#Mammy'), namedNode('http://example.org/cartoons#hasPets'), writer.list([ @@ -248,46 +251,46 @@ Then, we find triples with `:Mickey` as subject. ```JavaScript const store = N3.Store(); -store.addTriple( +store.addQuad( namedNode('http://ex.org/Pluto'), namedNode('http://ex.org/type'), namedNode('http://ex.org/Dog') ); -store.addTriple( +store.addQuad( namedNode('http://ex.org/Mickey'), namedNode('http://ex.org/type'), namedNode('http://ex.org/Mouse') ); -const mickey = store.getTriples(namedNode('http://ex.org/Mickey'), null, null)[0]; +const mickey = store.getQuads(namedNode('http://ex.org/Mickey'), null, null)[0]; console.log(mickey); ``` -### Addition and deletion of triples/quads +### Addition and deletion of quads The store provides the following manipulation methods ([documentation](http://rubenverborgh.github.io/N3.js/docs/N3Store.html)): -- `addTriple` to insert one triple/quad -- `addTriples` to insert an array of triples/quads -- `removeTriple` to remove one triple/quad -- `removeTriples` to remove an array of triples/quads +- `addQuad` to insert one quad +- `addQuads` to insert an array of quads +- `removeQuad` to remove one quad +- `removeQuads` to remove an array of quads - `createBlankNode` returns an unused blank node identifier -### Searching triples/quads or entities +### Searching quads or entities The store provides the following search methods ([documentation](http://rubenverborgh.github.io/N3.js/docs/N3Store.html)): -- `getTriples` returns an array of triples/quads matching the given pattern -- `countTriples` counts the number of triples/quads matching the given pattern -- `forEach` executes a callback on all matching triples/quads -- `every` returns whether a callback on matching triples/quads always returns true -- `some` returns whether a callback on matching triples/quads returns true at least once -- `getSubjects` returns an array of unique subjects occurring in matching triples -- `forSubjects` executes a callback on unique subjects occurring in matching triples -- `getPredicates` returns an array of unique predicates occurring in matching triple -- `forPredicates` executes a callback on unique predicates occurring in matching triples -- `getObjects` returns an array of unique objects occurring in matching triple -- `forObjects` executes a callback on unique objects occurring in matching triples -- `getGraphs` returns an array of unique graphs occurring in matching triple -- `forGraphs` executes a callback on unique graphs occurring in matching triples +- `getQuads` returns an array of quads matching the given pattern +- `countQuads` counts the number of quads matching the given pattern +- `forEach` executes a callback on all matching quads +- `every` returns whether a callback on matching quads always returns true +- `some` returns whether a callback on matching quads returns true at least once +- `getSubjects` returns an array of unique subjects occurring in matching quads +- `forSubjects` executes a callback on unique subjects occurring in matching quads +- `getPredicates` returns an array of unique predicates occurring in matching quad +- `forPredicates` executes a callback on unique predicates occurring in matching quads +- `getObjects` returns an array of unique objects occurring in matching quad +- `forObjects` executes a callback on unique objects occurring in matching quads +- `getGraphs` returns an array of unique graphs occurring in matching quad +- `forGraphs` executes a callback on unique graphs occurring in matching quads ## Compatibility ### Format specifications diff --git a/lib/N3Parser.js b/lib/N3Parser.js index 25b31179..a3c78f4a 100644 --- a/lib/N3Parser.js +++ b/lib/N3Parser.js @@ -210,12 +210,12 @@ N3Parser.prototype = { return value; }, - // ### `_readSubject` reads a triple's subject + // ### `_readSubject` reads a quad's subject _readSubject: function (token) { this._predicate = null; switch (token.type) { case '[': - // Start a new triple with a new blank node as subject + // Start a new quad with a new blank node as subject this._saveContext('blank', this._graph, this._subject = this._blankNode(), null, null); return this._readBlankNodeHead; @@ -262,7 +262,7 @@ N3Parser.prototype = { return this._readPredicateOrNamedGraph; }, - // ### `_readPredicate` reads a triple's predicate + // ### `_readPredicate` reads a quad's predicate _readPredicate: function (token) { var type = token.type; switch (type) { @@ -294,14 +294,14 @@ N3Parser.prototype = { return this._readObject; }, - // ### `_readObject` reads a triple's object + // ### `_readObject` reads a quad's object _readObject: function (token) { switch (token.type) { case 'literal': this._object = new Literal(token.value); return this._readDataTypeOrLang; case '[': - // Start a new triple with a new blank node as subject + // Start a new quad with a new blank node as subject this._saveContext('blank', this._graph, this._subject, this._predicate, this._subject = this._blankNode()); return this._readBlankNodeHead; @@ -328,7 +328,7 @@ N3Parser.prototype = { return this._getContextEndReader(); }, - // ### `_readPredicateOrNamedGraph` reads a triple's predicate, or a named graph + // ### `_readPredicateOrNamedGraph` reads a quad's predicate, or a named graph _readPredicateOrNamedGraph: function (token) { return token.type === '{' ? this._readGraph(token) : this._readPredicate(token); }, @@ -359,7 +359,7 @@ N3Parser.prototype = { if (token.type !== ']') return this._readBlankNodePunctuation(token); - // Store blank node triple + // Store blank node quad if (this._subject !== null) this._quad(this._subject, this._predicate, this._object, this._graph); @@ -379,7 +379,7 @@ N3Parser.prototype = { _readPredicateAfterBlank: function (token) { // If a dot follows a blank node in top context, there is no predicate if (token.type === '.' && !this._contextStack.length) { - this._subject = null; // cancel the current triple + this._subject = null; // cancel the current quad return this._readPunctuation(token); } return this._readPredicate(token); @@ -397,14 +397,14 @@ N3Parser.prototype = { switch (token.type) { case '[': - // Stack the current list triple and start a new triple with a blank node as subject + // Stack the current list quad and start a new quad with a blank node as subject this._saveContext('blank', this._graph, list = this._blankNode(), RDF_FIRST, this._subject = item = this._blankNode()); next = this._readBlankNodeHead; break; case '(': - // Stack the current list triple and start a new list + // Stack the current list quad and start a new list this._saveContext('list', this._graph, list = this._blankNode(), RDF_FIRST, RDF_NIL); this._subject = null; @@ -412,7 +412,7 @@ N3Parser.prototype = { case ')': // Closing the list; restore the parent context this._restoreContext(); - // If this list is contained within a parent list, return the membership triple here. + // If this list is contained within a parent list, return the membership quad here. // This will be ` rdf:first .`. if (stack.length !== 0 && stack[stack.length - 1].type === 'list') this._quad(this._subject, this._predicate, this._object, this._graph); @@ -527,7 +527,7 @@ N3Parser.prototype = { if (token.type !== '}') return this._readPunctuation(token); - // Store the last triple of the formula + // Store the last quad of the formula if (this._subject !== null) this._quad(this._subject, this._predicate, this._object, this._graph); @@ -538,7 +538,7 @@ N3Parser.prototype = { return this._object === null ? this._readPredicate : this._getContextEndReader(); }, - // ### `_readPunctuation` reads punctuation between triples or triple parts + // ### `_readPunctuation` reads punctuation between quads or quad parts _readPunctuation: function (token) { var next, subject = this._subject, graph = this._graph, inversePredicate = this._inversePredicate; @@ -572,7 +572,7 @@ N3Parser.prototype = { } return this._error('Expected punctuation to follow "' + this._object.id + '"', token); } - // A triple has been completed now, so return it + // A quad has been completed now, so return it if (subject !== null) { var predicate = this._predicate, object = this._object; if (!inversePredicate) @@ -598,7 +598,7 @@ N3Parser.prototype = { default: return this._error('Expected punctuation to follow "' + this._object.id + '"', token); } - // A triple has been completed now, so return it + // A quad has been completed now, so return it this._quad(this._subject, this._predicate, this._object, this._graph); return next; }, @@ -761,7 +761,7 @@ N3Parser.prototype = { // If we were reading an object, replace the subject by the path's object else subject = this._object, this._object = object; - // Emit the path's current triple and read its next section + // Emit the path's current quad and read its next section this._quad(subject, predicate, object, this._graph); return this._readPath; }, @@ -778,7 +778,7 @@ N3Parser.prototype = { // If we were reading an object, replace the subject by the path's subject else object = this._object, this._object = subject; - // Emit the path's current triple and read its next section + // Emit the path's current quad and read its next section this._quad(subject, predicate, object, this._graph); return this._readPath; }, @@ -799,7 +799,7 @@ N3Parser.prototype = { } }, - // ### `_quad` emits a triple through the callback + // ### `_quad` emits a quad through the callback _quad: function (subject, predicate, object, graph) { this._callback(null, new Quad(subject, predicate, object, graph || DEFAULTGRAPH)); @@ -902,8 +902,8 @@ N3Parser.prototype = { // ## Public methods - // ### `parse` parses the N3 input and emits each parsed triple through the callback - parse: function (input, tripleCallback, prefixCallback) { + // ### `parse` parses the N3 input and emits each parsed quad through the callback + parse: function (input, quadCallback, prefixCallback) { var self = this; // The read callback is the next function to be executed when a token arrives. // We start reading in the top context. @@ -916,19 +916,19 @@ N3Parser.prototype = { this._inversePredicate = false; this._quantified = Object.create(null); - // Parse synchronously if no triple callback is given - if (!tripleCallback) { - var triples = [], error; - this._callback = function (e, t) { e ? (error = e) : t && triples.push(t); }; + // Parse synchronously if no quad callback is given + if (!quadCallback) { + var quads = [], error; + this._callback = function (e, t) { e ? (error = e) : t && quads.push(t); }; this._lexer.tokenize(input).every(function (token) { return self._readCallback = self._readCallback(token); }); if (error) throw error; - return triples; + return quads; } // Parse asynchronously otherwise, executing the read callback when a token arrives - this._callback = tripleCallback; + this._callback = quadCallback; this._lexer.tokenize(input, function (error, token) { if (error !== null) self._callback(error), self._callback = noop; diff --git a/lib/N3Store.js b/lib/N3Store.js index e5e2a258..787bf3b0 100644 --- a/lib/N3Store.js +++ b/lib/N3Store.js @@ -1,4 +1,4 @@ -// **N3Store** objects store N3 triples by graph in memory. +// **N3Store** objects store N3 quads by graph in memory. var DataFactory = require('./N3DataFactory'); var Term = DataFactory.Term, @@ -6,11 +6,11 @@ var Term = DataFactory.Term, Quad = DataFactory.Quad; // ## Constructor -function N3Store(triples, options) { +function N3Store(quads, options) { if (!(this instanceof N3Store)) - return new N3Store(triples, options); + return new N3Store(quads, options); - // The number of triples is initially zero + // The number of quads is initially zero this._size = 0; // `_graphs` contains subject, predicate, and object indexes per graph this._graphs = Object.create(null); @@ -23,27 +23,27 @@ function N3Store(triples, options) { // `_blankNodeIndex` is the index of the last automatically named blank node this._blankNodeIndex = 0; - // Shift parameters if `triples` is not given - if (!options && triples && !triples[0]) - options = triples, triples = null; + // Shift parameters if `quads` is not given + if (!options && quads && !quads[0]) + options = quads, quads = null; options = options || {}; - // Add triples if passed - if (triples) - this.addTriples(triples); + // Add quads if passed + if (quads) + this.addQuads(quads); } N3Store.prototype = { // ## Public properties - // ### `size` returns the number of triples in the store + // ### `size` returns the number of quads in the store get size() { - // Return the triple count if if was cached + // Return the quad count if if was cached var size = this._size; if (size !== null) return size; - // Calculate the number of triples by counting to the deepest level + // Calculate the number of quads by counting to the deepest level size = 0; var graphs = this._graphs, subjects, subject; for (var graphKey in graphs) @@ -55,22 +55,22 @@ N3Store.prototype = { // ## Private methods - // ### `_addToIndex` adds a triple to a three-layered index. + // ### `_addToIndex` adds a quad to a three-layered index. // Returns if the index has changed, if the entry did not already exist. _addToIndex: function (index0, key0, key1, key2) { // Create layers as necessary var index1 = index0[key0] || (index0[key0] = {}); var index2 = index1[key1] || (index1[key1] = {}); - // Setting the key to _any_ value signals the presence of the triple + // Setting the key to _any_ value signals the presence of the quad var existed = key2 in index2; if (!existed) index2[key2] = null; return !existed; }, - // ### `_removeFromIndex` removes a triple from a three-layered index + // ### `_removeFromIndex` removes a quad from a three-layered index _removeFromIndex: function (index0, key0, key1, key2) { - // Remove the triple from the index + // Remove the quad from the index var index1 = index0[key0], index2 = index1[key1], key; delete index2[key2]; @@ -81,15 +81,15 @@ N3Store.prototype = { delete index0[key0]; }, - // ### `_findInIndex` finds a set of triples in a three-layered index. + // ### `_findInIndex` finds a set of quads in a three-layered index. // The index base is `index0` and the keys at each level are `key0`, `key1`, and `key2`. // Any of these keys can be undefined, which is interpreted as a wildcard. // `name0`, `name1`, and `name2` are the names of the keys at each level, - // used when reconstructing the resulting triple + // used when reconstructing the resulting quad // (for instance: _subject_, _predicate_, and _object_). - // Finally, `graph` will be the graph of the created triples. + // Finally, `graph` will be the graph of the created quads. // If `callback` is given, each result is passed through it - // and iteration halts when it returns truthy for any triple. + // and iteration halts when it returns truthy for any quad. // If instead `array` is given, each result is added to the array. _findInIndex: function (index0, key0, key1, key2, name0, name1, name2, graph, callback, array) { var tmp, index1, index2, varCount = !key0 + !key1 + !key2, @@ -110,7 +110,7 @@ N3Store.prototype = { if (index2 = index1[value1]) { // If a key is specified, use only that part of index 2, if it exists. var values = key2 ? (key2 in index2 ? [key2] : []) : Object.keys(index2); - // Create triples for all items found in index 2. + // Create quads for all items found in index 2. for (var l = values.length - 1; l >= 0; l--) { var result = new Quad(null, null, null, Term.fromId(graph)); result[name0] = Term.fromId(entity0); @@ -162,7 +162,7 @@ N3Store.prototype = { } }, - // ### `_countInIndex` counts matching triples in a three-layered index. + // ### `_countInIndex` counts matching quads in a three-layered index. // The index base is `index0` and the keys at each level are `key0`, `key1`, and `key2`. // Any of these keys can be undefined, which is interpreted as a wildcard. _countInIndex: function (index0, key0, key1, key2) { @@ -176,9 +176,9 @@ N3Store.prototype = { if (key1) (tmp = index1, index1 = {})[key1] = tmp[key1]; for (var value1 in index1) { if (index2 = index1[value1]) { - // If a key is specified, count the triple if it exists + // If a key is specified, count the quad if it exists if (key2) (key2 in index2) && count++; - // Otherwise, count all triples + // Otherwise, count all quads else count += Object.keys(index2).length; } } @@ -211,10 +211,10 @@ N3Store.prototype = { // ## Public methods - // ### `addTriple` adds a new triple to the store. - // Returns if the triple index has changed, if the triple did not already exist. - addTriple: function (subject, predicate, object, graph) { - // Shift arguments if a triple object is given instead of components + // ### `addQuad` adds a new quad to the store. + // Returns if the quad index has changed, if the quad did not already exist. + addQuad: function (subject, predicate, object, graph) { + // Shift arguments if a quad object is given instead of components if (!predicate) graph = subject.graph, object = subject.object, predicate = subject.predicate, subject = subject.subject; @@ -248,27 +248,27 @@ N3Store.prototype = { this._addToIndex(graphItem.predicates, predicate, object, subject); this._addToIndex(graphItem.objects, object, subject, predicate); - // The cached triple count is now invalid + // The cached quad count is now invalid this._size = null; return changed; }, - // ### `addTriples` adds multiple triples to the store - addTriples: function (triples) { - for (var i = triples.length - 1; i >= 0; i--) - this.addTriple(triples[i]); + // ### `addQuads` adds multiple quads to the store + addQuads: function (quads) { + for (var i = quads.length - 1; i >= 0; i--) + this.addQuad(quads[i]); }, // ### `import` adds a stream of quads to the store import: function (stream) { var self = this; - stream.on('data', function (quad) { self.addTriple(quad); }); + stream.on('data', function (quad) { self.addQuad(quad); }); return stream; }, - // ### `removeTriple` removes a triple from the store if it exists - removeTriple: function (subject, predicate, object, graph) { - // Shift arguments if a triple object is given instead of components + // ### `removeQuad` removes a quad from the store if it exists + removeQuad: function (subject, predicate, object, graph) { + // Shift arguments if a quad object is given instead of components if (!predicate) graph = subject.graph, object = subject.object, predicate = subject.predicate, subject = subject.subject; @@ -280,7 +280,7 @@ N3Store.prototype = { graph = Term.toId(graph); // Find internal identifiers for all components - // and verify the triple exists. + // and verify the quad exists. var graphItem, ids = this._ids, graphs = this._graphs, subjects, predicates; if (!(subject = ids[subject]) || !(predicate = ids[predicate]) || !(object = ids[object]) || !(graphItem = graphs[graph]) || @@ -301,22 +301,22 @@ N3Store.prototype = { return true; }, - // ### `removeTriples` removes multiple triples from the store - removeTriples: function (triples) { - for (var i = triples.length - 1; i >= 0; i--) - this.removeTriple(triples[i]); + // ### `removeQuads` removes multiple quads from the store + removeQuads: function (quads) { + for (var i = quads.length - 1; i >= 0; i--) + this.removeQuad(quads[i]); }, // ### `remove` removes a stream of quads from the store remove: function (stream) { var self = this; - stream.on('data', function (quad) { self.removeTriple(quad); }); + stream.on('data', function (quad) { self.removeQuad(quad); }); return stream; }, - // ### `getTriples` returns an array of triples matching a pattern. + // ### `getQuads` returns an array of quads matching a pattern. // Setting any field to `undefined` or `null` indicates a wildcard. - getTriples: function (subject, predicate, object, graph) { + getQuads: function (subject, predicate, object, graph) { // Convert terms to internal string representation subject = subject && Term.toId(subject); predicate = predicate && Term.toId(predicate); @@ -363,9 +363,9 @@ N3Store.prototype = { return quads; }, - // ### `countTriples` returns the number of triples matching a pattern. + // ### `countQuads` returns the number of quads matching a pattern. // Setting any field to `undefined` or `null` indicates a wildcard. - countTriples: function (subject, predicate, object, graph) { + countQuads: function (subject, predicate, object, graph) { // Convert terms to internal string representation subject = subject && Term.toId(subject); predicate = predicate && Term.toId(predicate); @@ -406,7 +406,7 @@ N3Store.prototype = { return count; }, - // ### `forEach` executes the callback on all triples. + // ### `forEach` executes the callback on all quads. // Setting any field to `undefined` or `null` indicates a wildcard. forEach: function (callback, subject, predicate, object, graph) { this.some(function (quad) { @@ -415,7 +415,7 @@ N3Store.prototype = { }, subject, predicate, object, graph); }, - // ### `every` executes the callback on all triples, + // ### `every` executes the callback on all quads, // and returns `true` if it returns truthy for all them. // Setting any field to `undefined` or `null` indicates a wildcard. every: function (callback, subject, predicate, object, graph) { @@ -427,7 +427,7 @@ N3Store.prototype = { return some && every; }, - // ### `some` executes the callback on all triples, + // ### `some` executes the callback on all quads, // and returns `true` if it returns truthy for any of them. // Setting any field to `undefined` or `null` indicates a wildcard. some: function (callback, subject, predicate, object, graph) { @@ -447,7 +447,7 @@ N3Store.prototype = { return false; for (var graphId in graphs) { - // Only if the specified graph contains triples, there can be result + // Only if the specified graph contains triples, there can be results if (content = graphs[graphId]) { // Choose the optimal index, based on what fields are present if (subjectId) { diff --git a/lib/N3StreamParser.js b/lib/N3StreamParser.js index ea4abdd0..9efe78d7 100644 --- a/lib/N3StreamParser.js +++ b/lib/N3StreamParser.js @@ -16,15 +16,15 @@ function N3StreamParser(options) { var self = this, parser = new N3Parser(options), onData, onEnd; // Pass dummy stream to obtain `data` and `end` callbacks parser.parse({ - on: function (event, cb) { + on: function (event, callback) { switch (event) { - case 'data': onData = cb; break; - case 'end': onEnd = cb; break; + case 'data': onData = callback; break; + case 'end': onEnd = callback; break; } }, }, - // Handle triples by pushing them down the pipeline - function (error, t) { error && self.emit('error', error) || t && self.push(t); }, + // Handle quads by pushing them down the pipeline + function (error, quad) { error && self.emit('error', error) || quad && self.push(quad); }, // Emit prefixes through the `prefix` event function (prefix, uri) { self.emit('prefix', prefix, uri); }); diff --git a/lib/N3StreamWriter.js b/lib/N3StreamWriter.js index 1c11720d..372cd6f0 100644 --- a/lib/N3StreamWriter.js +++ b/lib/N3StreamWriter.js @@ -20,7 +20,7 @@ function N3StreamWriter(options) { }, options); // Implement Transform methods on top of writer - this._transform = function (triple, encoding, done) { writer.addTriple(triple, done); }; + this._transform = function (quad, encoding, done) { writer.addQuad(quad, done); }; this._flush = function (done) { writer.end(done); }; } util.inherits(N3StreamWriter, Transform); diff --git a/lib/N3Writer.js b/lib/N3Writer.js index cc51e6be..95340719 100644 --- a/lib/N3Writer.js +++ b/lib/N3Writer.js @@ -49,7 +49,7 @@ function N3Writer(outputStream, options) { options.prefixes && this.addPrefixes(options.prefixes); } else { - this._writeTriple = this._writeTripleLine; + this._writeQuad = this._writeQuadLine; } } @@ -66,8 +66,8 @@ N3Writer.prototype = { this._outputStream.write(string, 'utf8', callback); }, - // ### `_writeTriple` writes the triple to the output stream - _writeTriple: function (subject, predicate, object, graph, done) { + // ### `_writeQuad` writes the quad to the output stream + _writeQuad: function (subject, predicate, object, graph, done) { try { // Write the graph's label if it has changed if (!graph.equals(this._graph)) { @@ -88,7 +88,7 @@ N3Writer.prototype = { this._encodePredicate(this._predicate = predicate) + ' ' + this._encodeObject(object), done); } - // Different subject; write the whole triple + // Different subject; write the whole quad else this._write((this._subject === null ? '' : '.\n') + this._encodeIriOrBlank(this._subject = subject) + ' ' + @@ -98,25 +98,25 @@ N3Writer.prototype = { catch (error) { done && done(error); } }, - // ### `_writeTripleLine` writes the triple or quad to the output stream as a single line - _writeTripleLine: function (subject, predicate, object, graph, done) { - // Write the triple without prefixes + // ### `_writeQuadLine` writes the quad to the output stream as a single line + _writeQuadLine: function (subject, predicate, object, graph, done) { + // Write the quad without prefixes delete this._prefixMatch; - this._write(this.tripleToString(subject, predicate, object, graph), done); + this._write(this.quadToString(subject, predicate, object, graph), done); }, - // ### `tripleToString` serializes a triple or quad as a string - tripleToString: function (subject, predicate, object, graph) { + // ### `quadToString` serializes a quad as a string + quadToString: function (subject, predicate, object, graph) { return this._encodeIriOrBlank(subject) + ' ' + this._encodeIriOrBlank(predicate) + ' ' + this._encodeObject(object) + (graph && graph.value ? ' ' + this._encodeIriOrBlank(graph) + '.\n' : '.\n'); }, - // ### `triplesToString` serializes an array of triples or quads as a string - triplesToString: function (triples) { - return triples.map(function (t) { - return this.tripleToString(t.subject, t.predicate, t.object, t.graph); + // ### `quadsToString` serializes an array of quads as a string + quadsToString: function (quads) { + return quads.map(function (t) { + return this.quadToString(t.subject, t.predicate, t.object, t.graph); }, this).join(''); }, @@ -165,23 +165,23 @@ N3Writer.prototype = { throw new Error('Cannot write because the writer has been closed.'); }, - // ### `addTriple` adds the triple to the output stream - addTriple: function (subject, predicate, object, graph, done) { - // The triple was given as a triple object, so shift parameters + // ### `addQuad` adds the quad to the output stream + addQuad: function (subject, predicate, object, graph, done) { + // The quad was given as an object, so shift parameters if (object === undefined) - this._writeTriple(subject.subject, subject.predicate, subject.object, subject.graph, predicate); + this._writeQuad(subject.subject, subject.predicate, subject.object, subject.graph, predicate); // The optional `graph` parameter was not provided else if (typeof graph === 'function') - this._writeTriple(subject, predicate, object, DEFAULTGRAPH, graph); + this._writeQuad(subject, predicate, object, DEFAULTGRAPH, graph); // The `graph` parameter was provided else - this._writeTriple(subject, predicate, object, graph || DEFAULTGRAPH, done); + this._writeQuad(subject, predicate, object, graph || DEFAULTGRAPH, done); }, - // ### `addTriples` adds the triples to the output stream - addTriples: function (triples) { - for (var i = 0; i < triples.length; i++) - this.addTriple(triples[i]); + // ### `addQuads` adds the quads to the output stream + addQuads: function (quads) { + for (var i = 0; i < quads.length; i++) + this.addQuad(quads[i]); }, // ### `addPrefix` adds the prefix to the output stream @@ -203,7 +203,7 @@ N3Writer.prototype = { if (/[#\/]$/.test(iri) && prefixIRIs[iri] !== (prefix += ':')) { hasPrefixes = true; prefixIRIs[iri] = prefix; - // Finish a possible pending triple + // Finish a possible pending quad if (this._subject !== null) { this._write(this._inDefaultGraph ? '.\n' : '\n}\n'); this._subject = null, this._graph = ''; @@ -284,7 +284,7 @@ N3Writer.prototype = { // ### `end` signals the end of the output stream end: function (done) { - // Finish a possible pending triple + // Finish a possible pending quad if (this._subject !== null) { this._write(this._inDefaultGraph ? '.\n' : '\n}\n'); this._subject = null; diff --git a/perf/N3Parser-perf.js b/perf/N3Parser-perf.js index 938592ad..29f7245c 100755 --- a/perf/N3Parser-perf.js +++ b/perf/N3Parser-perf.js @@ -14,13 +14,13 @@ var TEST = '- Parsing file ' + filename; console.time(TEST); var count = 0; -new N3.Parser({ documentIRI: base }).parse(fs.createReadStream(filename), function (error, triple) { +new N3.Parser({ documentIRI: base }).parse(fs.createReadStream(filename), function (error, quad) { assert(!error, error); - if (triple) + if (quad) count++; else { console.timeEnd(TEST); - console.log('* Triples parsed: ' + count); + console.log('* Quads parsed: ' + count); console.log('* Memory usage: ' + Math.round(process.memoryUsage().rss / 1024 / 1024) + 'MB'); } }); diff --git a/perf/N3Store-perf.js b/perf/N3Store-perf.js index 2856fc5d..e2fd527b 100755 --- a/perf/N3Store-perf.js +++ b/perf/N3Store-perf.js @@ -19,7 +19,7 @@ var i, j, k, l; for (i = 0; i < dim; i++) for (j = 0; j < dim; j++) for (k = 0; k < dim; k++) - store.addTriple(prefix + i, prefix + j, prefix + k); + store.addQuad(prefix + i, prefix + j, prefix + k); console.timeEnd(TEST); console.log('* Memory usage for triples: ' + Math.round(process.memoryUsage().rss / 1024 / 1024) + 'MB'); @@ -29,30 +29,30 @@ console.time(TEST); for (i = 0; i < dim; i++) for (j = 0; j < dim; j++) for (k = 0; k < dim; k++) - assert.equal(store.getTriples(prefix + i, prefix + j, prefix + k, '').length, 1); + assert.equal(store.getQuads(prefix + i, prefix + j, prefix + k, '').length, 1); console.timeEnd(TEST); TEST = '- Finding all ' + dimCubed + ' triples in the default graph ' + dimSquared * 2 + ' times (1 variable)'; console.time(TEST); for (i = 0; i < dim; i++) for (j = 0; j < dim; j++) - assert.equal(store.getTriples(prefix + i, prefix + j, null, '').length, dim); + assert.equal(store.getQuads(prefix + i, prefix + j, null, '').length, dim); for (i = 0; i < dim; i++) for (j = 0; j < dim; j++) - assert.equal(store.getTriples(prefix + i, null, prefix + j, '').length, dim); + assert.equal(store.getQuads(prefix + i, null, prefix + j, '').length, dim); for (i = 0; i < dim; i++) for (j = 0; j < dim; j++) - assert.equal(store.getTriples(null, prefix + i, prefix + j, '').length, dim); + assert.equal(store.getQuads(null, prefix + i, prefix + j, '').length, dim); console.timeEnd(TEST); TEST = '- Finding all ' + dimCubed + ' triples in the default graph ' + dimSquared * 3 + ' times (2 variables)'; console.time(TEST); for (i = 0; i < dim; i++) - assert.equal(store.getTriples(prefix + i, null, null, '').length, dimSquared); + assert.equal(store.getQuads(prefix + i, null, null, '').length, dimSquared); for (j = 0; j < dim; j++) - assert.equal(store.getTriples(null, prefix + j, null, '').length, dimSquared); + assert.equal(store.getQuads(null, prefix + j, null, '').length, dimSquared); for (k = 0; k < dim; k++) - assert.equal(store.getTriples(null, null, prefix + k, '').length, dimSquared); + assert.equal(store.getQuads(null, null, prefix + k, '').length, dimSquared); console.timeEnd(TEST); console.log(); @@ -70,7 +70,7 @@ for (i = 0; i < dim; i++) for (j = 0; j < dim; j++) for (k = 0; k < dim; k++) for (l = 0; l < dim; l++) - store.addTriple(prefix + i, prefix + j, prefix + k, prefix + l); + store.addQuad(prefix + i, prefix + j, prefix + k, prefix + l); console.timeEnd(TEST); console.log('* Memory usage for quads: ' + Math.round(process.memoryUsage().rss / 1024 / 1024) + 'MB'); @@ -78,11 +78,11 @@ console.log('* Memory usage for quads: ' + Math.round(process.memoryUsage().rss TEST = '- Finding all ' + dimQuads + ' quads ' + dimCubed * 4 + ' times'; console.time(TEST); for (i = 0; i < dim; i++) - assert.equal(store.getTriples(prefix + i, null, null, null).length, dimCubed); + assert.equal(store.getQuads(prefix + i, null, null, null).length, dimCubed); for (j = 0; j < dim; j++) - assert.equal(store.getTriples(null, prefix + j, null, null).length, dimCubed); + assert.equal(store.getQuads(null, prefix + j, null, null).length, dimCubed); for (k = 0; k < dim; k++) - assert.equal(store.getTriples(null, null, prefix + k, null).length, dimCubed); + assert.equal(store.getQuads(null, null, prefix + k, null).length, dimCubed); for (l = 0; l < dim; l++) - assert.equal(store.getTriples(null, null, null, prefix + l).length, dimCubed); + assert.equal(store.getQuads(null, null, null, prefix + l).length, dimCubed); console.timeEnd(TEST); diff --git a/spec/SpecTester.js b/spec/SpecTester.js index 41422023..be492e75 100755 --- a/spec/SpecTester.js +++ b/spec/SpecTester.js @@ -120,14 +120,14 @@ SpecTester.prototype._fetch = function (filename, callback) { // Parses the tests manifest into tests SpecTester.prototype._parseManifest = function (manifestContents, callback) { - // Parse the manifest into triples + // Parse the manifest into quads var manifest = {}, testStore = new N3.Store(), self = this; - new N3.Parser({ format: 'text/turtle' }).parse(manifestContents, function (error, triple) { - // Store triples until there are no more - if (error) return callback(error); - if (triple) return testStore.addTriple(triple.subject, triple.predicate, triple.object); + new N3.Parser({ format: 'text/turtle' }).parse(manifestContents, function (error, quad) { + // Store quads until there are no more + if (error) return callback(error); + if (quad) return testStore.addQuad(quad.subject, quad.predicate, quad.object); - // Once all triples are there, get the first item of the test list + // Once all quads are there, get the first item of the test list var tests = manifest.tests = [], skipped = manifest.skipped = [], itemHead = testStore.getObjects('', prefixes.mf + 'entries')[0]; @@ -135,19 +135,19 @@ SpecTester.prototype._parseManifest = function (manifestContents, callback) { while (itemHead && itemHead.value !== nil) { // Find and store the item's properties var itemValue = testStore.getObjects(itemHead, first)[0], - itemTriples = testStore.getTriples(itemValue, null, null), + itemQuads = testStore.getQuads(itemValue, null, null), test = { id: itemValue.value.replace(/^#/, '') }; - itemTriples.forEach(function (triple) { - var propertyMatch = triple.predicate.value.match(/#(.+)/); + itemQuads.forEach(function (quad) { + var propertyMatch = quad.predicate.value.match(/#(.+)/); if (propertyMatch) - test[propertyMatch[1]] = triple.object.value; + test[propertyMatch[1]] = quad.object.value; }); test.negative = /Negative/.test(test.type); test.skipped = self._skipNegative && test.negative; (!test.skipped ? tests : skipped).push(test); // Find the next test item - itemHead = testStore.getTriples(itemHead, rest, null)[0].object; + itemHead = testStore.getQuads(itemHead, rest, null)[0].object; } return callback(null, manifest); }); @@ -163,9 +163,9 @@ SpecTester.prototype._performTest = function (test, actionStream, callback) { resultWriter = new N3.Writer(fs.createWriteStream(resultFile), { format: 'N-Quads' }), config = { format: this._name, documentIRI: url.resolve(this._manifest, test.action) }, parser = new N3.Parser(config), self = this; - parser.parse(actionStream, function (error, triple) { + parser.parse(actionStream, function (error, quad) { if (error) test.error = error; - if (triple) resultWriter.addTriple(triple); + if (quad) resultWriter.addQuad(quad); // Verify the result after it has been written else resultWriter.end(function () { @@ -250,7 +250,7 @@ SpecTester.prototype._generateEarlReport = function (tests, callback) { report.addPrefix('manifest', manifest); function addTriple(s, p, o) { - report.addTriple(Term.fromId(s), Term.fromId(p), Term.fromId(o)); + report.addQuad(Term.fromId(s), Term.fromId(p), Term.fromId(o)); } addTriple(reportFile, prefixes.foaf + 'primaryTopic', app); diff --git a/test/N3Store-test.js b/test/N3Store-test.js index 8a84535a..bacf17e0 100644 --- a/test/N3Store-test.js +++ b/test/N3Store-test.js @@ -5,8 +5,7 @@ var Readable = require('stream').Readable, var Term = DataFactory.Term, NamedNode = DataFactory.NamedNode, DefaultGraph = DataFactory.DefaultGraph, - Quad = DataFactory.Quad, - Triple = DataFactory.Triple; + Quad = DataFactory.Quad; describe('N3Store', function () { describe('The N3Store module', function () { @@ -31,14 +30,14 @@ describe('N3Store', function () { }); it('should be empty', function () { - store.getTriples().should.be.empty; + store.getQuads().should.be.empty; }); describe('when importing a stream of 2 quads', function () { before(function (done) { var stream = new ArrayReader([ - new Triple(new NamedNode('s1'), new NamedNode('p2'), new NamedNode('o2')), - new Triple(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o1')), + new Quad(new NamedNode('s1'), new NamedNode('p2'), new NamedNode('o2')), + new Quad(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o1')), ]); var events = store.import(stream); events.on('end', done); @@ -50,8 +49,8 @@ describe('N3Store', function () { describe('when removing a stream of 2 quads', function () { before(function (done) { var stream = new ArrayReader([ - new Triple(new NamedNode('s1'), new NamedNode('p2'), new NamedNode('o2')), - new Triple(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o1')), + new Quad(new NamedNode('s1'), new NamedNode('p2'), new NamedNode('o2')), + new Quad(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o1')), ]); var events = store.remove(stream); events.on('end', done); @@ -88,8 +87,8 @@ describe('N3Store', function () { it('should still have size 0 (instead of null) after adding and removing a triple', function () { expect(store.size).to.eql(0); - store.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')).should.be.true; - store.removeTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')).should.be.true; + store.addQuad(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')).should.be.true; + store.removeQuad(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')).should.be.true; expect(store.size).to.eql(0); }); @@ -97,9 +96,9 @@ describe('N3Store', function () { store.createBlankNode().value.should.eql('b0'); store.createBlankNode().value.should.eql('b1'); - store.addTriple('_:b0', '_:b1', '_:b2').should.be.true; + store.addQuad('_:b0', '_:b1', '_:b2').should.be.true; store.createBlankNode().value.should.eql('b3'); - store.removeTriples(store.getTriples()); + store.removeQuads(store.getQuads()); }); it('should be able to generate named blank nodes', function () { @@ -109,9 +108,9 @@ describe('N3Store', function () { }); it('should be able to store triples with generated blank nodes', function () { - store.addTriple(store.createBlankNode('x'), new NamedNode('b'), new NamedNode('c')).should.be.true; - shouldIncludeAll(store.getTriples(null, new NamedNode('b')), ['_:x', 'b', 'c'])(); - store.removeTriples(store.getTriples()); + store.addQuad(store.createBlankNode('x'), new NamedNode('b'), new NamedNode('c')).should.be.true; + shouldIncludeAll(store.getQuads(null, new NamedNode('b')), ['_:x', 'b', 'c'])(); + store.removeQuads(store.getQuads()); }); }); @@ -128,7 +127,7 @@ describe('N3Store', function () { describe('adding a triple that already exists', function () { it('should return false', function () { - store.addTriple('s1', 'p1', 'o1').should.be.false; + store.addQuad('s1', 'p1', 'o1').should.be.false; }); it('should not increase the size', function () { @@ -138,7 +137,7 @@ describe('N3Store', function () { describe('adding a triple that did not exist yet', function () { it('should return true', function () { - store.addTriple('s1', 'p1', 'o4').should.be.true; + store.addQuad('s1', 'p1', 'o4').should.be.true; }); it('should increase the size', function () { @@ -148,7 +147,7 @@ describe('N3Store', function () { describe('removing an existing triple', function () { it('should return true', function () { - store.removeTriple('s1', 'p1', 'o4').should.be.true; + store.removeQuad('s1', 'p1', 'o4').should.be.true; }); it('should decrease the size', function () { @@ -158,7 +157,7 @@ describe('N3Store', function () { describe('removing a non-existing triple', function () { it('should return false', function () { - store.removeTriple('s1', 'p1', 'o5').should.be.false; + store.removeQuad('s1', 'p1', 'o5').should.be.false; }); it('should not decrease the size', function () { @@ -169,13 +168,13 @@ describe('N3Store', function () { describe('An N3Store with 5 elements', function () { var store = new N3Store(); - store.addTriple('s1', 'p1', 'o1').should.be.true; - store.addTriple({ subject: 's1', predicate: 'p1', object: 'o2' }).should.be.true; - store.addTriples([ + store.addQuad('s1', 'p1', 'o1').should.be.true; + store.addQuad({ subject: 's1', predicate: 'p1', object: 'o2' }).should.be.true; + store.addQuads([ { subject: 's1', predicate: 'p2', object: 'o2' }, { subject: 's2', predicate: 'p1', object: 'o1' }, ]); - store.addTriple('s1', 'p1', 'o1', 'c4').should.be.true; + store.addQuad('s1', 'p1', 'o1', 'c4').should.be.true; it('should have size 5', function () { store.size.should.eql(5); @@ -183,7 +182,7 @@ describe('N3Store', function () { describe('when searched without parameters', function () { it('should return all items', - shouldIncludeAll(store.getTriples(), + shouldIncludeAll(store.getQuads(), ['s1', 'p1', 'o1'], ['s1', 'p1', 'o2'], ['s1', 'p2', 'o2'], @@ -193,7 +192,7 @@ describe('N3Store', function () { describe('when searched with an existing subject parameter', function () { it('should return all items with this subject in all graphs', - shouldIncludeAll(store.getTriples(new NamedNode('s1'), null, null), + shouldIncludeAll(store.getQuads(new NamedNode('s1'), null, null), ['s1', 'p1', 'o1'], ['s1', 'p1', 'o2'], ['s1', 'p2', 'o2'], @@ -201,16 +200,16 @@ describe('N3Store', function () { }); describe('when searched with a non-existing subject parameter', function () { - itShouldBeEmpty(store.getTriples(new NamedNode('s3'), null, null)); + itShouldBeEmpty(store.getQuads(new NamedNode('s3'), null, null)); }); describe('when searched with a non-existing subject parameter that exists elsewhere', function () { - itShouldBeEmpty(store.getTriples(new NamedNode('p1'), null, null)); + itShouldBeEmpty(store.getQuads(new NamedNode('p1'), null, null)); }); describe('when searched with an existing predicate parameter', function () { it('should return all items with this predicate in all graphs', - shouldIncludeAll(store.getTriples(null, new NamedNode('p1'), null), + shouldIncludeAll(store.getQuads(null, new NamedNode('p1'), null), ['s1', 'p1', 'o1'], ['s1', 'p1', 'o2'], ['s2', 'p1', 'o1'], @@ -218,70 +217,70 @@ describe('N3Store', function () { }); describe('when searched with a non-existing predicate parameter', function () { - itShouldBeEmpty(store.getTriples(null, new NamedNode('p3'), null)); + itShouldBeEmpty(store.getQuads(null, new NamedNode('p3'), null)); }); describe('when searched with an existing object parameter', function () { it('should return all items with this object in all graphs', - shouldIncludeAll(store.getTriples(null, null, new NamedNode('o1')), + shouldIncludeAll(store.getQuads(null, null, new NamedNode('o1')), ['s1', 'p1', 'o1'], ['s2', 'p1', 'o1'], ['s1', 'p1', 'o1', 'c4'])); }); describe('when searched with a non-existing object parameter', function () { - itShouldBeEmpty(store.getTriples(null, null, new NamedNode('o4'))); + itShouldBeEmpty(store.getQuads(null, null, new NamedNode('o4'))); }); describe('when searched with existing subject and predicate parameters', function () { it('should return all items with this subject and predicate in all graphs', - shouldIncludeAll(store.getTriples(new NamedNode('s1'), new NamedNode('p1'), null), + shouldIncludeAll(store.getQuads(new NamedNode('s1'), new NamedNode('p1'), null), ['s1', 'p1', 'o1'], ['s1', 'p1', 'o2'], ['s1', 'p1', 'o1', 'c4'])); }); describe('when searched with non-existing subject and predicate parameters', function () { - itShouldBeEmpty(store.getTriples(new NamedNode('s2'), new NamedNode('p2'), null)); + itShouldBeEmpty(store.getQuads(new NamedNode('s2'), new NamedNode('p2'), null)); }); describe('when searched with existing subject and object parameters', function () { it('should return all items with this subject and object in all graphs', - shouldIncludeAll(store.getTriples(new NamedNode('s1'), null, new NamedNode('o1')), + shouldIncludeAll(store.getQuads(new NamedNode('s1'), null, new NamedNode('o1')), ['s1', 'p1', 'o1'], ['s1', 'p1', 'o1', 'c4'])); }); describe('when searched with non-existing subject and object parameters', function () { - itShouldBeEmpty(store.getTriples(new NamedNode('s2'), new NamedNode('p2'), null)); + itShouldBeEmpty(store.getQuads(new NamedNode('s2'), new NamedNode('p2'), null)); }); describe('when searched with existing predicate and object parameters', function () { it('should return all items with this predicate and object in all graphs', - shouldIncludeAll(store.getTriples(null, new NamedNode('p1'), new NamedNode('o1')), + shouldIncludeAll(store.getQuads(null, new NamedNode('p1'), new NamedNode('o1')), ['s1', 'p1', 'o1'], ['s2', 'p1', 'o1'], ['s1', 'p1', 'o1', 'c4'])); }); describe('when searched with non-existing predicate and object parameters in the default graph', function () { - itShouldBeEmpty(store.getTriples(null, new NamedNode('p2'), new NamedNode('o3'), new DefaultGraph())); + itShouldBeEmpty(store.getQuads(null, new NamedNode('p2'), new NamedNode('o3'), new DefaultGraph())); }); describe('when searched with existing subject, predicate, and object parameters', function () { it('should return all items with this subject, predicate, and object in all graphs', - shouldIncludeAll(store.getTriples(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o1')), + shouldIncludeAll(store.getQuads(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o1')), ['s1', 'p1', 'o1'], ['s1', 'p1', 'o1', 'c4'])); }); describe('when searched with a non-existing triple', function () { - itShouldBeEmpty(store.getTriples(new NamedNode('s2'), new NamedNode('p2'), new NamedNode('o1'))); + itShouldBeEmpty(store.getQuads(new NamedNode('s2'), new NamedNode('p2'), new NamedNode('o1'))); }); describe('when searched with the default graph parameter', function () { it('should return all items in the default graph', - shouldIncludeAll(store.getTriples(null, null, null, new DefaultGraph()), + shouldIncludeAll(store.getQuads(null, null, null, new DefaultGraph()), ['s1', 'p1', 'o1'], ['s1', 'p1', 'o2'], ['s1', 'p2', 'o2'], @@ -290,12 +289,12 @@ describe('N3Store', function () { describe('when searched with an existing named graph parameter', function () { it('should return all items in that graph', - shouldIncludeAll(store.getTriples(null, null, null, new NamedNode('c4')), + shouldIncludeAll(store.getQuads(null, null, null, new NamedNode('c4')), ['s1', 'p1', 'o1', 'c4'])); }); describe('when searched with a non-existing named graph parameter', function () { - itShouldBeEmpty(store.getTriples(null, null, null, new NamedNode('c5'))); + itShouldBeEmpty(store.getQuads(null, null, null, new NamedNode('c5'))); }); describe('getSubjects', function () { @@ -775,170 +774,170 @@ describe('N3Store', function () { describe('when counted without parameters', function () { it('should count all items in all graphs', function () { - store.countTriples().should.equal(5); + store.countQuads().should.equal(5); }); }); describe('when counted with an existing subject parameter', function () { it('should count all items with this subject in all graphs', function () { - store.countTriples(new NamedNode('s1'), null, null).should.equal(4); + store.countQuads(new NamedNode('s1'), null, null).should.equal(4); }); }); describe('when counted with a non-existing subject parameter', function () { it('should be empty', function () { - store.countTriples(new NamedNode('s3'), null, null).should.equal(0); + store.countQuads(new NamedNode('s3'), null, null).should.equal(0); }); }); describe('when counted with a non-existing subject parameter that exists elsewhere', function () { it('should be empty', function () { - store.countTriples(new NamedNode('p1'), null, null).should.equal(0); + store.countQuads(new NamedNode('p1'), null, null).should.equal(0); }); }); describe('when counted with an existing predicate parameter', function () { it('should count all items with this predicate in all graphs', function () { - store.countTriples(null, new NamedNode('p1'), null).should.equal(4); + store.countQuads(null, new NamedNode('p1'), null).should.equal(4); }); }); describe('when counted with a non-existing predicate parameter', function () { it('should be empty', function () { - store.countTriples(null, new NamedNode('p3'), null).should.equal(0); + store.countQuads(null, new NamedNode('p3'), null).should.equal(0); }); }); describe('when counted with an existing object parameter', function () { it('should count all items with this object in all graphs', function () { - store.countTriples(null, null, 'o1').should.equal(3); + store.countQuads(null, null, 'o1').should.equal(3); }); }); describe('when counted with a non-existing object parameter', function () { it('should be empty', function () { - store.countTriples(null, null, 'o4').should.equal(0); + store.countQuads(null, null, 'o4').should.equal(0); }); }); describe('when counted with existing subject and predicate parameters', function () { it('should count all items with this subject and predicate in all graphs', function () { - store.countTriples('s1', 'p1', null).should.equal(3); + store.countQuads('s1', 'p1', null).should.equal(3); }); }); describe('when counted with non-existing subject and predicate parameters', function () { it('should be empty', function () { - store.countTriples('s2', 'p2', null).should.equal(0); + store.countQuads('s2', 'p2', null).should.equal(0); }); }); describe('when counted with existing subject and object parameters', function () { it('should count all items with this subject and object in all graphs', function () { - store.countTriples('s1', null, 'o1').should.equal(2); + store.countQuads('s1', null, 'o1').should.equal(2); }); }); describe('when counted with non-existing subject and object parameters', function () { it('should be empty', function () { - store.countTriples('s2', 'p2', null).should.equal(0); + store.countQuads('s2', 'p2', null).should.equal(0); }); }); describe('when counted with existing predicate and object parameters', function () { it('should count all items with this predicate and object in all graphs', function () { - store.countTriples(null, 'p1', 'o1').should.equal(3); + store.countQuads(null, 'p1', 'o1').should.equal(3); }); }); describe('when counted with non-existing predicate and object parameters', function () { it('should be empty', function () { - store.countTriples(null, 'p2', 'o3').should.equal(0); + store.countQuads(null, 'p2', 'o3').should.equal(0); }); }); describe('when counted with existing subject, predicate, and object parameters', function () { it('should count all items with this subject, predicate, and object in all graphs', function () { - store.countTriples('s1', 'p1', 'o1').should.equal(2); + store.countQuads('s1', 'p1', 'o1').should.equal(2); }); }); describe('when counted with a non-existing triple', function () { it('should be empty', function () { - store.countTriples('s2', 'p2', 'o1').should.equal(0); + store.countQuads('s2', 'p2', 'o1').should.equal(0); }); }); describe('when counted with the default graph parameter', function () { it('should count all items in the default graph', function () { - store.countTriples(null, null, null, new DefaultGraph()).should.equal(4); + store.countQuads(null, null, null, new DefaultGraph()).should.equal(4); }); }); describe('when counted with an existing named graph parameter', function () { it('should count all items in that graph', function () { - store.countTriples(null, null, null, 'c4').should.equal(1); + store.countQuads(null, null, null, 'c4').should.equal(1); }); }); describe('when counted with a non-existing named graph parameter', function () { it('should be empty', function () { - store.countTriples(null, null, null, 'c5').should.equal(0); + store.countQuads(null, null, null, 'c5').should.equal(0); }); }); describe('when trying to remove a triple with a non-existing subject', function () { - before(function () { store.removeTriple(new NamedNode('s0'), new NamedNode('p1'), new NamedNode('o1')).should.be.false; }); + before(function () { store.removeQuad(new NamedNode('s0'), new NamedNode('p1'), new NamedNode('o1')).should.be.false; }); it('should still have size 5', function () { store.size.should.eql(5); }); }); describe('when trying to remove a triple with a non-existing predicate', function () { - before(function () { store.removeTriple(new NamedNode('s1'), new NamedNode('p0'), new NamedNode('o1')).should.be.false; }); + before(function () { store.removeQuad(new NamedNode('s1'), new NamedNode('p0'), new NamedNode('o1')).should.be.false; }); it('should still have size 5', function () { store.size.should.eql(5); }); }); describe('when trying to remove a triple with a non-existing object', function () { - before(function () { store.removeTriple(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o0')).should.be.false; }); + before(function () { store.removeQuad(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o0')).should.be.false; }); it('should still have size 5', function () { store.size.should.eql(5); }); }); describe('when trying to remove a triple for which no subjects exist', function () { - before(function () { store.removeTriple(new NamedNode('o1'), new NamedNode('p1'), new NamedNode('o1')).should.be.false; }); + before(function () { store.removeQuad(new NamedNode('o1'), new NamedNode('p1'), new NamedNode('o1')).should.be.false; }); it('should still have size 5', function () { store.size.should.eql(5); }); }); describe('when trying to remove a triple for which no predicates exist', function () { - before(function () { store.removeTriple(new NamedNode('s1'), new NamedNode('s1'), new NamedNode('o1')).should.be.false; }); + before(function () { store.removeQuad(new NamedNode('s1'), new NamedNode('s1'), new NamedNode('o1')).should.be.false; }); it('should still have size 5', function () { store.size.should.eql(5); }); }); describe('when trying to remove a triple for which no objects exist', function () { - before(function () { store.removeTriple(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('s1')).should.be.false; }); + before(function () { store.removeQuad(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('s1')).should.be.false; }); it('should still have size 5', function () { store.size.should.eql(5); }); }); describe('when trying to remove a triple that does not exist', function () { - before(function () { store.removeTriple(new NamedNode('s1'), new NamedNode('p2'), new NamedNode('o1')).should.be.false; }); + before(function () { store.removeQuad(new NamedNode('s1'), new NamedNode('p2'), new NamedNode('o1')).should.be.false; }); it('should still have size 5', function () { store.size.should.eql(5); }); }); describe('when trying to remove an incomplete triple', function () { - before(function () { store.removeTriple(new NamedNode('s1'), null, null).should.be.false; }); + before(function () { store.removeQuad(new NamedNode('s1'), null, null).should.be.false; }); it('should still have size 5', function () { store.size.should.eql(5); }); }); describe('when trying to remove a triple with a non-existing graph', function () { - before(function () { store.removeTriple(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o1'), new NamedNode('c0')).should.be.false; }); + before(function () { store.removeQuad(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o1'), new NamedNode('c0')).should.be.false; }); it('should still have size 5', function () { store.size.should.eql(5); }); }); describe('when removing an existing triple', function () { - before(function () { store.removeTriple(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o1')).should.be.true; }); + before(function () { store.removeQuad(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o1')).should.be.true; }); it('should have size 4', function () { store.size.should.eql(4); }); it('should not contain that triple anymore', - shouldIncludeAll(function () { return store.getTriples(); }, + shouldIncludeAll(function () { return store.getQuads(); }, ['s1', 'p1', 'o2'], ['s1', 'p2', 'o2'], ['s2', 'p1', 'o1'], @@ -946,32 +945,32 @@ describe('N3Store', function () { }); describe('when removing an existing triple from a named graph', function () { - before(function () { store.removeTriple(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o1'), new NamedNode('c4')).should.be.true; }); + before(function () { store.removeQuad(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o1'), new NamedNode('c4')).should.be.true; }); it('should have size 3', function () { store.size.should.eql(3); }); - itShouldBeEmpty(function () { return store.getTriples(null, null, null, 'c4'); }); + itShouldBeEmpty(function () { return store.getQuads(null, null, null, 'c4'); }); }); describe('when removing multiple triples', function () { before(function () { - store.removeTriples([ - new Triple(new NamedNode('s1'), new NamedNode('p2'), new NamedNode('o2')), - new Triple(new NamedNode('s2'), new NamedNode('p1'), new NamedNode('o1')), + store.removeQuads([ + new Quad(new NamedNode('s1'), new NamedNode('p2'), new NamedNode('o2')), + new Quad(new NamedNode('s2'), new NamedNode('p1'), new NamedNode('o1')), ]); }); it('should have size 1', function () { store.size.should.eql(1); }); it('should not contain those triples anymore', - shouldIncludeAll(function () { return store.getTriples(); }, + shouldIncludeAll(function () { return store.getQuads(); }, ['s1', 'p1', 'o2'])); }); describe('when adding and removing a triple', function () { before(function () { - store.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')).should.be.true; - store.removeTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')).should.be.true; + store.addQuad(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')).should.be.true; + store.removeQuad(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')).should.be.true; }); it('should have an unchanged size', function () { store.size.should.eql(1); }); @@ -981,17 +980,17 @@ describe('N3Store', function () { describe('An N3Store containing a blank node', function () { var store = new N3Store(); var b1 = store.createBlankNode(); - store.addTriple(new NamedNode('s1'), new NamedNode('p1'), b1).should.be.true; + store.addQuad(new NamedNode('s1'), new NamedNode('p1'), b1).should.be.true; describe('when searched with more than one variable', function () { it('should return a triple with the blank node as an object', - shouldIncludeAll(store.getTriples(), + shouldIncludeAll(store.getQuads(), ['s1', 'p1', '_:' + b1.value])); }); describe('when searched with one variable', function () { it('should return a triple with the blank node as an object', - shouldIncludeAll(store.getTriples('s1', 'p1'), + shouldIncludeAll(store.getQuads('s1', 'p1'), ['s1', 'p1', '_:' + b1.value])); }); }); @@ -1002,14 +1001,14 @@ describe('N3Store', function () { // Test inspired by http://www.devthought.com/2012/01/18/an-object-is-not-a-hash/. // The value `__proto__` is not supported however – fixing it introduces too much overhead. it('should be able to contain entities with JavaScript object property names', function () { - store.addTriple('toString', 'valueOf', 'toLocaleString', 'hasOwnProperty').should.be.true; - shouldIncludeAll(store.getTriples(null, null, null, 'hasOwnProperty'), + store.addQuad('toString', 'valueOf', 'toLocaleString', 'hasOwnProperty').should.be.true; + shouldIncludeAll(store.getQuads(null, null, null, 'hasOwnProperty'), ['toString', 'valueOf', 'toLocaleString', 'hasOwnProperty'])(); }); it('should be able to contain entities named "null"', function () { - store.addTriple('null', 'null', 'null', 'null').should.be.true; - shouldIncludeAll(store.getTriples(null, null, null, 'null'), ['null', 'null', 'null', 'null'])(); + store.addQuad('null', 'null', 'null', 'null').should.be.true; + shouldIncludeAll(store.getQuads(null, null, null, 'null'), ['null', 'null', 'null', 'null'])(); }); }); }); diff --git a/test/N3Writer-test.js b/test/N3Writer-test.js index d3fee928..dbdaa50c 100644 --- a/test/N3Writer-test.js +++ b/test/N3Writer-test.js @@ -4,8 +4,7 @@ var DataFactory = require('../N3').DataFactory; var Term = DataFactory.Term, NamedNode = DataFactory.NamedNode, Literal = DataFactory.Literal, - Quad = DataFactory.Quad, - Triple = DataFactory.Triple; + Quad = DataFactory.Quad; describe('N3Writer', function () { describe('The N3Writer module', function () { @@ -25,19 +24,19 @@ describe('N3Writer', function () { describe('An N3Writer instance', function () { it('should serialize a single triple', function () { var writer = N3Writer(); - writer.tripleToString(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')).should.equal('
.\n'); + writer.quadToString(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')).should.equal(' .\n'); }); it('should serialize a single quad', function () { var writer = N3Writer(); - writer.tripleToString(new NamedNode('a'), new NamedNode('b'), new NamedNode('c'), new NamedNode('g')).should.equal(' .\n'); + writer.quadToString(new NamedNode('a'), new NamedNode('b'), new NamedNode('c'), new NamedNode('g')).should.equal(' .\n'); }); it('should serialize an array of triples', function () { var writer = N3Writer(); var triples = [new Quad(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')), new Quad(new NamedNode('d'), new NamedNode('e'), new NamedNode('f'))]; - writer.triplesToString(triples).should.equal(' .\n .\n'); + writer.quadsToString(triples).should.equal(' .\n .\n'); }); @@ -219,7 +218,7 @@ describe('N3Writer', function () { it('sends output through end when no stream argument is given', function (done) { var writer = new N3Writer(), notCalled = true; - writer.addTriple(new Triple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')), function () { notCalled = false; }); + writer.addQuad(new Quad(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')), function () { notCalled = false; }); writer.end(function (error, output) { output.should.equal(' .\n'); done(notCalled || error); @@ -228,7 +227,7 @@ describe('N3Writer', function () { it('respects the prefixes argument when no stream argument is given', function (done) { var writer = new N3Writer({ prefixes: { a: 'b#' } }); - writer.addTriple(new Triple(new NamedNode('b#a'), new NamedNode('b#b'), new NamedNode('b#c'))); + writer.addQuad(new Quad(new NamedNode('b#a'), new NamedNode('b#b'), new NamedNode('b#c'))); writer.end(function (error, output) { output.should.equal('@prefix a: .\n\na:a a:b a:c.\n'); done(error); @@ -239,7 +238,7 @@ describe('N3Writer', function () { var writer = new N3Writer(); writer.addPrefix('a', 'b#'); writer.addPrefix('a', 'b#'); - writer.addTriple(new Triple(new NamedNode('b#a'), new NamedNode('b#b'), new NamedNode('b#c'))); + writer.addQuad(new Quad(new NamedNode('b#a'), new NamedNode('b#b'), new NamedNode('b#c'))); writer.addPrefix('a', 'b#'); writer.addPrefix('a', 'b#'); writer.addPrefix('b', 'b#'); @@ -254,9 +253,9 @@ describe('N3Writer', function () { it('serializes triples of a graph with a prefix declaration in between', function (done) { var writer = new N3Writer(); writer.addPrefix('a', 'b#'); - writer.addTriple(new Quad(new NamedNode('b#a'), new NamedNode('b#b'), new NamedNode('b#c'), new NamedNode('b#g'))); + writer.addQuad(new Quad(new NamedNode('b#a'), new NamedNode('b#b'), new NamedNode('b#c'), new NamedNode('b#g'))); writer.addPrefix('d', 'e#'); - writer.addTriple(new Quad(new NamedNode('b#a'), new NamedNode('b#b'), new NamedNode('b#d'), new NamedNode('b#g'))); + writer.addQuad(new Quad(new NamedNode('b#a'), new NamedNode('b#b'), new NamedNode('b#d'), new NamedNode('b#g'))); writer.end(function (error, output) { output.should.equal('@prefix a: .\n\na:g {\na:a a:b a:c\n}\n' + '@prefix d: .\n\na:g {\na:a a:b a:d\n}\n'); @@ -266,8 +265,8 @@ describe('N3Writer', function () { it('should accept triples with separated components', function (done) { var writer = N3Writer(); - writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')); - writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('d')); + writer.addQuad(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')); + writer.addQuad(new NamedNode('a'), new NamedNode('b'), new NamedNode('d')); writer.end(function (error, output) { output.should.equal(' , .\n'); done(error); @@ -276,8 +275,8 @@ describe('N3Writer', function () { it('should accept quads with separated components', function (done) { var writer = N3Writer(); - writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c'), new NamedNode('g')); - writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('d'), new NamedNode('g')); + writer.addQuad(new NamedNode('a'), new NamedNode('b'), new NamedNode('c'), new NamedNode('g')); + writer.addQuad(new NamedNode('a'), new NamedNode('b'), new NamedNode('d'), new NamedNode('g')); writer.end(function (error, output) { output.should.equal(' {\n , \n}\n'); done(error); @@ -286,8 +285,8 @@ describe('N3Writer', function () { it('should serialize triples with an empty blank node as object', function (done) { var writer = N3Writer(); - writer.addTriple(new NamedNode('a1'), new NamedNode('b'), writer.blank()); - writer.addTriple(new NamedNode('a2'), new NamedNode('b'), writer.blank([])); + writer.addQuad(new NamedNode('a1'), new NamedNode('b'), writer.blank()); + writer.addQuad(new NamedNode('a2'), new NamedNode('b'), writer.blank([])); writer.end(function (error, output) { output.should.equal(' [].\n' + ' [].\n'); @@ -297,9 +296,9 @@ describe('N3Writer', function () { it('should serialize triples with a one-triple blank node as object', function (done) { var writer = N3Writer(); - writer.addTriple(new NamedNode('a1'), new NamedNode('b'), writer.blank(new NamedNode('d'), new NamedNode('e'))); - writer.addTriple(new NamedNode('a2'), new NamedNode('b'), writer.blank({ predicate: new NamedNode('d'), object: new NamedNode('e') })); - writer.addTriple(new NamedNode('a3'), new NamedNode('b'), writer.blank([{ predicate: new NamedNode('d'), object: new NamedNode('e') }])); + writer.addQuad(new NamedNode('a1'), new NamedNode('b'), writer.blank(new NamedNode('d'), new NamedNode('e'))); + writer.addQuad(new NamedNode('a2'), new NamedNode('b'), writer.blank({ predicate: new NamedNode('d'), object: new NamedNode('e') })); + writer.addQuad(new NamedNode('a3'), new NamedNode('b'), writer.blank([{ predicate: new NamedNode('d'), object: new NamedNode('e') }])); writer.end(function (error, output) { output.should.equal(' [ ].\n' + ' [ ].\n' + @@ -310,7 +309,7 @@ describe('N3Writer', function () { it('should serialize triples with a two-triple blank node as object', function (done) { var writer = N3Writer(); - writer.addTriple(new NamedNode('a'), new NamedNode('b'), writer.blank([ + writer.addQuad(new NamedNode('a'), new NamedNode('b'), writer.blank([ { predicate: new NamedNode('d'), object: new NamedNode('e') }, { predicate: new NamedNode('f'), object: new Literal('"g"') }, ])); @@ -325,7 +324,7 @@ describe('N3Writer', function () { it('should serialize triples with a three-triple blank node as object', function (done) { var writer = N3Writer(); - writer.addTriple(new NamedNode('a'), new NamedNode('b'), writer.blank([ + writer.addQuad(new NamedNode('a'), new NamedNode('b'), writer.blank([ { predicate: new NamedNode('d'), object: new NamedNode('e') }, { predicate: new NamedNode('f'), object: new Literal('"g"') }, { predicate: new NamedNode('h'), object: new NamedNode('i') }, @@ -342,7 +341,7 @@ describe('N3Writer', function () { it('should serialize triples with predicate-sharing blank node triples as object', function (done) { var writer = N3Writer(); - writer.addTriple(new NamedNode('a'), new NamedNode('b'), writer.blank([ + writer.addQuad(new NamedNode('a'), new NamedNode('b'), writer.blank([ { predicate: new NamedNode('d'), object: new NamedNode('e') }, { predicate: new NamedNode('d'), object: new NamedNode('f') }, { predicate: new NamedNode('g'), object: new NamedNode('h') }, @@ -359,14 +358,14 @@ describe('N3Writer', function () { it('should serialize triples with nested blank nodes as object', function (done) { var writer = N3Writer(); - writer.addTriple(new NamedNode('a1'), new NamedNode('b'), writer.blank([ + writer.addQuad(new NamedNode('a1'), new NamedNode('b'), writer.blank([ { predicate: new NamedNode('d'), object: writer.blank() }, ])); - writer.addTriple(new NamedNode('a2'), new NamedNode('b'), writer.blank([ + writer.addQuad(new NamedNode('a2'), new NamedNode('b'), writer.blank([ { predicate: new NamedNode('d'), object: writer.blank(new NamedNode('e'), new NamedNode('f')) }, { predicate: new NamedNode('g'), object: writer.blank(new NamedNode('h'), new Literal('"i"')) }, ])); - writer.addTriple(new NamedNode('a3'), new NamedNode('b'), writer.blank([ + writer.addQuad(new NamedNode('a3'), new NamedNode('b'), writer.blank([ { predicate: new NamedNode('d'), object: writer.blank([ { predicate: new NamedNode('g'), object: writer.blank(new NamedNode('h'), new NamedNode('i')) }, { predicate: new NamedNode('j'), object: writer.blank(new NamedNode('k'), new Literal('"l"')) }, @@ -392,8 +391,8 @@ describe('N3Writer', function () { it('should serialize triples with an empty blank node as subject', function (done) { var writer = N3Writer(); - writer.addTriple(writer.blank(), new NamedNode('b'), new NamedNode('c')); - writer.addTriple(writer.blank([]), new NamedNode('b'), new NamedNode('c')); + writer.addQuad(writer.blank(), new NamedNode('b'), new NamedNode('c')); + writer.addQuad(writer.blank([]), new NamedNode('b'), new NamedNode('c')); writer.end(function (error, output) { output.should.equal('[] .\n' + '[] .\n'); @@ -403,9 +402,9 @@ describe('N3Writer', function () { it('should serialize triples with a one-triple blank node as subject', function (done) { var writer = N3Writer(); - writer.addTriple(writer.blank(new NamedNode('a'), new NamedNode('b')), new NamedNode('c'), new NamedNode('d')); - writer.addTriple(writer.blank({ predicate: new NamedNode('a'), object: new NamedNode('b') }), new NamedNode('c'), new NamedNode('d')); - writer.addTriple(writer.blank([{ predicate: new NamedNode('a'), object: new NamedNode('b') }]), new NamedNode('c'), new NamedNode('d')); + writer.addQuad(writer.blank(new NamedNode('a'), new NamedNode('b')), new NamedNode('c'), new NamedNode('d')); + writer.addQuad(writer.blank({ predicate: new NamedNode('a'), object: new NamedNode('b') }), new NamedNode('c'), new NamedNode('d')); + writer.addQuad(writer.blank([{ predicate: new NamedNode('a'), object: new NamedNode('b') }]), new NamedNode('c'), new NamedNode('d')); writer.end(function (error, output) { output.should.equal('[ ] .\n' + '[ ] .\n' + @@ -416,8 +415,8 @@ describe('N3Writer', function () { it('should serialize triples with an empty blank node as graph', function (done) { var writer = N3Writer(); - writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c'), writer.blank()); - writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c'), writer.blank([])); + writer.addQuad(new NamedNode('a'), new NamedNode('b'), new NamedNode('c'), writer.blank()); + writer.addQuad(new NamedNode('a'), new NamedNode('b'), new NamedNode('c'), writer.blank([])); writer.end(function (error, output) { output.should.equal('[] {\n \n}\n' + '[] {\n \n}\n'); @@ -427,8 +426,8 @@ describe('N3Writer', function () { it('should serialize triples with an empty list as object', function (done) { var writer = N3Writer(); - writer.addTriple(new NamedNode('a1'), new NamedNode('b'), writer.list()); - writer.addTriple(new NamedNode('a2'), new NamedNode('b'), writer.list([])); + writer.addQuad(new NamedNode('a1'), new NamedNode('b'), writer.list()); + writer.addQuad(new NamedNode('a2'), new NamedNode('b'), writer.list([])); writer.end(function (error, output) { output.should.equal(' ().\n' + ' ().\n'); @@ -438,8 +437,8 @@ describe('N3Writer', function () { it('should serialize triples with a one-element list as object', function (done) { var writer = N3Writer(); - writer.addTriple(new NamedNode('a1'), new NamedNode('b'), writer.list([new NamedNode('c')])); - writer.addTriple(new NamedNode('a2'), new NamedNode('b'), writer.list([new Literal('"c"')])); + writer.addQuad(new NamedNode('a1'), new NamedNode('b'), writer.list([new NamedNode('c')])); + writer.addQuad(new NamedNode('a2'), new NamedNode('b'), writer.list([new Literal('"c"')])); writer.end(function (error, output) { output.should.equal(' ().\n' + ' ("c").\n'); @@ -449,8 +448,8 @@ describe('N3Writer', function () { it('should serialize triples with a three-element list as object', function (done) { var writer = N3Writer(); - writer.addTriple(new NamedNode('a1'), new NamedNode('b'), writer.list([new NamedNode('c'), new NamedNode('d'), new NamedNode('e')])); - writer.addTriple(new NamedNode('a2'), new NamedNode('b'), writer.list([new Literal('"c"'), new Literal('"d"'), new Literal('"e"')])); + writer.addQuad(new NamedNode('a1'), new NamedNode('b'), writer.list([new NamedNode('c'), new NamedNode('d'), new NamedNode('e')])); + writer.addQuad(new NamedNode('a2'), new NamedNode('b'), writer.list([new Literal('"c"'), new Literal('"d"'), new Literal('"e"')])); writer.end(function (error, output) { output.should.equal(' ( ).\n' + ' ("c" "d" "e").\n'); @@ -460,8 +459,8 @@ describe('N3Writer', function () { it('should serialize triples with an empty list as subject', function (done) { var writer = N3Writer(); - writer.addTriple(writer.list(), new NamedNode('b1'), new NamedNode('c')); - writer.addTriple(writer.list([]), new NamedNode('b2'), new NamedNode('c')); + writer.addQuad(writer.list(), new NamedNode('b1'), new NamedNode('c')); + writer.addQuad(writer.list([]), new NamedNode('b2'), new NamedNode('c')); writer.end(function (error, output) { output.should.equal('() .\n' + '() .\n'); @@ -471,8 +470,8 @@ describe('N3Writer', function () { it('should serialize triples with a one-element list as subject', function (done) { var writer = N3Writer(); - writer.addTriple(writer.list([new NamedNode('a')]), new NamedNode('b1'), new NamedNode('c')); - writer.addTriple(writer.list([new NamedNode('a')]), new NamedNode('b2'), new NamedNode('c')); + writer.addQuad(writer.list([new NamedNode('a')]), new NamedNode('b1'), new NamedNode('c')); + writer.addQuad(writer.list([new NamedNode('a')]), new NamedNode('b2'), new NamedNode('c')); writer.end(function (error, output) { output.should.equal('() .\n' + '() .\n'); @@ -482,7 +481,7 @@ describe('N3Writer', function () { it('should serialize triples with a three-element list as subject', function (done) { var writer = N3Writer(); - writer.addTriple(writer.list([new NamedNode('a1'), new Literal('"b"'), new Literal('"c"')]), new NamedNode('d'), new NamedNode('e')); + writer.addQuad(writer.list([new NamedNode('a1'), new Literal('"b"'), new Literal('"c"')]), new NamedNode('d'), new NamedNode('e')); writer.end(function (error, output) { output.should.equal('( "b" "c") .\n'); done(error); @@ -491,8 +490,8 @@ describe('N3Writer', function () { it('should accept triples in bulk', function (done) { var writer = N3Writer(); - writer.addTriples([new Triple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')), - new Triple(new NamedNode('a'), new NamedNode('b'), new NamedNode('d'))]); + writer.addQuads([new Quad(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')), + new Quad(new NamedNode('a'), new NamedNode('b'), new NamedNode('d'))]); writer.end(function (error, output) { output.should.equal(' , .\n'); done(error); @@ -501,19 +500,19 @@ describe('N3Writer', function () { it('should not allow writing after end', function (done) { var writer = N3Writer(); - writer.addTriple(new Triple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c'))); + writer.addQuad(new Quad(new NamedNode('a'), new NamedNode('b'), new NamedNode('c'))); writer.end(); - writer.addTriple(new Triple(new NamedNode('d'), new NamedNode('e'), new NamedNode('f')), function (error) { + writer.addQuad(new Quad(new NamedNode('d'), new NamedNode('e'), new NamedNode('f')), function (error) { error.should.be.an.instanceof(Error); error.should.have.property('message', 'Cannot write because the writer has been closed.'); done(); }); }); - it('should write simple triples in N-Triples mode', function (done) { - var writer = N3Writer({ format: 'N-Triples' }); - writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')); - writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('d')); + it('should write simple triples in N-Quads mode', function (done) { + var writer = N3Writer({ format: 'N-Quads' }); + writer.addQuad(new NamedNode('a'), new NamedNode('b'), new NamedNode('c')); + writer.addQuad(new NamedNode('a'), new NamedNode('b'), new NamedNode('d')); writer.end(function (error, output) { output.should.equal(' .\n .\n'); done(error); @@ -524,8 +523,8 @@ describe('N3Writer', function () { var writer = N3Writer({ format: 'N-Quads' }); var called = false; function callback() { called = true; } - writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('c'), callback); - writer.addTriple(new NamedNode('a'), new NamedNode('b'), new NamedNode('d'), new NamedNode('g')); + writer.addQuad(new NamedNode('a'), new NamedNode('b'), new NamedNode('c'), callback); + writer.addQuad(new NamedNode('a'), new NamedNode('b'), new NamedNode('d'), new NamedNode('g')); writer.end(function (error, output) { called.should.be.true; output.should.equal(' .\n .\n'); @@ -573,7 +572,7 @@ function shouldSerialize(/* prefixes?, tripleArrays..., expectedResult */) { (function next() { var item = tripleArrays.shift(); if (item) - writer.addTriple(new Quad(Term.fromId(item[0]), Term.fromId(item[1]), Term.fromId(item[2]), Term.fromId(item[3])), next); + writer.addQuad(new Quad(Term.fromId(item[0]), Term.fromId(item[1]), Term.fromId(item[2]), Term.fromId(item[3])), next); else writer.end(function (error) { try {