Comparing version 0.4.3 to 0.4.4
@@ -30,3 +30,3 @@ // **N3Lexer** tokenizes N3 documents. | ||
this._tokenize(input, function (error, token) { | ||
if (!error && /IRI|prefixed|literal|langcode|type|\.|eof/.test(token.type)) | ||
if (!error && /^(?:IRI|prefixed|literal|langcode|type|\.|eof)$/.test(token.type)) | ||
callback && callback(error, token); | ||
@@ -104,6 +104,4 @@ else | ||
// Try to find a full IRI without escape sequences. | ||
if (match = this._unescapedIri.exec(input)) { | ||
type = 'IRI'; | ||
value = match[1]; | ||
} | ||
if (match = this._unescapedIri.exec(input)) | ||
type = 'IRI', value = match[1]; | ||
// Try to find a full IRI with escape sequences. | ||
@@ -114,4 +112,3 @@ else if (match = this._iri.exec(input)) { | ||
return reportSyntaxError(this); | ||
type = 'IRI'; | ||
value = unescaped; | ||
type = 'IRI', value = unescaped; | ||
} | ||
@@ -125,7 +122,4 @@ break; | ||
if ((match = this._blank.exec(input)) || | ||
inputFinished && (match = this._blank.exec(input + ' '))) { | ||
type = 'prefixed'; | ||
prefix = '_'; | ||
value = match[1]; | ||
} | ||
inputFinished && (match = this._blank.exec(input + ' '))) | ||
type = 'prefixed', prefix = '_', value = match[1]; | ||
break; | ||
@@ -136,6 +130,4 @@ | ||
// Try to find a non-empty double-quoted literal without escape sequences. | ||
if (match = this._unescapedString.exec(input)) { | ||
type = 'literal'; | ||
value = match[0]; | ||
} | ||
if (match = this._unescapedString.exec(input)) | ||
type = 'literal', value = match[0]; | ||
// Try to find any other literal wrapped in a pair of single or double quotes. | ||
@@ -146,4 +138,3 @@ else if (match = this._singleQuotedString.exec(input)) { | ||
return reportSyntaxError(this); | ||
type = 'literal'; | ||
value = unescaped.replace(/^'|'$/g, '"'); | ||
type = 'literal', value = unescaped.replace(/^'|'$/g, '"'); | ||
} | ||
@@ -158,4 +149,3 @@ // Try to find a literal wrapped in three pairs of single or double quotes. | ||
return reportSyntaxError(this); | ||
type = 'literal'; | ||
value = unescaped.replace(/^'|'$/g, '"'); | ||
type = 'literal', value = unescaped.replace(/^'|'$/g, '"'); | ||
} | ||
@@ -166,10 +156,7 @@ break; | ||
// Try to find a language code. | ||
if (this._prevTokenType === 'literal' && (match = this._langcode.exec(input))) { | ||
type = 'langcode'; | ||
value = match[1]; | ||
} | ||
if (this._prevTokenType === 'literal' && (match = this._langcode.exec(input))) | ||
type = 'langcode', value = match[1]; | ||
// Try to find a keyword. | ||
else if (match = this._keyword.exec(input)) { | ||
else if (match = this._keyword.exec(input)) | ||
type = match[0]; | ||
} | ||
break; | ||
@@ -222,6 +209,4 @@ | ||
// Try to match a boolean. | ||
if (match = this._boolean.exec(input)) { | ||
type = 'literal'; | ||
value = '"' + match[0] + '"^^http://www.w3.org/2001/XMLSchema#boolean'; | ||
} | ||
if (match = this._boolean.exec(input)) | ||
type = 'literal', value = '"' + match[0] + '"^^http://www.w3.org/2001/XMLSchema#boolean'; | ||
else | ||
@@ -233,6 +218,4 @@ inconclusive = true; | ||
// 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'; | ||
} | ||
if (match = this._shortPredicates.exec(input)) | ||
type = 'abbreviation', value = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'; | ||
else | ||
@@ -263,6 +246,4 @@ inconclusive = true; | ||
if ((this._prevTokenType === '@prefix' || this._prevTokenType === 'PREFIX') && | ||
(match = this._prefix.exec(input))) { | ||
type = 'prefix'; | ||
value = match[1] || ''; | ||
} | ||
(match = this._prefix.exec(input))) | ||
type = 'prefix', value = match[1] || ''; | ||
// Try to find a prefixed name. Since it can contain (but not end with) a dot, | ||
@@ -272,7 +253,4 @@ // we always need a non-dot character before deciding it is a prefixed name. | ||
else if ((match = this._prefixed.exec(input)) || | ||
inputFinished && (match = this._prefixed.exec(input + ' '))) { | ||
type = 'prefixed'; | ||
prefix = match[1] || ''; | ||
value = this._unescape(match[2]); | ||
} | ||
inputFinished && (match = this._prefixed.exec(input + ' '))) | ||
type = 'prefixed', prefix = match[1] || '', value = this._unescape(match[2]); | ||
} | ||
@@ -384,5 +362,4 @@ | ||
function end() { | ||
if (self._input !== null) { | ||
if (self._input !== null) | ||
self._tokenizeToEnd(callback, true); | ||
} | ||
} | ||
@@ -389,0 +366,0 @@ }, |
@@ -9,5 +9,5 @@ // **N3Parser** parses N3 documents. | ||
var absoluteIRI = /:/, | ||
documentPart = /[^\/]*$/, | ||
rootIRI = /^(?:[^:]+:\/*)?[^\/]*/; | ||
var absoluteIRI = /^[a-z][a-z0-9+.-]*:/i, | ||
schemeAuthority = /^(?:([a-z][a-z0-9+.-]*:))?(?:\/\/[^\/]*)?/i, | ||
dotSegments = /(?:^|\/)\.\.?(?:$|[\/#?])/; | ||
@@ -26,13 +26,3 @@ // The next ID for new blank nodes | ||
options = options || {}; | ||
if (!options.documentIRI) { | ||
this._baseIRI = null; | ||
this._baseIRIPath = null; | ||
} | ||
else { | ||
if (options.documentIRI.indexOf('#') > 0) | ||
throw new Error('Invalid document IRI'); | ||
this._baseIRI = options.documentIRI; | ||
this._baseIRIPath = this._baseIRI.replace(documentPart, ''); | ||
this._baseIRIRoot = this._baseIRI.match(rootIRI)[0]; | ||
} | ||
this._setBase(options.documentIRI); | ||
@@ -49,3 +39,3 @@ // Set supported features depending on the format. | ||
if (isLineMode) { | ||
this._baseIRI = ''; | ||
this._base = ''; | ||
this._resolveIRI = function (token) { | ||
@@ -71,2 +61,17 @@ this._error('Disallowed relative IRI', token); | ||
// ### `_setBase` sets the base IRI to resolve relative IRIs. | ||
_setBase: function (baseIRI) { | ||
if (!baseIRI) | ||
baseIRI = null; | ||
else if (baseIRI.indexOf('#') >= 0) | ||
throw new Error('Invalid base IRI ' + baseIRI); | ||
// Set base IRI and its components | ||
if (this._base = baseIRI) { | ||
this._basePath = baseIRI.replace(/[^\/?]*(?:\?.*)?$/, ''); | ||
baseIRI = baseIRI.match(schemeAuthority); | ||
this._baseRoot = baseIRI[0]; | ||
this._baseScheme = baseIRI[1]; | ||
} | ||
}, | ||
// ### `_readInTopContext` reads a token when in the top context. | ||
@@ -103,5 +108,4 @@ _readInTopContext: function (token) { | ||
case 'GRAPH': | ||
if (this._supportsNamedGraphs) { | ||
if (this._supportsNamedGraphs) | ||
return this._readNamedGraphLabel; | ||
} | ||
// Otherwise, the next token must be a subject. | ||
@@ -118,3 +122,3 @@ default: | ||
case 'IRI': | ||
if (this._baseIRI === null || absoluteIRI.test(token.value)) | ||
if (this._base === null || absoluteIRI.test(token.value)) | ||
this._subject = token.value; | ||
@@ -156,3 +160,3 @@ else | ||
case 'abbreviation': | ||
if (this._baseIRI === null || absoluteIRI.test(token.value)) | ||
if (this._base === null || absoluteIRI.test(token.value)) | ||
this._predicate = token.value; | ||
@@ -163,11 +167,8 @@ else | ||
case 'prefixed': | ||
if (token.prefix === '_') { | ||
if (token.prefix === '_') | ||
return this._error('Disallowed blank node as predicate', token); | ||
} | ||
else { | ||
var prefix = this._prefixes[token.prefix]; | ||
if (prefix === undefined) | ||
return this._error('Undefined prefix "' + token.prefix + ':"', token); | ||
this._predicate = prefix + token.value; | ||
} | ||
var prefix = this._prefixes[token.prefix]; | ||
if (prefix === undefined) | ||
return this._error('Undefined prefix "' + token.prefix + ':"', token); | ||
this._predicate = prefix + token.value; | ||
break; | ||
@@ -196,3 +197,3 @@ case '.': | ||
case 'IRI': | ||
if (this._baseIRI === null || absoluteIRI.test(token.value)) | ||
if (this._base === null || absoluteIRI.test(token.value)) | ||
this._object = token.value; | ||
@@ -248,4 +249,6 @@ else | ||
} | ||
this._predicate = null; | ||
return this._readPredicate(token); | ||
else { | ||
this._predicate = null; | ||
return this._readPredicate(token); | ||
} | ||
}, | ||
@@ -286,3 +289,3 @@ | ||
if (token.prefix === '') { | ||
if (this._baseIRI === null || absoluteIRI.test(token.value)) | ||
if (this._base === null || absoluteIRI.test(token.value)) | ||
value = token.value; | ||
@@ -319,3 +322,6 @@ else | ||
case 'IRI': | ||
item = token.value; | ||
if (this._base === null || absoluteIRI.test(token.value)) | ||
item = token.value; | ||
else | ||
item = this._resolveIRI(token); | ||
break; | ||
@@ -437,3 +443,3 @@ case 'prefixed': | ||
if (this._supportsQuads && this._graph === null) { | ||
if (this._baseIRI === null || absoluteIRI.test(token.value)) | ||
if (this._base === null || absoluteIRI.test(token.value)) | ||
graph = token.value; | ||
@@ -511,3 +517,3 @@ else | ||
var prefixIRI; | ||
if (this._baseIRI === null || absoluteIRI.test(token.value)) | ||
if (this._base === null || absoluteIRI.test(token.value)) | ||
prefixIRI = token.value; | ||
@@ -525,10 +531,7 @@ else | ||
return this._error('Expected IRI to follow base declaration', token); | ||
if (token.value.indexOf('#') > 0) | ||
return this._error('Invalid base IRI', token); | ||
if (this._baseIRI === null || absoluteIRI.test(token.value)) | ||
this._baseIRI = token.value; | ||
else | ||
this._baseIRI = this._resolveIRI(token); | ||
this._baseIRIPath = this._baseIRI.replace(documentPart, ''); | ||
this._baseIRIRoot = this._baseIRI.match(rootIRI)[0]; | ||
try { | ||
this._setBase(this._base === null || | ||
absoluteIRI.test(token.value) ? token.value : this._resolveIRI(token)); | ||
} | ||
catch (error) { this._error(error.message, token); } | ||
return this._readDeclarationPunctuation; | ||
@@ -588,3 +591,4 @@ }, | ||
// ### `_resolveIRI` resolves an IRI token against the base path | ||
// ### `_resolveIRI` resolves a relative IRI token against the base path, | ||
// assuming that a base path has been set and that the IRI is indeed relative. | ||
_resolveIRI: function (token) { | ||
@@ -594,19 +598,79 @@ var iri = token.value; | ||
// An empty relative IRI indicates the base IRI | ||
case undefined: | ||
return this._baseIRI; | ||
case undefined: return this._base; | ||
// Resolve relative fragment IRIs against the base IRI | ||
case '#': | ||
return this._baseIRI + iri; | ||
case '#': return this._base + iri; | ||
// Resolve relative query string IRIs by replacing the query string | ||
case '?': | ||
return this._baseIRI.replace(/(?:\?.*)?$/, iri); | ||
// Resolve root relative IRIs at the root of the base IRI | ||
case '?': return this._base.replace(/(?:\?.*)?$/, iri); | ||
// Resolve root-relative IRIs at the root of the base IRI | ||
case '/': | ||
return this._baseIRIRoot + iri; | ||
// Resolve scheme-relative IRIs to the scheme | ||
return (iri[1] === '/' ? this._baseScheme : this._baseRoot) + this._removeDotSegments(iri); | ||
// Resolve all other IRIs at the base IRI's path | ||
default: | ||
return this._baseIRIPath + iri; | ||
return this._removeDotSegments(this._basePath + iri); | ||
} | ||
}, | ||
// ### `_removeDotSegments` resolves './' and '../' path segments in an IRI as per RFC3986. | ||
_removeDotSegments: function (iri) { | ||
// Don't modify the IRI if it does not contain any dot segments | ||
if (!dotSegments.test(iri)) | ||
return iri; | ||
// Start with an imaginary slash before the IRI in order to resolve trailing './' and '../' | ||
var result = '', length = iri.length, i = -1, pathStart = -1, segmentStart = 0, next = '/'; | ||
while (i < length) { | ||
switch (next) { | ||
// The path starts with the first slash after the authority | ||
case ':': | ||
if (pathStart < 0) { | ||
// Skip two slashes before the authority | ||
if (iri[++i] === '/' && iri[++i] === '/') | ||
// Skip to slash after the authority | ||
while ((pathStart = i + 1) < length && iri[pathStart] !== '/') | ||
i = pathStart; | ||
} | ||
break; | ||
// Don't modify a query string or fragment | ||
case '?': | ||
case '#': | ||
i = length; | ||
break; | ||
// Handle '/.' or '/..' path segments | ||
case '/': | ||
if (iri[i + 1] === '.') { | ||
next = iri[++i + 1]; | ||
switch (next) { | ||
// Remove a '/.' segment | ||
case '/': | ||
result += iri.substring(segmentStart, i - 1); | ||
segmentStart = i + 1; | ||
break; | ||
// Remove a trailing '/.' segment | ||
case undefined: | ||
case '?': | ||
case '#': | ||
return result + iri.substring(segmentStart, i) + iri.substr(i + 1); | ||
// Remove a '/..' segment | ||
case '.': | ||
next = iri[++i + 1]; | ||
if (next === undefined || next === '/' || next === '?' || next === '#') { | ||
result += iri.substring(segmentStart, i - 2); | ||
// Try to remove the parent path from result | ||
if ((segmentStart = result.lastIndexOf('/')) >= pathStart) | ||
result = result.substr(0, segmentStart); | ||
// Remove a trailing '/..' segment | ||
if (next !== '/') | ||
return result + '/' + iri.substr(i + 1); | ||
segmentStart = i + 1; | ||
} | ||
} | ||
} | ||
} | ||
next = iri[++i]; | ||
} | ||
return result + iri.substring(segmentStart); | ||
}, | ||
// ## Public methods | ||
@@ -644,3 +708,3 @@ | ||
} | ||
} | ||
}, | ||
}; | ||
@@ -647,0 +711,0 @@ |
@@ -155,7 +155,3 @@ // **N3Store** objects store N3 triples by graph in memory. | ||
if (!graphItem) { | ||
graphItem = this._graphs[graph] = { | ||
subjects: {}, | ||
predicates: {}, | ||
objects: {} | ||
}; | ||
graphItem = this._graphs[graph] = { subjects: {}, predicates: {}, objects: {} }; | ||
// Freezing a graph helps subsequent `add` performance, | ||
@@ -162,0 +158,0 @@ // and properties will never be modified anyway. |
@@ -100,3 +100,3 @@ // **N3Util** provides N3 utility functions | ||
// Add the N3Util functions to the given object or its prototype | ||
function AddN3Util(parent, toPrototype) { | ||
function addN3Util(parent, toPrototype) { | ||
for (var name in N3Util) | ||
@@ -106,3 +106,3 @@ if (!toPrototype) | ||
else | ||
parent.prototype[name] = ApplyToThis(N3Util[name]); | ||
parent.prototype[name] = applyToThis(N3Util[name]); | ||
@@ -113,3 +113,3 @@ return parent; | ||
// Returns a function that applies `f` to the `this` object | ||
function ApplyToThis(f) { | ||
function applyToThis(f) { | ||
return function (a) { return f(this, a); }; | ||
@@ -119,2 +119,2 @@ } | ||
// Expose N3Util, attaching all functions to it | ||
module.exports = AddN3Util(AddN3Util); | ||
module.exports = addN3Util(addN3Util); |
@@ -68,3 +68,5 @@ // **N3Writer** writes N3 documents. | ||
(graph ? this._encodeIriOrBlankNode(graph) + ' {\n' : '')); | ||
this._graph = graph, this._subject = null; | ||
this._subject = null; | ||
// Don't treat identical blank nodes as repeating graphs | ||
this._graph = graph[0] !== '[' ? graph : ']'; | ||
} | ||
@@ -107,12 +109,14 @@ // Don't repeat the subject if it's the same | ||
// ### `_encodeIriOrBlankNode` represents an IRI or blank node | ||
_encodeIriOrBlankNode: function (iri) { | ||
// A blank node is represented as-is | ||
if (iri[0] === '_' && iri[1] === ':') return iri; | ||
_encodeIriOrBlankNode: function (entity) { | ||
// A blank node or list is represented as-is | ||
var firstChar = entity[0]; | ||
if (firstChar === '[' || firstChar === '(' || firstChar === '_' && entity[1] === ':') | ||
return entity; | ||
// Escape special characters | ||
if (escape.test(iri)) | ||
iri = iri.replace(escapeAll, characterReplacer); | ||
if (escape.test(entity)) | ||
entity = entity.replace(escapeAll, characterReplacer); | ||
// Try to represent the IRI as prefixed name | ||
var prefixMatch = this._prefixRegex.exec(iri); | ||
return !prefixMatch ? '<' + iri + '>' : | ||
(!prefixMatch[1] ? iri : this._prefixIRIs[prefixMatch[1]] + prefixMatch[2]); | ||
var prefixMatch = this._prefixRegex.exec(entity); | ||
return !prefixMatch ? '<' + entity + '>' : | ||
(!prefixMatch[1] ? entity : this._prefixIRIs[prefixMatch[1]] + prefixMatch[2]); | ||
}, | ||
@@ -138,2 +142,5 @@ | ||
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); | ||
@@ -168,3 +175,3 @@ }, | ||
// The triple was given as a triple object, so shift parameters | ||
if (typeof object !== 'string') | ||
if (object === undefined) | ||
this._writeTriple(subject.subject, subject.predicate, subject.object, | ||
@@ -227,2 +234,54 @@ subject.graph || '', predicate); | ||
// ### `blank` creates a blank node with the given content | ||
blank: function (predicate, object) { | ||
var children = predicate, child, length; | ||
// Empty blank node | ||
if (predicate === undefined) | ||
children = []; | ||
// Blank node passed as blank("predicate", "object") | ||
else if (typeof predicate === 'string') | ||
children = [{ predicate: predicate, object: object }]; | ||
// Blank node passed as blank({ predicate: predicate, object: object }) | ||
else if (!('length' in predicate)) | ||
children = [predicate]; | ||
switch (length = children.length) { | ||
// Generate an empty blank node | ||
case 0: | ||
return '[]'; | ||
// 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) + ' ]'; | ||
// Generate a multi-triple or nested blank node | ||
default: | ||
var contents = '['; | ||
// Write all triples in order | ||
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); | ||
// Otherwise, write the predicate and the object | ||
else { | ||
contents += (i ? ';\n ' : '\n ') + | ||
this._encodePredicate(child.predicate) + ' ' + | ||
this._encodeObject(child.object); | ||
predicate = child.predicate; | ||
} | ||
} | ||
return contents + '\n]'; | ||
} | ||
}, | ||
// ### `list` creates a list node with the given content | ||
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]); | ||
return '(' + contents.join(' ') + ')'; | ||
}, | ||
// ### `_prefixRegex` matches a prefixed name or IRI that begins with one of the added prefixes | ||
@@ -229,0 +288,0 @@ _prefixRegex: /$0^/, |
{ | ||
"name": "n3", | ||
"version": "0.4.3", | ||
"version": "0.4.4", | ||
"description": "Lightning fast, asynchronous, streaming Turtle / N3 / RDF library.", | ||
@@ -25,5 +25,5 @@ "author": "Ruben Verborgh <ruben.verborgh@gmail.com>", | ||
"docco": "~0.6.2", | ||
"eslint": "~0.19.0", | ||
"eslint": "~1.2.1", | ||
"istanbul": "~0.3.0", | ||
"mocha": "~1.15.0", | ||
"mocha": "~2.3.0", | ||
"pre-commit": "~0.0.9", | ||
@@ -30,0 +30,0 @@ "request": "~2.22.0", |
#!/usr/bin/env node | ||
var N3 = require('../N3'); | ||
var fs = require('fs'), | ||
path = require('path'), | ||
assert = require('assert'); | ||
@@ -9,3 +10,4 @@ | ||
var filename = process.argv[2]; | ||
var filename = path.resolve(process.cwd(), process.argv[2]), | ||
base = 'file://' + filename; | ||
@@ -16,7 +18,6 @@ var TEST = '- Parsing file ' + filename; | ||
var count = 0; | ||
new N3.Parser().parse(fs.createReadStream(filename), function (error, triple) { | ||
new N3.Parser({ documentIRI: base }).parse(fs.createReadStream(filename), function (error, triple) { | ||
assert(!error, error); | ||
if (triple) { | ||
if (triple) | ||
count++; | ||
} | ||
else { | ||
@@ -23,0 +24,0 @@ console.timeEnd(TEST); |
@@ -17,5 +17,6 @@ #!/usr/bin/env node | ||
console.time(TEST); | ||
for (var i = 0; i < dim; i++) | ||
for (var j = 0; j < dim; j++) | ||
for (var k = 0; k < dim; k++) | ||
var i, j, k; | ||
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); | ||
@@ -22,0 +23,0 @@ console.timeEnd(TEST); |
@@ -9,9 +9,9 @@ # Lightning fast, asynchronous, streaming RDF for JavaScript | ||
[TriG](http://www.w3.org/TR/trig/), | ||
[N-Triples](http://www.w3.org/TR/ntriples/) | ||
and [N-Quads](http://www.w3.org/TR/nquads/). | ||
[N-Triples](http://www.w3.org/TR/n-triples/) | ||
and [N-Quads](http://www.w3.org/TR/n-quads/). | ||
- [**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/ntriples/) | ||
and [N-Quads](http://www.w3.org/TR/nquads/). | ||
[N-Triples](http://www.w3.org/TR/n-triples/) | ||
and [N-Quads](http://www.w3.org/TR/n-quads/). | ||
- **Storage** of triples/quads in memory | ||
@@ -203,3 +203,3 @@ | ||
``` js | ||
var writer = N3.Writer({ prefixes: { 'c': 'http://example.org/cartoons#' } }); | ||
var writer = N3.Writer({ prefixes: { c: 'http://example.org/cartoons#' } }); | ||
writer.addTriple('http://example.org/cartoons#Tom', | ||
@@ -230,3 +230,3 @@ 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', | ||
``` js | ||
var writer = N3.Writer(process.stdout, { prefixes: { 'c': 'http://example.org/cartoons#' } }); | ||
var writer = N3.Writer(process.stdout, { prefixes: { c: 'http://example.org/cartoons#' } }); | ||
writer.addTriple('http://example.org/cartoons#Tom', | ||
@@ -250,3 +250,3 @@ 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', | ||
inputStream = fs.createReadStream('cartoons.ttl'), | ||
streamWriter = new N3.StreamWriter({ prefixes: { 'c': 'http://example.org/cartoons#' } }); | ||
streamWriter = new N3.StreamWriter({ prefixes: { c: 'http://example.org/cartoons#' } }); | ||
inputStream.pipe(streamParser); | ||
@@ -257,2 +257,37 @@ streamParser.pipe(streamWriter); | ||
### Blank nodes and lists | ||
You might want to use the `[…]` and list `(…)` notations of Turtle and TriG. | ||
However, a streaming writer cannot create these automatically: | ||
the shorthand notations are only possible if blank nodes or list heads are not used later on, | ||
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); }); | ||
``` | ||
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 | ||
@@ -326,3 +361,3 @@ | ||
``` js | ||
var prefixes = { 'rdfs': 'http://www.w3.org/2000/01/rdf-schema#' }; | ||
var prefixes = { rdfs: 'http://www.w3.org/2000/01/rdf-schema#' }; | ||
N3Util.isPrefixedName('rdfs:label'); // true; | ||
@@ -329,0 +364,0 @@ N3Util.expandPrefixedName('rdfs:label', prefixes); // http://www.w3.org/2000/01/rdf-schema#label |
@@ -68,3 +68,3 @@ #!/usr/bin/env node | ||
async.series({ actionStream: self._fetch.bind(self, test.action), | ||
resultStream: self._fetch.bind(self, test.result), }, | ||
resultStream: self._fetch.bind(self, test.result) }, | ||
function (error, results) { | ||
@@ -92,3 +92,3 @@ if (error) return callback(error); | ||
process.exit(tests.every(function (test) { return test.success; }) ? 0 : 1); | ||
} | ||
}, | ||
], | ||
@@ -162,3 +162,3 @@ function (error) { | ||
config = { format: this._name, documentIRI: url.resolve(this._manifest, test.action) }, | ||
parser = N3.Parser(config), self = this; | ||
parser = new N3.Parser(config), self = this; | ||
parser.parse(actionStream, function (error, triple) { | ||
@@ -224,4 +224,4 @@ if (error) test.error = error; | ||
if (/\.nq/.test(expected)) { | ||
fs.writeFileSync(actual += '.trig', NQuadsToTrig(results.actualContents)); | ||
fs.writeFileSync(expected += '.trig', NQuadsToTrig(results.expectedContents)); | ||
fs.writeFileSync(actual += '.trig', quadsToTrig(results.actualContents)); | ||
fs.writeFileSync(expected += '.trig', quadsToTrig(results.expectedContents)); | ||
} | ||
@@ -231,3 +231,3 @@ exec('sparql -d ' + expected + ' --compare ' + actual, | ||
} | ||
function NQuadsToTrig(nquad) { | ||
function quadsToTrig(nquad) { | ||
return nquad.replace(/^([^\s]+)\s+([^\s]+)\s+(.+)\s+([^\s"]+)\s*\.$/mg, '$4 { $1 $2 $3 }'); | ||
@@ -234,0 +234,0 @@ } |
var N3Lexer = require('../N3').Lexer; | ||
var chai = require('chai'), | ||
expect = chai.expect, | ||
events = require('events'); | ||
var expect = chai.expect; | ||
chai.should(); | ||
@@ -366,5 +366,5 @@ | ||
{ type: 'literal', value: '"10e20"^^http://www.w3.org/2001/XMLSchema#double', line: 1 }, | ||
{ type: ',', line: 1}, | ||
{ type: ',', line: 1 }, | ||
{ type: 'literal', value: '"+30.40E+50"^^http://www.w3.org/2001/XMLSchema#double', line: 1 }, | ||
{ type: '.', line: 1}, | ||
{ type: '.', line: 1 }, | ||
{ type: 'literal', value: '"-60.70e-80"^^http://www.w3.org/2001/XMLSchema#double', line: 1 }, | ||
@@ -725,3 +725,3 @@ { type: '.', line: 1 }, | ||
else if (token.type === 'eof') | ||
throw new Error("Expected error " + expectedError); | ||
throw new Error('Expected error ' + expectedError); | ||
} | ||
@@ -728,0 +728,0 @@ }; |
var N3Store = require('../N3').Store; | ||
var chai = require('chai'), | ||
expect = chai.expect; | ||
var chai = require('chai'); | ||
var expect = chai.expect; | ||
chai.should(); | ||
@@ -50,5 +50,5 @@ chai.use(require('chai-things')); | ||
var store = new N3Store([ | ||
{ subject: 's1', predicate: 'p1', object: 'o1'}, | ||
{ subject: 's1', predicate: 'p1', object: 'o2'}, | ||
{ subject: 's1', predicate: 'p1', object: 'o3'}, | ||
{ subject: 's1', predicate: 'p1', object: 'o1' }, | ||
{ subject: 's1', predicate: 'p1', object: 'o2' }, | ||
{ subject: 's1', predicate: 'p1', object: 'o3' }, | ||
]); | ||
@@ -64,6 +64,6 @@ | ||
store.addTriple('s1', 'p1', 'o1'); | ||
store.addTriple({ subject: 's1', predicate: 'p1', object: 'o2'}); | ||
store.addTriple({ subject: 's1', predicate: 'p1', object: 'o2' }); | ||
store.addTriples([ | ||
{ subject: 's1', predicate: 'p2', object: 'o2'}, | ||
{ subject: 's2', predicate: 'p1', object: 'o1'}, | ||
{ subject: 's1', predicate: 'p2', object: 'o2' }, | ||
{ subject: 's2', predicate: 'p1', object: 'o1' }, | ||
]); | ||
@@ -346,4 +346,4 @@ store.addTriple('s1', 'p2', 'o3', 'c4'); | ||
store.removeTriples([ | ||
{ subject: 's1', predicate: 'p2', object: 'o2'}, | ||
{ subject: 's2', predicate: 'p1', object: 'o1'}, | ||
{ subject: 's1', predicate: 'p2', object: 'o2' }, | ||
{ subject: 's2', predicate: 'p1', object: 'o1' }, | ||
]); | ||
@@ -377,3 +377,3 @@ }); | ||
], | ||
{ prefixes: { 'a': 'http://foo.org/#', 'b': 'http://bar.org/', 'g': 'http://graphs.org/#' } }); | ||
{ prefixes: { a: 'http://foo.org/#', b: 'http://bar.org/', g: 'http://graphs.org/#' } }); | ||
@@ -417,3 +417,3 @@ describe('should allow to query subjects with prefixes', function () { | ||
store.addPrefix('a', 'http://foo.org/#'); | ||
store.addPrefixes({ 'b': 'http://bar.org/', 'g': 'http://graphs.org/#' }); | ||
store.addPrefixes({ b: 'http://bar.org/', g: 'http://graphs.org/#' }); | ||
@@ -454,3 +454,3 @@ describe('should allow to query subjects with prefixes', function () { | ||
], | ||
{ prefixes: { 'http': 'http://www.w3.org/2006/http#' } }); | ||
{ prefixes: { http: 'http://www.w3.org/2006/http#' } }); | ||
@@ -466,3 +466,3 @@ describe('should allow to query subjects without prefixes', function () { | ||
describe('An N3Store created without triples but with prefixes', function () { | ||
var store = new N3Store({ prefixes: { 'http': 'http://www.w3.org/2006/http#' } }); | ||
var store = new N3Store({ prefixes: { http: 'http://www.w3.org/2006/http#' } }); | ||
store.addTriple('a', 'http://www.w3.org/2006/http#b', 'c'); | ||
@@ -469,0 +469,0 @@ |
@@ -6,3 +6,2 @@ var N3StreamWriter = require('../N3').StreamWriter; | ||
chai.should(); | ||
chai.use(require('chai-things')); | ||
@@ -9,0 +8,0 @@ describe('N3StreamWriter', function () { |
var N3Util = require('../N3').Util; | ||
var chai = require('chai'), | ||
expect = chai.expect; | ||
var chai = require('chai'); | ||
var expect = chai.expect; | ||
chai.should(); | ||
@@ -264,7 +264,7 @@ | ||
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.equal('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.equal('"a"^^http://ex.org/#type'); | ||
}); | ||
@@ -277,3 +277,3 @@ | ||
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.equal('a:Test'); | ||
}); | ||
@@ -280,0 +280,0 @@ |
@@ -272,2 +272,207 @@ var N3Writer = require('../N3').Writer; | ||
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.end(function (error, output) { | ||
output.should.equal('<a1> <b> [].\n' + | ||
'<a2> <b> [].\n'); | ||
done(error); | ||
}); | ||
}); | ||
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.end(function (error, output) { | ||
output.should.equal('<a1> <b> [ <d> <e> ].\n' + | ||
'<a2> <b> [ <d> <e> ].\n' + | ||
'<a3> <b> [ <d> <e> ].\n'); | ||
done(error); | ||
}); | ||
}); | ||
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.end(function (error, output) { | ||
output.should.equal('<a> <b> [\n' + | ||
' <d> <e>;\n' + | ||
' <f> "g"\n' + | ||
'].\n'); | ||
done(error); | ||
}); | ||
}); | ||
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.end(function (error, output) { | ||
output.should.equal('<a> <b> [\n' + | ||
' <d> <e>;\n' + | ||
' <f> "g";\n' + | ||
' <h> <i>\n' + | ||
'].\n'); | ||
done(error); | ||
}); | ||
}); | ||
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.end(function (error, output) { | ||
output.should.equal('<a> <b> [\n' + | ||
' <d> <e>, <f>;\n' + | ||
' <g> <h>, <i>\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('a2', 'b', writer.blank([ | ||
{ predicate: 'd', object: writer.blank('e', 'f') }, | ||
{ predicate: 'g', object: writer.blank('h', '"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.end(function (error, output) { | ||
output.should.equal('<a1> <b> [\n' + | ||
' <d> []\n' + | ||
'].\n' + | ||
'<a2> <b> [\n' + | ||
' <d> [ <e> <f> ];\n' + | ||
' <g> [ <h> "i" ]\n' + | ||
'].\n' + | ||
'<a3> <b> [\n' + | ||
' <d> [\n' + | ||
' <g> [ <h> <i> ];\n' + | ||
' <j> [ <k> "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.end(function (error, output) { | ||
output.should.equal('[] <b> <c>.\n' + | ||
'[] <b> <c>.\n'); | ||
done(error); | ||
}); | ||
}); | ||
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.end(function (error, output) { | ||
output.should.equal('[ <a> <b> ] <c> <d>.\n' + | ||
'[ <a> <b> ] <c> <d>.\n' + | ||
'[ <a> <b> ] <c> <d>.\n'); | ||
done(error); | ||
}); | ||
}); | ||
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.end(function (error, output) { | ||
output.should.equal('[] {\n<a> <b> <c>\n}\n' + | ||
'[] {\n<a> <b> <c>\n}\n'); | ||
done(error); | ||
}); | ||
}); | ||
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.end(function (error, output) { | ||
output.should.equal('<a1> <b> ().\n' + | ||
'<a2> <b> ().\n'); | ||
done(error); | ||
}); | ||
}); | ||
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.end(function (error, output) { | ||
output.should.equal('<a1> <b> (<c>).\n' + | ||
'<a2> <b> ("c").\n'); | ||
done(error); | ||
}); | ||
}); | ||
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.end(function (error, output) { | ||
output.should.equal('<a1> <b> (<c> <d> <e>).\n' + | ||
'<a2> <b> ("c" "d" "e").\n'); | ||
done(error); | ||
}); | ||
}); | ||
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.end(function (error, output) { | ||
output.should.equal('() <b1> <c>;\n' + | ||
' <b2> <c>.\n'); | ||
done(error); | ||
}); | ||
}); | ||
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.end(function (error, output) { | ||
output.should.equal('(<a>) <b1> <c>;\n' + | ||
' <b2> <c>.\n'); | ||
done(error); | ||
}); | ||
}); | ||
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.end(function (error, output) { | ||
output.should.equal('(<a> "b" "c") <d> <e>.\n'); | ||
done(error); | ||
}); | ||
}); | ||
it('should accept triples in bulk', function (done) { | ||
@@ -382,3 +587,3 @@ var writer = N3Writer(); | ||
}); | ||
})(); | ||
}()); | ||
}; | ||
@@ -385,0 +590,0 @@ } |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
285935
5350
410
127
2
2
2
23