├── .editorconfig ├── .eslintrc.js ├── .gitignore ├── Makefile ├── README.ipynb ├── README.md ├── UNLICENSE ├── bin ├── node_modules │ └── rdf.js ├── turtle-equal.js └── turtle-nt.js ├── index.js ├── lib ├── BlankNodeMap.js ├── Builtins.js ├── DataFactory.js ├── Dataset.js ├── Graph.js ├── GraphEquals.js ├── GraphSimplyEntails.js ├── Profile.js ├── RDFEnvironment.js ├── RDFNode.js ├── ResultSet.js ├── TurtleParser.js ├── encodeString.js ├── environment.js ├── ns.js ├── prefixes.js └── space.js ├── package.json └── test ├── .eslintrc.js ├── BlankNode.test.js ├── BlankNodeMap.test.js ├── DataFactory.test.js ├── Dataset.test.js ├── DefaultGraph.test.js ├── Graph.test.js ├── Literal.test.js ├── NamedNode.test.js ├── PrefixMap.test.js ├── Profile.test.js ├── Quad.test.js ├── RDF-MT.test.js ├── RDFEnvironment.test.js ├── RDFNode.test.js ├── ResultSet.test.js ├── TermMap.test.js ├── Triple.test.js ├── TriplePattern.test.js ├── TurtleParser.test.js ├── Variable.test.js ├── builtins-Number.test.js ├── builtins-Object.test.js ├── builtins-String.test.js ├── environment.test.js ├── ns.test.js └── parse.test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://EditorConfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = tab 7 | indent_size = 3 8 | end_of_line = lf 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | module.exports = { 3 | "env": { 4 | "node": true, 5 | "es6": true, 6 | }, 7 | "extends": "eslint:recommended", 8 | "parserOptions": { 9 | "ecmaVersion": 6, 10 | }, 11 | "rules": { 12 | "indent": [ "error", "tab", { SwitchCase: 1 } ], 13 | "strict": ["error", "global"], 14 | "no-unused-vars": [ "warn", { "args": "none" } ], 15 | "no-unreachable": [ "error" ], 16 | "linebreak-style": [ "error", "unix" ], 17 | "semi": [ "error", "always" ], 18 | "comma-dangle": [ "error", "always-multiline" ], 19 | "no-console": [ "error" ], 20 | }, 21 | }; 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /test/TurtleTests/ 3 | /test/rdf-mt-tests/ 4 | /.ipynb_checkpoints 5 | /.nyc_output 6 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # You could also set to "wget -o -" 2 | GET="curl" 3 | MOCHA=./node_modules/.bin/mocha 4 | ISTANBUL=./node_modules/.bin/nyc 5 | 6 | all: README.md 7 | 8 | test: test/TurtleTests/manifest.ttl test/rdf-mt-tests/manifest.ttl 9 | $(MOCHA) 10 | 11 | coverage: test/TurtleTests/manifest.ttl 12 | $(ISTANBUL) --reporter=html $(MOCHA) 13 | 14 | test/TurtleTests/manifest.ttl: | test/TurtleTests 15 | 16 | test/TurtleTests: 17 | $(GET) 'https://www.w3.org/2013/TurtleTests/TESTS.tar.gz' | tar -zx -C test -f - 18 | 19 | test/rdf-mt-tests/manifest.ttl: | test/rdf-mt-tests 20 | 21 | test/rdf-mt-tests: 22 | mkdir $@ 23 | $(GET) 'https://www.w3.org/2013/rdf-mt-tests/TESTS.tar.gz' | tar -zx -C test/rdf-mt-tests -f - 24 | 25 | # Edit with: 26 | # $ ijsnotebook README.ipynb 27 | # `cat -s` collapses multiple newlines into a single newline 28 | README.md: README.ipynb 29 | jupyter-nbconvert $< --to markdown --stdout | sed 's/^var /const /' | cat -s > $@ 30 | 31 | clean: 32 | rm -rf README.md coverage 33 | 34 | .PHONY: test clean 35 | -------------------------------------------------------------------------------- /UNLICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /bin/node_modules/rdf.js: -------------------------------------------------------------------------------- 1 | module.exports = require('../../index.js'); 2 | -------------------------------------------------------------------------------- /bin/turtle-equal.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var fs = require('fs'); 4 | 5 | var parse = require('./../index.js').parse; 6 | var TurtleParser = require('rdf').TurtleParser; 7 | var rdfenv = require('rdf').environment; 8 | 9 | var files = process.argv.slice(2); 10 | var baseURI = 'http://example.com/'; 11 | 12 | var graphii = files.map(function(filepath){ 13 | try { 14 | //console.error(filepath); 15 | var inputContents = fs.readFileSync(filepath, 'UTF-8'); 16 | var turtleParser = TurtleParser.parse(inputContents, baseURI); 17 | var outputGraph = turtleParser.graph; 18 | console.log(outputGraph.toArray().map(function(t){ return t.toString()+'\n'; }).join('')); 19 | return outputGraph; 20 | }catch(err){ 21 | console.error(err.stack); 22 | } 23 | }); 24 | 25 | var match = graphii[0].equals(graphii[1]); 26 | if(match){ 27 | console.log(match); 28 | }else{ 29 | console.error('No match'); 30 | process.exit(1); 31 | } 32 | -------------------------------------------------------------------------------- /bin/turtle-nt.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var fs = require('fs'); 4 | 5 | var TurtleParser = require('rdf').TurtleParser; 6 | var rdfenv = require('rdf').environment; 7 | 8 | var files = process.argv.slice(2); 9 | var baseURI = 'http://example.com/'; 10 | 11 | files.forEach(function(filepath){ 12 | try { 13 | //console.error(filepath); 14 | var inputContents = fs.readFileSync(filepath, 'UTF-8'); 15 | var turtleParser = TurtleParser.parse(inputContents, baseURI); 16 | var outputGraph = turtleParser.graph; 17 | console.log(outputGraph.toArray().map(function(t){ return t.toString()+'\n'; }).join('')); 18 | }catch(err){ 19 | console.error(err.stack); 20 | } 21 | }); 22 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /** 4 | * RDF 5 | * 6 | * Implement a mash-up of the RDF Interfaces API, the RDF API, and first and foremost whatever makes sense for Node.js 7 | */ 8 | 9 | var api = exports; 10 | 11 | api.RDFNode = require('./lib/RDFNode.js').RDFNode; 12 | api.Term = api.RDFNode; 13 | api.NamedNode = require('./lib/RDFNode.js').NamedNode; 14 | api.BlankNode = require('./lib/RDFNode.js').BlankNode; 15 | api.Literal = require('./lib/RDFNode.js').Literal; 16 | api.Variable = require('./lib/RDFNode.js').Variable; 17 | 18 | api.Profile = require('./lib/Profile.js').Profile; 19 | api.TermMap = require('./lib/Profile.js').TermMap; 20 | api.PrefixMap = require('./lib/Profile.js').PrefixMap; 21 | api.RDFEnvironment = require('./lib/RDFEnvironment.js').RDFEnvironment; 22 | api.BlankNodeMap = require('./lib/BlankNodeMap.js').BlankNodeMap; 23 | 24 | api.TurtleParser = require('./lib/TurtleParser.js').Turtle; 25 | 26 | api.Graph = require('./lib/Graph.js').Graph; 27 | api.Triple = require('./lib/RDFNode.js').Triple; 28 | api.TriplePattern = require('./lib/RDFNode.js').TriplePattern; 29 | api.ResultSet = require("./lib/ResultSet.js").ResultSet; 30 | 31 | api.DefaultGraph = require('./lib/RDFNode.js').DefaultGraph; 32 | api.Dataset = require('./lib/Dataset.js').Dataset; 33 | api.Quad = require('./lib/RDFNode.js').Quad; 34 | 35 | // DataFactory support 36 | api.DataFactory = require('./lib/DataFactory.js').DataFactory; 37 | api.factory = require('./lib/environment').factory; 38 | // api.namedNode = require('./lib/DataFactory.js').namedNode; 39 | // api.blankNode = require('./lib/DataFactory.js').blankNode; 40 | // api.literal = require('./lib/DataFactory.js').literal; 41 | // api.variable = require('./lib/DataFactory.js').variable; 42 | // api.defaultGraph = require('./lib/DataFactory.js').defaultGraph; 43 | // api.triple = require('./lib/DataFactory.js').triple; 44 | // api.quad = require('./lib/DataFactory.js').quad; 45 | 46 | api.environment = require('./lib/environment').environment; 47 | api.setBuiltins = require('./lib/Builtins').setBuiltins; 48 | api.unsetBuiltins = require('./lib/Builtins').unsetBuiltins; 49 | api.builtins = require('./lib/Builtins'); 50 | api.parse = function(o, id){ 51 | return api.builtins.ref.call(o, id); 52 | }; 53 | 54 | api.ns = require('./lib/ns.js').ns; 55 | api.rdfns = require('./lib/ns.js').rdfns; 56 | api.rdfsns = require('./lib/ns.js').rdfsns; 57 | api.xsdns = require('./lib/ns.js').xsdns; 58 | -------------------------------------------------------------------------------- /lib/BlankNodeMap.js: -------------------------------------------------------------------------------- 1 | 2 | "use strict"; 3 | 4 | var BlankNode = require('./RDFNode.js').BlankNode; 5 | var Triple = require('./RDFNode.js').Triple; 6 | var Quad = require('./RDFNode.js').Quad; 7 | 8 | // Declare or generate a mapping of Variables or BlankNodes to BlankNodes, Terms, or Literals 9 | 10 | module.exports.BlankNodeMap = BlankNodeMap; 11 | function BlankNodeMap(){ 12 | if(!(this instanceof BlankNodeMap)) return new BlankNodeMap(); 13 | this.mapping = {}; 14 | this.start = 0; 15 | this.labelPrefix = 'bn'; 16 | } 17 | 18 | BlankNodeMap.prototype.get = function get(bnode){ 19 | return this.mapping[bnode]; 20 | }; 21 | 22 | BlankNodeMap.prototype.process = function process(bnode){ 23 | if(bnode instanceof Triple){ 24 | return new Triple(this.process(bnode.subject), bnode.predicate, this.process(bnode.object)); 25 | } 26 | if(bnode instanceof Quad){ 27 | return new Quad(this.process(bnode.subject), bnode.predicate, this.process(bnode.object), bnode.graph); 28 | } 29 | if(typeof bnode=='string' && bnode.substring(0,2)!=='_:'){ 30 | bnode = '_:' + bnode; 31 | } 32 | if(this.mapping[bnode]) return this.mapping[bnode]; 33 | if(this.labelPrefix) this.mapping[bnode] = new BlankNode(this.labelPrefix+this.start); 34 | else this.mapping[bnode] = new BlankNode(bnode.toString()); 35 | this.start++; 36 | return this.mapping[bnode]; 37 | }; 38 | 39 | BlankNodeMap.prototype.equals = function equals(bnode, target){ 40 | if(this.mapping[bnode]) return this.mapping[bnode]===target; 41 | this.mapping[bnode] = target; 42 | return true; 43 | }; 44 | -------------------------------------------------------------------------------- /lib/DataFactory.js: -------------------------------------------------------------------------------- 1 | // RDF Representation - DataFactory support 2 | 3 | "use strict"; 4 | 5 | var RDFNode = require('./RDFNode.js'); 6 | var Dataset = require('./Dataset.js').Dataset; 7 | 8 | module.exports.DataFactory = DataFactory; 9 | function DataFactory(){ 10 | // At a future date, have rdf.Environment use DataFactory for its Environment#createFoo methods 11 | // this.blankNodeId = 0; 12 | // this.blankNodeMap = {}; 13 | this.DefaultGraphInstance = new RDFNode.DefaultGraph(); 14 | } 15 | 16 | DataFactory.prototype.namedNode = function namedNode(uri){ 17 | return new RDFNode.NamedNode(uri); 18 | }; 19 | DataFactory.prototype.blankNode = function blankNode(label){ 20 | // If a label is specified, possibly re-use an existing blankNode 21 | return new RDFNode.BlankNode(label); 22 | }; 23 | DataFactory.prototype.literal = function literal(value, dt){ 24 | return new RDFNode.Literal(value, dt); 25 | }; 26 | DataFactory.prototype.variable = function variable(name){ 27 | return new RDFNode.Variable(name); 28 | }; 29 | DataFactory.prototype.defaultGraph = function defaultGraph(){ 30 | return this.DefaultGraphInstance; 31 | }; 32 | DataFactory.prototype.triple = function triple(subject, predicate, object){ 33 | return new RDFNode.Triple(subject, predicate, object); 34 | }; 35 | DataFactory.prototype.quad = function quad(subject, predicate, object, graph){ 36 | return new RDFNode.Quad(subject, predicate, object, graph || this.DefaultGraphInstance); 37 | }; 38 | DataFactory.prototype.dataset = function dataset(src){ 39 | return new Dataset(src); 40 | }; 41 | DataFactory.prototype.fromTerm = function fromTerm(node){ 42 | if(typeof node!=='object') throw new Error('Expected an object `node`'); 43 | if(node instanceof RDFNode.RDFNode) return node; 44 | switch(node.termType){ 45 | case 'NamedNode': return new RDFNode.NamedNode(node.value); 46 | case 'BlankNode': return new RDFNode.BlankNode(node.value); 47 | case 'Literal': return new RDFNode.Literal(node.value, node.language ? node.language : this.fromTerm(node.datatype)); // FIXME 48 | case 'Variable': return new RDFNode.Variable(node.value); 49 | case 'DefaultGraph': return this.DefaultGraphInstance; 50 | } 51 | throw new Error('Unrecognised Term#termType'); 52 | }; 53 | DataFactory.prototype.fromQuad = function fromQuad(quad){ 54 | if(typeof quad!=='object') throw new Error('Expected an object `quad`'); 55 | if(quad instanceof RDFNode.Quad) return quad; 56 | return new RDFNode.Quad(this.fromTerm(quad.subject), this.fromTerm(quad.predicate), this.fromTerm(quad.object), this.fromTerm(quad.graph)); 57 | }; 58 | DataFactory.prototype.fromTriple = function fromTriple(stmt){ 59 | if(typeof stmt!=='object') throw new Error('Expected an object `quad`'); 60 | if(stmt instanceof RDFNode.Triple) return stmt; 61 | return new RDFNode.Triple(this.fromTerm(stmt.subject), this.fromTerm(stmt.predicate), this.fromTerm(stmt.object)); 62 | }; 63 | -------------------------------------------------------------------------------- /lib/Dataset.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var RDFNode = require('./RDFNode.js'); 4 | var Graph = require('./Graph.js').Graph; 5 | 6 | /** 7 | * Read an RDF Collection and return it as an Array 8 | */ 9 | var rdfnil = new RDFNode.NamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'); 10 | var rdffirst = new RDFNode.NamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#first'); 11 | var rdfrest = new RDFNode.NamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#rest'); 12 | 13 | function isIndex(i, a, b, c, d, t){ 14 | if(!i[a]) return false; 15 | if(!i[a][b]) return false; 16 | if(!i[a][b][c]) return false; 17 | return i[a][b][c][d] ? i[a][b][c][d].equals(t) : false ; 18 | } 19 | 20 | function insertIndex(i, a, b, c, d, t){ 21 | if(!i[a]) i[a] = {}; 22 | if(!i[a][b]) i[a][b] = {}; 23 | if(!i[a][b][c]) i[a][b][c] = {}; 24 | i[a][b][c][d] = t; 25 | } 26 | 27 | function deleteIndex(i, a, b, c, d, t){ 28 | if(i[a] && i[a][b] && i[a][b][c] && i[a][b][c][d]){ 29 | if(!i[a][b][c][d].equals(t)) throw new Error('assertion fail: deleted quad mismatch'); 30 | delete(i[a][b][c][d]); 31 | if(!Object.keys(i[a][b][c]).length) delete(i[a][b][c]); 32 | if(!Object.keys(i[a][b]).length) delete(i[a][b]); 33 | if(!Object.keys(i[a]).length) delete(i[a]); 34 | } 35 | } 36 | 37 | exports.Dataset = Dataset; 38 | function Dataset(init){ 39 | this.clear(); 40 | //this._actions = []; 41 | Object.defineProperty(this, 'size', {get: function(){return self.length;}}); 42 | var self = this; 43 | if(init && init.forEach){ 44 | init.forEach(function(t){ self.add(t); }); 45 | } 46 | } 47 | Dataset.prototype.length = null; 48 | Dataset.prototype.graph = null; 49 | 50 | // TODO remove this? What is this doing? 51 | Dataset.prototype.importArray = function(a) { while( a.length > 0) { this.add(a.pop()); } }; 52 | 53 | Dataset.prototype.insertIndex = insertIndex; 54 | Dataset.prototype.deleteIndex = deleteIndex; 55 | Dataset.prototype.add = function(quad) { 56 | if(!(quad instanceof RDFNode.Quad)) throw new TypeError('Expected a Quad for argument[0] `quad`'); 57 | var st=quad.subject.toNT(), pt=quad.predicate.toNT(), ot=quad.object.toNT(), gt=quad.graph.toNT(); 58 | if(isIndex(this.indexSPOG, st, pt, ot, gt, quad)) return; 59 | insertIndex(this.indexSPOG, st, pt, ot, gt, quad); 60 | insertIndex(this.indexPOGS, pt, ot, gt, st, quad); 61 | insertIndex(this.indexOGSP, ot, gt, st, pt, quad); 62 | insertIndex(this.indexGSPO, gt, st, pt, ot, quad); 63 | insertIndex(this.indexGPOS, gt, pt, ot, st, quad); 64 | insertIndex(this.indexOSGP, ot, st, gt, pt, quad); 65 | this.length++; 66 | //this.actions.forEach(function(fn){ fn(quad); }); 67 | }; 68 | Dataset.prototype.addAll = function(g){ 69 | var g2 = this; 70 | g.forEach(function(s){ g2.add(s); }); 71 | }; 72 | Dataset.prototype.union = function union(){ 73 | var gx = new Graph; 74 | this.forEach(function(q){ 75 | gx.add(new RDFNode.Triple(q.subject, q.predicate, q.object)); 76 | }); 77 | return gx; 78 | }; 79 | Dataset.prototype.remove = function(quad) { 80 | var st=quad.subject.toNT(), pt=quad.predicate.toNT(), ot=quad.object.toNT(), gt=quad.graph.toNT(); 81 | if(!isIndex(this.indexSPOG, st, pt, ot, gt, quad)) return; 82 | deleteIndex(this.indexSPOG, st, pt, ot, gt, quad); 83 | deleteIndex(this.indexPOGS, pt, ot, gt, st, quad); 84 | deleteIndex(this.indexOGSP, ot, gt, st, pt, quad); 85 | deleteIndex(this.indexGSPO, gt, st, pt, ot, quad); 86 | deleteIndex(this.indexGPOS, gt, pt, ot, st, quad); 87 | deleteIndex(this.indexOSGP, ot, st, gt, pt, quad); 88 | this.length--; 89 | }; 90 | Dataset.prototype.delete = Dataset.prototype.remove; 91 | Dataset.prototype.has = function(quad) { 92 | if(!(quad instanceof RDFNode.Quad)) throw new TypeError('Expected a Quad for argument[0] `quad`'); 93 | var st=quad.subject.toNT(), pt=quad.predicate.toNT(), ot=quad.object.toNT(), gt=quad.graph.toNT(); 94 | return isIndex(this.indexSPOG, st, pt, ot, gt, quad); 95 | }; 96 | Dataset.prototype.removeMatches = function(s, p, o, g) { 97 | var self = this; 98 | this.match(s, p, o, g).forEach(function(t) { 99 | self.remove(t); 100 | }); 101 | }; 102 | Dataset.prototype.deleteMatches = Dataset.prototype.removeMatches; 103 | Dataset.prototype.clear = function(){ 104 | this.indexSPOG = {}; 105 | this.indexPOGS = {}; 106 | this.indexOGSP = {}; 107 | this.indexGSPO = {}; 108 | this.indexGPOS = {}; 109 | this.indexOSGP = {}; 110 | this.length = 0; 111 | }; 112 | Dataset.prototype.import = function(s) { 113 | var _g1 = 0, _g = s.length; 114 | while(_g1 < _g) { 115 | var i = _g1++; 116 | this.add(s.get(i)); 117 | } 118 | }; 119 | Dataset.prototype.every = function every(filter) { return this.toArray().every(filter); }; 120 | Dataset.prototype.some = function some(filter) { return this.toArray().some(filter); }; 121 | Dataset.prototype.forEach = function forEach(callbck) { this.toArray().forEach(callbck); }; 122 | Dataset.prototype.toArray = function toArray() { 123 | var quads = []; 124 | var data = this.indexSPOG; 125 | if(!data) return []; 126 | (function go(data, c){ 127 | if(c) Object.keys(data).forEach(function(t){go(data[t], c-1);}); 128 | else quads.push(data); 129 | })(data, 4); 130 | return quads; 131 | }; 132 | Dataset.prototype.filter = function filter(cb){ 133 | var result = new Dataset; 134 | this.forEach(function(quad){ 135 | if(cb(quad)) result.add(quad); 136 | }); 137 | return result; 138 | }; 139 | Dataset.prototype.getCollection = function getCollection(subject){ 140 | var collection=[], seen=[]; 141 | var first, rest=subject; 142 | while(rest && !rest.equals(rdfnil)){ 143 | var g = this.match(rest, rdffirst, null); 144 | if(g.length===0) throw new Error('Collection <'+rest+'> is incomplete'); 145 | first = g.toArray().map(function(v){return v.object;})[0]; 146 | if(seen.indexOf(rest.toString())!==-1) throw new Error('Collection <'+rest+'> is circular'); 147 | seen.push(rest.toString()); 148 | collection.push(first); 149 | rest = this.match(rest, rdfrest, null).toArray().map(function(v){return v.object;})[0]; 150 | } 151 | return collection; 152 | }; 153 | // FIXME ensure that the RDFNode#equals semantics are met 154 | 155 | Dataset.prototype.match = function match(subject, predicate, object, graph){ 156 | // if the String prototype has a nodeType/toNT function, builtins is enabled, 157 | if(typeof subject=="string" && typeof subject.toNT!='function') subject = new RDFNode.NamedNode(subject); 158 | if(subject!==null && !RDFNode.RDFNode.is(subject)) throw new Error('match subject is not an RDFNode'); 159 | if(subject!==null && subject.termType!=='NamedNode' && subject.termType!=='BlankNode') throw new Error('match subject must be a NamedNode/BlankNode'); 160 | if(typeof predicate=="string" && typeof predicate.toNT!='function') predicate = new RDFNode.NamedNode(predicate); 161 | if(predicate!==null && !RDFNode.RDFNode.is(predicate)) throw new Error('match predicate is not an RDFNode'); 162 | if(predicate!==null && predicate.termType!=='NamedNode') throw new Error('match predicate must be a NamedNode'); 163 | if(typeof object=="string" && typeof object.toNT!='function') object = new RDFNode.NamedNode(object); 164 | if(object!==null && !RDFNode.RDFNode.is(object)) throw new Error('match object is not an RDFNode'); 165 | if(object!==null && object.termType!=='NamedNode' && object.termType!=='BlankNode' && object.termType!=='Literal') throw new Error('match object must be a NamedNode/BlankNode/Literal'); 166 | if(typeof graph=="string" && typeof graph.toNT!='function') graph = new RDFNode.NamedNode(graph); 167 | if(graph!==null && !RDFNode.RDFNode.is(graph)) throw new Error('match graph is not an RDFNode'); 168 | if(graph!==null && graph.termType!=='NamedNode') throw new Error('match graph must be a NamedNode'); 169 | var result = new Dataset; 170 | var pattern = {s:subject&&subject.toNT(), p:predicate&&predicate.toNT(), o:object&&object.toNT(), g:graph&&graph.toNT()}; 171 | var patternIndexMap = [ 172 | {index:this.indexSPOG, constants:["s", "p", "o", "g"], variables:[]}, 173 | {index:this.indexSPOG, constants:["s", "p", "o"], variables:["g"]}, 174 | {index:this.indexGSPO, constants:["s", "p", "g"], variables:["o"]}, 175 | {index:this.indexSPOG, constants:["s", "p"], variables:["o", "g"]}, 176 | {index:this.indexOSGP, constants:["s", "o", "g"], variables:["p"]}, 177 | {index:this.indexOSGP, constants:["s", "o"], variables:["p", "g"]}, 178 | {index:this.indexGSPO, constants:["s", "g"], variables:["p", "o"]}, 179 | {index:this.indexSPOG, constants:["s"], variables:["p", "o", "g"]}, 180 | {index:this.indexPOGS, constants:["p", "o", "g"], variables:["s"]}, 181 | {index:this.indexPOGS, constants:["p", "o"], variables:["s", "g"]}, 182 | {index:this.indexGPOS, constants:["p", "g"], variables:["s", "o"]}, 183 | {index:this.indexPOGS, constants:["p"], variables:["s", "o", "g"]}, 184 | {index:this.indexOGSP, constants:["o", "g"], variables:["s", "p"]}, 185 | {index:this.indexOGSP, constants:["o"], variables:["s", "p", "g"]}, 186 | {index:this.indexGSPO, constants:["g"], variables:["s", "p", "o"]}, 187 | {index:this.indexSPOG, constants:[], variables:["s", "p", "o", "g"]}, 188 | ]; 189 | var patternType = 0; 190 | if(!pattern.s) patternType |= 8; 191 | if(!pattern.p) patternType |= 4; 192 | if(!pattern.o) patternType |= 2; 193 | if(!pattern.g) patternType |= 1; 194 | var index = patternIndexMap[patternType]; 195 | var data = index.index; 196 | index.constants.forEach(function(v){if(data) data=data[pattern[v]];}); 197 | if(!data) return result; 198 | (function go(data, c){ 199 | if(c) return void Object.keys(data).forEach(function(t){go(data[t], c-1);}); 200 | if(subject && !data.subject.equals(subject)) throw new Error('assertion fail: subject'); 201 | if(predicate && !data.predicate.equals(predicate)) throw new Error('assertion fail: predicate'); 202 | if(object && !data.object.equals(object)) throw new Error('assertion fail: object'); 203 | if(graph && !data.graph.equals(graph)) throw new Error('assertion fail: graph'); 204 | result.add(data); 205 | })(data, index.variables.length); 206 | return result; 207 | }; 208 | 209 | // Gets a reference to a particular subject 210 | // Graph.prototype.reference = function reference(subject){ 211 | // return new ResultSet.ResultSet(this, subject); 212 | // }; 213 | -------------------------------------------------------------------------------- /lib/Graph.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var RDFNode = require('./RDFNode.js'); 4 | var ResultSet = require('./ResultSet.js'); 5 | 6 | /** 7 | * The very fastest graph for heavy read operations, but uses three indexes 8 | * Graph (fast, triple indexed) implements DataStore 9 | 10 | [NoInterfaceObject] 11 | interface Graph { 12 | readonly attribute unsigned long length; 13 | Graph add (in Triple triple); 14 | Graph remove (in Triple triple); 15 | Graph removeMatches (in any? subject, in any? predicate, in any? object); 16 | sequence toArray (); 17 | boolean some (in TripleFilter callback); 18 | boolean every (in TripleFilter callback); 19 | Graph filter (in TripleFilter filter); 20 | void forEach (in TripleCallback callback); 21 | Graph match (in any? subject, in any? predicate, in any? object, in optional unsigned long limit); 22 | Graph merge (in Graph graph); 23 | Graph addAll (in Graph graph); 24 | readonly attribute sequence actions; 25 | Graph addAction (in TripleAction action, in optional boolean run); 26 | }; 27 | 28 | */ 29 | 30 | /** 31 | * Read an RDF Collection and return it as an Array 32 | */ 33 | var rdfnil = new RDFNode.NamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'); 34 | var rdffirst = new RDFNode.NamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#first'); 35 | var rdfrest = new RDFNode.NamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#rest'); 36 | 37 | function getKey(node){ 38 | if(!node) return node; 39 | switch(node.termType){ 40 | case 'Literal': return node.datatype + node.language + ' ' + node.value; 41 | } 42 | return node.value; 43 | } 44 | 45 | function isIndex(i, a, b, c, t){ 46 | if(!i[a]) return false; 47 | if(!i[a][b]) return false; 48 | return i[a][b][c] ? i[a][b][c].equals(t) : false ; 49 | } 50 | 51 | function insertIndex(i, a, b, c, t){ 52 | if(!i[a]) i[a] = {}; 53 | if(!i[a][b]) i[a][b] = {}; 54 | i[a][b][c] = t; 55 | } 56 | 57 | function deleteIndex(i, a, b, c, t){ 58 | if(i[a]&&i[a][b]&&i[a][b][c]){ 59 | if(!i[a][b][c].equals(t)) throw new Error('assertion fail: deleted triple mismatch'); 60 | delete(i[a][b][c]); 61 | if(!Object.keys(i[a][b]).length) delete(i[a][b]); 62 | if(!Object.keys(i[a]).length) delete(i[a]); 63 | } 64 | } 65 | 66 | exports.Graph = Graph; 67 | function Graph(init){ 68 | this.clear(); 69 | //this._actions = []; 70 | Object.defineProperty(this, 'size', {get: function(){return self.length;}}); 71 | var self = this; 72 | if(init && init.forEach){ 73 | init.forEach(function(t){ self.add(t); }); 74 | } 75 | } 76 | Graph.prototype.length = null; 77 | Graph.prototype.graph = null; 78 | 79 | Graph.prototype.importArray = function(a) { while( a.length > 0) { this.add(a.pop()); } }; 80 | 81 | Graph.prototype.insertIndex = insertIndex; 82 | Graph.prototype.deleteIndex = deleteIndex; 83 | Graph.prototype.add = function(triple) { 84 | if(!(triple instanceof RDFNode.Triple)) throw new TypeError('Expected a Triple for argument[0] `triple`'); 85 | var st=getKey(triple.subject), pt=getKey(triple.predicate), ot=getKey(triple.object); 86 | if(isIndex(this.indexSOP, st, ot, pt, triple)) return; 87 | insertIndex(this.indexOPS, ot, pt, st, triple); 88 | insertIndex(this.indexPSO, pt, st, ot, triple); 89 | insertIndex(this.indexSOP, st, ot, pt, triple); 90 | this.length++; 91 | //this.actions.forEach(function(fn){ fn(triple); }); 92 | }; 93 | Graph.prototype.addAll = function(g){ 94 | var g2 = this; 95 | g.forEach(function(s){ g2.add(s); }); 96 | }; 97 | Graph.prototype.union = function union(g){ 98 | var gx = new Graph; 99 | gx.addAll(this); 100 | gx.addAll(g); 101 | return gx; 102 | }; 103 | Graph.prototype.merge = Graph.prototype.union; 104 | Graph.prototype.remove = function(triple) { 105 | var st=getKey(triple.subject), pt=getKey(triple.predicate), ot=getKey(triple.object); 106 | if(!isIndex(this.indexSOP, st, ot, pt, triple)) return; 107 | deleteIndex(this.indexOPS, ot, pt, st, triple); 108 | deleteIndex(this.indexPSO, pt, st, ot, triple); 109 | deleteIndex(this.indexSOP, st, ot, pt, triple); 110 | this.length--; 111 | }; 112 | Graph.prototype.delete = Graph.prototype.remove; 113 | Graph.prototype.has = function(triple) { 114 | var st=getKey(triple.subject), pt=getKey(triple.predicate), ot=getKey(triple.object); 115 | return isIndex(this.indexSOP, st, ot, pt, triple); 116 | }; 117 | Graph.prototype.removeMatches = function(s, p, o) { 118 | var graph = this; 119 | this.match(s, p, o).forEach(function(t) { 120 | graph.remove(t); 121 | }); 122 | }; 123 | Graph.prototype.deleteMatches = Graph.prototype.removeMatches; 124 | Graph.prototype.clear = function(){ 125 | this.indexSOP = {}; 126 | this.indexPSO = {}; 127 | this.indexOPS = {}; 128 | this.length = 0; 129 | }; 130 | Graph.prototype.import = function(s) { 131 | var _g1 = 0, _g = s.length; 132 | while(_g1 < _g) { 133 | var i = _g1++; 134 | this.add(s.get(i)); 135 | } 136 | }; 137 | Graph.prototype.every = function every(filter) { return this.toArray().every(filter); }; 138 | Graph.prototype.some = function some(filter) { return this.toArray().some(filter); }; 139 | Graph.prototype.forEach = function forEach(callbck) { this.toArray().forEach(callbck); }; 140 | Graph.prototype.toArray = function toArray() { 141 | var triples = []; 142 | var data = this.indexPSO; 143 | if(!data) return []; 144 | (function go(data, c){ 145 | if(c) Object.keys(data).forEach(function(t){go(data[t], c-1);}); 146 | else triples.push(data); 147 | })(data, 3); 148 | return triples; 149 | }; 150 | Graph.prototype.filter = function filter(cb){ 151 | var result = new Graph; 152 | this.forEach(function(triple){ 153 | if(cb(triple)) result.add(triple); 154 | }); 155 | return result; 156 | }; 157 | Graph.prototype.getCollection = function getCollection(subject){ 158 | var collection=[], seen=[]; 159 | var first, rest=subject; 160 | while(rest && !rest.equals(rdfnil)){ 161 | var g = this.match(rest, rdffirst, null); 162 | if(g.length===0) throw new Error('Collection <'+rest+'> is incomplete'); 163 | first = g.toArray().map(function(v){return v.object;})[0]; 164 | if(seen.indexOf(rest.toString())!==-1) throw new Error('Collection <'+rest+'> is circular'); 165 | seen.push(rest.toString()); 166 | collection.push(first); 167 | rest = this.match(rest, rdfrest, null).toArray().map(function(v){return v.object;})[0]; 168 | } 169 | return collection; 170 | }; 171 | // FIXME this should return a Graph, not an Array 172 | // FIXME ensure that the RDFNode#equals semantics are met 173 | Graph.prototype.match = function match(subject, predicate, object){ 174 | if(typeof subject=="string") subject = new RDFNode.NamedNode(subject); 175 | if(subject!==null && !RDFNode.RDFNode.is(subject)) throw new Error('match subject is not an RDFNode'); 176 | if(subject!==null && subject.termType!=='NamedNode' && subject.termType!=='BlankNode') throw new Error('match subject must be a NamedNode/BlankNode'); 177 | if(typeof predicate=="string") predicate = new RDFNode.NamedNode(predicate); 178 | if(predicate!==null && !RDFNode.RDFNode.is(predicate)) throw new Error('match predicate is not an RDFNode'); 179 | if(predicate!==null && predicate.termType!=='NamedNode') throw new Error('match predicate must be a NamedNode'); 180 | if(typeof object=="string") object = new RDFNode.NamedNode(object); 181 | if(object!==null && !RDFNode.RDFNode.is(object)) throw new Error('match object is not an RDFNode'); 182 | if(object!==null && object.termType!=='NamedNode' && object.termType!=='BlankNode' && object.termType!=='Literal') throw new Error('match object must be a NamedNode/BlankNode/Literal'); 183 | var triples = new Graph; 184 | var pattern = {s:subject&&getKey(subject), p:predicate&&getKey(predicate), o:getKey(object)}; 185 | var patternIndexMap = [ 186 | {index:this.indexOPS, constants:["o", "p", "s"], variables:[]}, 187 | {index:this.indexPSO, constants:["p", "s"], variables:["o"]}, 188 | {index:this.indexSOP, constants:["s", "o"], variables:["p"]}, 189 | {index:this.indexSOP, constants:["s"], variables:["o", "p"]}, 190 | {index:this.indexOPS, constants:["o", "p"], variables:["s"]}, 191 | {index:this.indexPSO, constants:["p"], variables:["s", "o"]}, 192 | {index:this.indexOPS, constants:["o"], variables:["p", "s"]}, 193 | {index:this.indexPSO, constants:[], variables:["p", "s", "o"]}, 194 | ]; 195 | var patternType = 0; 196 | if(!pattern.s) patternType |= 4; 197 | if(!pattern.p) patternType |= 2; 198 | if(!pattern.o) patternType |= 1; 199 | var index = patternIndexMap[patternType]; 200 | var data = index.index; 201 | index.constants.forEach(function(v){if(data) data=data[pattern[v]];}); 202 | if(!data) return triples; 203 | (function go(data, c){ 204 | if(c) return void Object.keys(data).forEach(function(t){go(data[t], c-1);}); 205 | if(subject && !data.subject.equals(subject)) throw new Error('assertion fail: subject'); 206 | if(predicate && !data.predicate.equals(predicate)) throw new Error('assertion fail: predicate'); 207 | if(object && !data.object.equals(object)) throw new Error('assertion fail: object'); 208 | triples.add(data); 209 | })(data, index.variables.length); 210 | return triples; 211 | }; 212 | 213 | var GraphEquals = require('./GraphEquals.js'); 214 | Graph.prototype.isomorphic = function isomorphic(b){ 215 | return GraphEquals(this, b); 216 | }; 217 | Graph.prototype.equals = function equals(b){ 218 | return GraphEquals(this, b); 219 | }; 220 | var GraphSimplyEntails = require('./GraphSimplyEntails.js'); 221 | Graph.prototype.simplyEntails = function simplyEntails(subset){ 222 | var reference = this; 223 | return GraphSimplyEntails(reference, subset); 224 | }; 225 | 226 | //Graph.prototype.addAction = function(action, run){ 227 | // this._actions.push(action); 228 | // if(run){ 229 | // this.forEach(action); 230 | // } 231 | //} 232 | // 233 | //Object.defineProperty(Graph.prototype, 'actions', { get: function(){ return this._actions; } }); 234 | 235 | // Gets a reference to a particular subject 236 | Graph.prototype.reference = function reference(subject){ 237 | return new ResultSet.ResultSet(this, subject); 238 | }; 239 | -------------------------------------------------------------------------------- /lib/GraphEquals.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = GraphEquals; 4 | function GraphEquals(a, b, depth){ 5 | if(typeof a.length!='number') throw new Error('Expected an RDFGraph for argument `a`'); 6 | if(typeof b.length!='number') throw new Error('Expected an RDFGraph for argument `b`'); 7 | if(a.length!==b.length) return false; 8 | if(a.length<=0) throw new Error('Expected a nonempty RDFGraph'); 9 | var al = a.toArray(); 10 | var bl = b.toArray(); 11 | //if(!a.every(function(s))) return false; 12 | var stack = [ {i:0, depth:0, bindings:{}} ]; 13 | // Iterate through each statement in `a` 14 | // test that named nodes/literals/bound bnodes have a match in the other document 15 | // For each bnode encountered in the statement that's unbound, determine every possible binding and recurse 16 | while(stack.length){ 17 | // If `depth` starts as 0 this will never be hit 18 | if(--depth===0) throw new Error('Hit search limit'); 19 | var state = stack.pop(); 20 | if(state.i===al.length) return state.bindings; 21 | var stmt = al[state.i]; 22 | // If it's a bnode, then map it. If it's not mapped, use `null` to search for any values. 23 | // in theory the predicate will never be a bnode, but the additional test shouldn't hurt anything 24 | var stmtsubject = stmt.subject.nodeType()==='BlankNode' ? (state.bindings[stmt.subject] || null) : stmt.subject ; 25 | var stmtpredicate = stmt.predicate.nodeType()==='BlankNode' ? (state.bindings[stmt.predicate] || null) : stmt.predicate ; 26 | var stmtobject = stmt.object.nodeType()==='BlankNode' ? (state.bindings[stmt.object] || null) : stmt.object ; 27 | var matches = b.match(stmtsubject, stmtpredicate, stmtobject).filter(function(m){ 28 | // wildcards must only match bnodes 29 | // The predicate should never be a bnode, so skip over that code path for now 30 | if(stmtsubject===null && m.subject.nodeType()!=='BlankNode') return false; 31 | //if(stmtpredicate===null && m.predicate.nodeType()!=='BlankNode') return false; 32 | if(stmtobject===null && m.object.nodeType()!=='BlankNode') return false; 33 | return true; 34 | }); 35 | if(stmtsubject && stmtpredicate && stmtobject){ 36 | if(matches.length===1){ 37 | // if there's a single match where all nodes match exactly, push the comparison for the next item 38 | stack.push({ i:state.i+1, depth:state.depth, bindings:state.bindings }); 39 | }else if(matches.length===0){ 40 | continue; 41 | }else{ 42 | throw new Error('Multiple matches, expected exactly one or zero match'); 43 | } 44 | }else{ 45 | // otherwise there's an unbound bnode, get the possible mappings and push those onto the stack 46 | matches.forEach(function(match){ 47 | var b2 = {}; 48 | var depth = state.depth; 49 | for(var n in state.bindings) b2[n] = state.bindings[n]; 50 | if(stmtsubject===null){ 51 | if(b2[stmt.subject]===undefined){ 52 | for(var n in b2) if(b2[n]===match.subject) return; 53 | b2[stmt.subject] = match.subject; 54 | depth++; 55 | }else{ 56 | throw new Error('bnode already mapped'); 57 | } 58 | } 59 | // if(stmtpredicate===null && b2[stmt.predicate]===undefined){ 60 | // if(b2[stmt.predicate]===undefined){ 61 | // for(var n in b2) if(b2[n]===match.predicate) return; 62 | // b2[stmt.predicate] = match.predicate; 63 | // depth++; 64 | // }else{ 65 | // throw new Error('bnode already mapped'); 66 | // } 67 | // } 68 | if(stmtobject===null){ 69 | if(b2[stmt.object]===undefined){ 70 | for(var n in b2) if(b2[n]===match.object) return; 71 | b2[stmt.object] = match.object; 72 | depth++; 73 | }else{ 74 | throw new Error('bnode already mapped'); 75 | } 76 | } 77 | stack.push({ i:state.i, depth:depth, bindings:b2 }); 78 | }); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /lib/GraphSimplyEntails.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // Verify that `ref` simply entails `tst` 4 | // According to RDF 1.1 Semantics, this is true iff a subgraph of `ref` is an instance of `tst` 5 | // Go through every triple in `tst` and map bnodes to nodes in `ref` 6 | 7 | module.exports = GraphSimplyEntails; 8 | function GraphSimplyEntails(ref, tst, depth){ 9 | if(typeof ref.length!='number') throw new Error('Expected an RDFGraph for argument `ref`'); 10 | if(typeof tst.length!='number') throw new Error('Expected an RDFGraph for argument `tst`'); 11 | if(tst.length > ref.length) return false; 12 | var tstl = tst.toArray(); 13 | //if(!a.every(function(s))) return false; 14 | var stack = [ {i:0, depth:0, bindings:{}} ]; 15 | // Iterate through each statement in `a` 16 | // test that named nodes/literals/bound bnodes have a match in the other document 17 | // For each bnode encountered in the statement that's unbound, determine every possible binding and recurse 18 | while(stack.length){ 19 | // If `depth` starts as 0 this will never be hit 20 | if(--depth===0) throw new Error('Hit search limit'); 21 | var state = stack.pop(); 22 | if(state.i===tstl.length) return state.bindings; 23 | var stmt = tstl[state.i]; 24 | // If it's a bnode, then map it. If it's not mapped, use `null` to search for any values. 25 | // in theory the predicate will never be a bnode, but the additional test shouldn't hurt anything 26 | var stmtsubject = stmt.subject.termType==='BlankNode' ? (state.bindings[stmt.subject] || null) : stmt.subject ; 27 | var stmtpredicate = stmt.predicate.termType==='BlankNode' ? (state.bindings[stmt.predicate] || null) : stmt.predicate ; 28 | var stmtobject = stmt.object.termType==='BlankNode' ? (state.bindings[stmt.object] || null) : stmt.object ; 29 | var matches = ref.match(stmtsubject, stmtpredicate, stmtobject).filter(function(m){ 30 | // wildcards must only match bnodes 31 | // The predicate should never be a bnode, so skip over that code path for now 32 | // if(stmtsubject===null && (m.subject.termType!=='BlankNode' && m.subject.termType!=='NamedNode')) return false; 33 | //if(stmtpredicate===null && (m.predicate.termType!=='BlankNode' && m.predicate.termType!=='NamedNode')) return false; 34 | // if(stmtobject===null && (m.object.termType!=='BlankNode' && m.object.termType!=='NamedNode' && m.object.termType!=='Literal')) return false; 35 | return true; 36 | }); 37 | if(stmtsubject && stmtpredicate && stmtobject){ 38 | if(matches.length===1){ 39 | // if there's a single match where all nodes match exactly, push the comparison for the next item 40 | stack.push({ i:state.i+1, depth:state.depth, bindings:state.bindings }); 41 | }else if(matches.length===0){ 42 | continue; 43 | }else{ 44 | throw new Error('Multiple matches, expected exactly one or zero match'); 45 | } 46 | }else{ 47 | // otherwise there's an unbound bnode, get the possible mappings and push those onto the stack 48 | matches.forEach(function(match){ 49 | var b2 = {}; 50 | var depth = state.depth; 51 | for(var n in state.bindings) b2[n] = state.bindings[n]; 52 | if(stmtsubject===null){ 53 | if(b2[stmt.subject]===undefined){ 54 | for(var n in b2) if(b2[n]===match.subject) return; 55 | b2[stmt.subject] = match.subject; 56 | depth++; 57 | }else{ 58 | throw new Error('bnode already mapped'); 59 | } 60 | } 61 | // if(stmtpredicate===null && b2[stmt.predicate]===undefined){ 62 | // if(b2[stmt.predicate]===undefined){ 63 | // for(var n in b2) if(b2[n]===match.predicate) return; 64 | // b2[stmt.predicate] = match.predicate; 65 | // depth++; 66 | // }else{ 67 | // throw new Error('bnode already mapped'); 68 | // } 69 | // } 70 | if(stmtobject===null){ 71 | if(b2[stmt.object]===undefined){ 72 | for(var n in b2) if(b2[n]===match.object) return; 73 | b2[stmt.object] = match.object; 74 | depth++; 75 | }else{ 76 | throw new Error('bnode already mapped'); 77 | } 78 | } 79 | stack.push({ i:state.i, depth:depth, bindings:b2 }); 80 | }); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /lib/Profile.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /** Implements interfaces from http://www.w3.org/TR/2011/WD-rdf-interfaces-20110510/ */ 4 | 5 | var api = exports; 6 | 7 | var NamedNode = require("./RDFNode.js").NamedNode; 8 | 9 | api.SCHEME_MATCH = new RegExp("^[a-z0-9-.+]+:", "i"); 10 | 11 | // This is the same as the XML NCName 12 | // Note how [\uD800-\uDBFF][\uDC00-\uDFFF] is a surrogate pair that encodes #x10000-#xEFFFF 13 | api.CURIE_PREFIX = new RegExp("^([A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]|[\uD800-\uDBFF][\uDC00-\uDFFF])([A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD.0-9\u00B7\u0300-\u036F\u203F-\u2040\\-]|[\uD800-\uDBFF][\uDC00-\uDFFF])*$", "i"); 14 | 15 | 16 | // For implementations that don't have Map defined...??? 17 | function GoodEnoughMap(){ 18 | this.map = {}; 19 | } 20 | GoodEnoughMap.prototype.has = function has(key){ 21 | return Object.hasOwnProperty.call(this.map, key+':'); 22 | }; 23 | GoodEnoughMap.prototype.get = function get(key){ 24 | return Object.hasOwnProperty.call(this.map, key+':') ? this.map[key+':'] : undefined; 25 | }; 26 | GoodEnoughMap.prototype.set = function set(key, value){ 27 | // Store with some suffix to avoid certain magic keywords 28 | this.map[key+':'] = value; 29 | }; 30 | GoodEnoughMap.prototype.delete = function del(key){ 31 | delete this.map[key+':']; 32 | }; 33 | GoodEnoughMap.prototype.forEach = function forEach(it){ 34 | var map = this.map; 35 | Object.keys(this.map).forEach(function(k){ 36 | it(map[k], k.substring(0, k.length-1)); 37 | }); 38 | }; 39 | var StringMap = (typeof Map=='function') ? Map : GoodEnoughMap ; 40 | 41 | /** 42 | * Implements PrefixMap http://www.w3.org/TR/2011/WD-rdf-interfaces-20110510/#idl-def-PrefixMap 43 | */ 44 | api.PrefixMap = function PrefixMap(){ 45 | this.prefixMap = new StringMap; 46 | }; 47 | api.PrefixMap.prototype.get = function(prefix){ 48 | // strip a trailing ":" 49 | if(prefix.slice(-1)==":") prefix=prefix.slice(0, -1); 50 | return this.prefixMap.get(prefix); 51 | }; 52 | api.PrefixMap.prototype.set = function(prefix, iri){ 53 | // strip a trailing ":" 54 | if(prefix.slice(-1)==":") prefix=prefix.slice(0, -1); 55 | if(typeof prefix!='string') throw new TypeError('Expected a string argument[0] `prefix`'); 56 | if(iri===null) return void this.prefixMap.delete(prefix); 57 | if(typeof iri!='string') throw new TypeError('Expected a string argument[1] `iri`'); 58 | if(prefix.length && !api.CURIE_PREFIX.exec(prefix)) throw new Error('Invalid prefix name'); 59 | this.prefixMap.set(prefix, iri); 60 | }; 61 | api.PrefixMap.prototype.list = function(){ 62 | var list = []; 63 | this.prefixMap.forEach(function(expansion, prefix){ 64 | list.push(prefix); 65 | }); 66 | return list; 67 | }; 68 | api.PrefixMap.prototype.remove = function(prefix){ 69 | this.prefixMap.delete(prefix); 70 | }; 71 | api.PrefixMap.prototype.resolve = function(curie){ 72 | var index = curie.indexOf(":"); 73 | if(index<0) return null; 74 | var prefix = curie.slice(0, index); 75 | var iri = this.get(prefix); 76 | if(!iri) return null; 77 | var resolved = iri.concat(curie.slice(index+1)); 78 | if(resolved.match(api.SCHEME_MATCH)==null && this.base!=null){ 79 | resolved = this.base.resolveReference(resolved); 80 | } 81 | return resolved.toString(); 82 | }; 83 | api.PrefixMap.prototype.shrink = function(uri) { 84 | if(typeof uri!='string') throw new TypeError('Expected string arguments[0] `uri`'); 85 | var shrunk = uri; 86 | var matchedLen = ''; 87 | this.prefixMap.forEach(function(expansion, prefix){ 88 | if(uri.substr(0,expansion.length)==expansion && expansion.length>matchedLen){ 89 | shrunk = prefix + ':' + uri.substring(expansion.length); 90 | matchedLen = expansion.length; 91 | } 92 | }); 93 | return shrunk; 94 | }; 95 | api.PrefixMap.prototype.setDefault = function(uri){ 96 | this.set('', uri); 97 | }; 98 | api.PrefixMap.prototype.addAll = function(prefixes, override){ 99 | var localPrefixMap = this.prefixMap; 100 | if(override){ 101 | prefixes.prefixMap.forEach(function(expansion, prefix){ 102 | localPrefixMap.set(prefix, expansion); 103 | }); 104 | }else{ 105 | prefixes.prefixMap.forEach(function(expansion, prefix){ 106 | if(!localPrefixMap.has(prefix)) localPrefixMap.set(prefix, expansion); 107 | }); 108 | } 109 | }; 110 | 111 | /** 112 | * Implements TermMap http://www.w3.org/TR/2011/WD-rdf-interfaces-20110510/#idl-def-TermMap 113 | */ 114 | api.TermMap = function TermMap(){ 115 | this.termMap = new StringMap; 116 | this.vocabulary = null; 117 | }; 118 | api.TermMap.prototype.get = function(term){ 119 | return this.termMap.get(term); 120 | }; 121 | api.TermMap.prototype.set = function(term, iri){ 122 | if(typeof term!='string') throw new TypeError('Expected a string argument[0] `prefix`'); 123 | if(iri===null) return void this.termMap.delete(term); 124 | if(typeof iri!='string') throw new TypeError('Expected a string argument[1] `iri`'); 125 | if(!api.CURIE_PREFIX.exec(term)) throw new Error('Invalid term name'); 126 | this.termMap.set(term, iri); 127 | }; 128 | api.TermMap.prototype.list = function(){ 129 | var list = []; 130 | this.termMap.forEach(function(definition, term){ 131 | list.push(term); 132 | }); 133 | return list; 134 | }; 135 | api.TermMap.prototype.remove = function(term){ 136 | this.termMap.delete(term); 137 | }; 138 | api.TermMap.prototype.resolve = function(term){ 139 | var expansion = this.termMap.get(term); 140 | if(typeof expansion=='string') return expansion; 141 | if(typeof this.vocabulary=='string') return this.vocabulary+term; 142 | return null; 143 | }; 144 | api.TermMap.prototype.shrink = function(uri){ 145 | var shrunk = uri; 146 | this.termMap.forEach(function(definition, term){ 147 | if(uri==definition){ 148 | shrunk = term; 149 | } 150 | }); 151 | if(typeof this.vocabulary==='string' && uri.substring(0, this.vocabulary.length)===this.vocabulary){ 152 | return uri.substring(this.vocabulary.length); 153 | } 154 | return shrunk; 155 | }; 156 | api.TermMap.prototype.setDefault = function(uri){ 157 | this.vocabulary = (uri==='') ? null : uri; 158 | }; 159 | api.TermMap.prototype.addAll = function(terms, override){ 160 | var termMap = this.termMap; 161 | if(override){ 162 | terms.termMap.forEach(function(definition, term){ 163 | termMap.set(term, definition); 164 | }); 165 | }else{ 166 | terms.termMap.forEach(function(definition, term){ 167 | if(!termMap.has(term)) termMap.set(term, definition); 168 | }); 169 | } 170 | }; 171 | 172 | /** 173 | * Implements Profile http://www.w3.org/TR/2011/WD-rdf-interfaces-20110510/#idl-def-Profile 174 | */ 175 | api.Profile = function Profile() { 176 | this.prefixes = new api.PrefixMap; 177 | this.terms = new api.TermMap; 178 | }; 179 | api.Profile.prototype.resolve = function(toresolve){ 180 | if(toresolve.indexOf(":")<0) return this.terms.resolve(toresolve); 181 | else return this.prefixes.resolve(toresolve); 182 | }; 183 | api.Profile.prototype.setDefaultVocabulary = function(uri){ 184 | this.terms.setDefault(uri); 185 | }; 186 | api.Profile.prototype.setDefaultPrefix = function(uri){ 187 | this.prefixes.setDefault(uri); 188 | }; 189 | api.Profile.prototype.setTerm = function(term, uri){ 190 | this.terms.set(term, uri); 191 | }; 192 | api.Profile.prototype.setPrefix = function(prefix, uri){ 193 | this.prefixes.set(prefix, uri); 194 | }; 195 | api.Profile.prototype.shrink = function(uri){ 196 | return this.terms.shrink(this.prefixes.shrink(uri)); 197 | }; 198 | api.Profile.prototype.importProfile = function(profile, override){ 199 | this.prefixes.addAll(profile.prefixes, override); 200 | this.terms.addAll(profile.terms, override); 201 | }; 202 | -------------------------------------------------------------------------------- /lib/RDFEnvironment.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var NamedNode = require("./RDFNode.js").NamedNode; 4 | var BlankNode = require("./RDFNode.js").BlankNode; 5 | var Literal = require("./RDFNode.js").Literal; 6 | var Triple = require("./RDFNode.js").Triple; 7 | var Graph = require("./Graph.js").Graph; 8 | var Profile = require("./Profile.js").Profile; 9 | var PrefixMap = require("./Profile.js").PrefixMap; 10 | var TermMap = require("./Profile.js").TermMap; 11 | var loadRequiredPrefixMap = require("./prefixes.js").loadRequiredPrefixMap; 12 | 13 | /** 14 | * Implements RDFEnvironment http://www.w3.org/TR/2011/WD-rdf-interfaces-20110510/#idl-def-RDFEnvironment 15 | */ 16 | exports.RDFEnvironment = function RDFEnvironment(){ 17 | Profile.call(this); 18 | loadRequiredPrefixMap(this); 19 | }; 20 | exports.RDFEnvironment.prototype = Object.create(Profile.prototype, {constructor:{value:exports.RDFEnvironment, iterable:false}}); 21 | exports.RDFEnvironment.prototype.createBlankNode = function(){ 22 | return new BlankNode; 23 | }; 24 | exports.RDFEnvironment.prototype.createNamedNode = function(v){ 25 | return new NamedNode(v); 26 | }; 27 | exports.RDFEnvironment.prototype.createLiteral = function(value, datatype, _dt){ 28 | if(typeof value!='string') throw new Error('Expected argument[0] `value` to be a string'); 29 | if(datatype!==undefined && datatype!==null && typeof datatype!=='string' && !(datatype instanceof NamedNode)) throw new TypeError('Expected optional argument[1] `datatype` to be a string'); 30 | if(_dt!==undefined && _dt!==null && typeof _dt!=='string' && !(_dt instanceof NamedNode)) throw new TypeError('Expected optional argument[2] `_dt` to be a string'); 31 | if(datatype instanceof NamedNode){ 32 | return new Literal(value, datatype); 33 | }else if(typeof datatype=='string' && (_dt==null || _dt==undefined || _dt=='http://www.w3.org/1999/02/22-rdf-syntax-ns#langString')){ 34 | // Process arguments as a typed and/or language literal 35 | return new Literal(value, datatype); 36 | }else if((datatype==null || datatype==undefined) && _dt){ 37 | // Process arguments as a typed literal 38 | return Literal.typed(value, _dt); 39 | } 40 | return new Literal(value); 41 | }; 42 | exports.RDFEnvironment.prototype.createTypedLiteral = function(value, datatype){ 43 | return Literal.typed(value, datatype); 44 | }; 45 | exports.RDFEnvironment.prototype.createLanguageLiteral = function(value, language){ 46 | return Literal.language(value, language); 47 | }; 48 | exports.RDFEnvironment.prototype.createTriple = function(s,p,o){ 49 | return new Triple(s,p,o); 50 | }; 51 | exports.RDFEnvironment.prototype.createGraph = function(g){ 52 | return new Graph(g); 53 | }; 54 | //exports.RDFEnvironment.prototype.createAction = function(){ 55 | // return new Action; 56 | //} 57 | exports.RDFEnvironment.prototype.createProfile = function(){ 58 | return new Profile; 59 | }; 60 | exports.RDFEnvironment.prototype.createTermMap = function(){ 61 | return new TermMap; 62 | }; 63 | exports.RDFEnvironment.prototype.createPrefixMap = function(){ 64 | return new PrefixMap; 65 | }; 66 | -------------------------------------------------------------------------------- /lib/RDFNode.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var encodeString = require('./encodeString.js'); 4 | var api = exports; 5 | 6 | function inherits(ctor, superCtor) { 7 | //ctor.super_ = superCtor; 8 | ctor.prototype = Object.create(superCtor.prototype, { 9 | constructor: { value: ctor, enumerable: false }, 10 | }); 11 | } 12 | 13 | function nodeType(v){ 14 | if(v.nodeType) return v.nodeType(); 15 | if(typeof v=='string') return (v.substr(0,2)=='_:')?'BlankNode':'IRI'; 16 | return 'TypedLiteral'; 17 | } 18 | api.nodeType = nodeType; 19 | 20 | function RDFNodeEquals(other) { 21 | if(typeof other=='string'){ 22 | return this.termType=="NamedNode" && this.value==other; 23 | } 24 | if(api.RDFNode.is(other)){ 25 | if(nodeType(this)!=nodeType(other)) return false; 26 | switch(this.termType) { 27 | case "BlankNode": 28 | case "NamedNode": 29 | case "Variable": 30 | case "DefaultGraph": 31 | return this.toString()==other.toString(); 32 | case "Literal": 33 | return ( this.language==other.language 34 | && this.nominalValue==other.nominalValue 35 | && this.datatype.toString()==other.datatype.toString() 36 | ); 37 | } 38 | if(typeof this.toNT=='function' && typeof other.toNT=='function'){ 39 | return this.toNT() == other.toNT(); 40 | } 41 | } 42 | //throw new Error('Cannot compare values'); 43 | return false; 44 | } 45 | api.RDFNodeEquals = RDFNodeEquals; 46 | 47 | function RDFNodeCompare(other) { 48 | // Node type order: IRI, BlankNode, Literal 49 | var typeThis=this.termType, typeOther=other.termType; 50 | if(typeThis != typeOther){ 51 | switch(typeThis) { 52 | case "IRI": 53 | case "NamedNode": 54 | // must be a BlankNode or Literal 55 | return -1; 56 | case "BlankNode": 57 | if(typeOther=="Literal") return -1; 58 | else return 1; 59 | case "Literal": 60 | return 1; 61 | } 62 | throw new Error(typeThis); 63 | } 64 | // node types are the same, compare nomialValue 65 | if(typeof this.nominalValue=='string' && typeof other.nominalValue=='string'){ 66 | if(this.nominalValue < other.nominalValue) return -1; 67 | if(this.nominalValue > other.nominalValue) return 1; 68 | } 69 | // values are the same, compare by datatype 70 | if(typeof this.datatype=='string' && typeof other.datatype=='string'){ 71 | if(this.datatype < other.datatype) return -1; 72 | if(this.datatype > other.datatype) return 1; 73 | } 74 | if(typeof this.language=='string' || typeof other.language=='string'){ 75 | if(typeof this.language=='string' && typeof other.language=='string'){ 76 | if(this.language < other.language) return -1; 77 | if(this.language > other.language) return 1; 78 | }else{ 79 | if(other.language) return -1; 80 | if(this.language) return 1; 81 | } 82 | } 83 | // Compare by any other metric? 84 | if(typeof this.valueOf=='function'){ 85 | if(this.valueOf() < other) return -1; 86 | if(this.valueOf() > other) return 1; 87 | //if(this.valueOf() == other) return 0; 88 | } 89 | if(this.equals(other)) return 0; 90 | throw new Error('Cannot compare values'); 91 | } 92 | api.RDFNodeEquals = RDFNodeEquals; 93 | 94 | /** 95 | * Implements Triple http://www.w3.org/TR/2011/WD-rdf-interfaces-20110510/#idl-def-Triple 96 | */ 97 | api.Triple = function Triple(s, p, o) { 98 | if(typeof s=='string') s = new NamedNode(s); 99 | if(!api.RDFNode.is(s)) throw new Error('Triple subject is not an RDFNode'); 100 | if(s.termType!=='NamedNode' && s.termType!=='BlankNode') throw new Error('subject must be a NamedNode/BlankNode'); 101 | 102 | if(typeof p=='string') p = new NamedNode(p); 103 | if(!api.RDFNode.is(p)) throw new Error('Triple predicate is not an RDFNode'); 104 | if(p.termType!=='NamedNode') throw new Error('predicate must be a NamedNode'); 105 | 106 | if(typeof o=='string') o = new NamedNode(o); 107 | if(!api.RDFNode.is(o)) throw new Error('Triple object is not an RDFNode'); 108 | if(o.termType!=='NamedNode' && o.termType!=='BlankNode' && o.termType!=='Literal') throw new Error('object must be a NamedNode/BlankNode/Literal'); 109 | 110 | this.subject = s; 111 | this.predicate = p; 112 | this.object = o; 113 | }; 114 | api.Triple.prototype.size = 3; 115 | api.Triple.prototype.length = 3; 116 | api.Triple.prototype.toString = function() { 117 | return this.subject.toNT() + " " + this.predicate.toNT() + " " + this.object.toNT() + " ."; 118 | }; 119 | api.Triple.prototype.toNT = function toNT() { 120 | return this.subject.toNT() + " " + this.predicate.toNT() + " " + this.object.toNT() + " ."; 121 | }; 122 | api.Triple.prototype.toTurtle = function toTurtle(profile) { 123 | return this.subject.toTurtle(profile) + " " + this.predicate.toTurtle(profile) + " " + this.object.toTurtle(profile) + " ."; 124 | }; 125 | api.Triple.prototype.equals = function(t) { 126 | return RDFNodeEquals.call(this.subject,t.subject) && RDFNodeEquals.call(this.predicate,t.predicate) && RDFNodeEquals.call(this.object,t.object); 127 | }; 128 | api.Triple.prototype.compare = function(other) { 129 | var r = 0; 130 | // test the return value, also assign to `r` 131 | if(r = this.subject.compare(other.subject)) return r; 132 | if(r = this.predicate.compare(other.predicate)) return r; 133 | if(r = this.object.compare(other.object)) return r; 134 | }; 135 | 136 | /** 137 | */ 138 | api.Quad = function Quad(s, p, o, g) { 139 | if(typeof s=='string') s = new NamedNode(s); 140 | if(!api.RDFNode.is(s)) throw new Error('Quad subject is not an RDFNode'); 141 | if(s.termType!=='NamedNode' && s.termType!=='BlankNode') throw new Error('`subject` must be a NamedNode/BlankNode'); 142 | 143 | if(typeof p=='string') p = new NamedNode(p); 144 | if(!api.RDFNode.is(p)) throw new Error('Quad predicate is not an RDFNode'); 145 | if(p.termType!=='NamedNode') throw new Error('`predicate` must be a NamedNode'); 146 | 147 | if(typeof o=='string') o = new NamedNode(o); 148 | if(!api.RDFNode.is(o)) throw new Error('Quad object is not an RDFNode'); 149 | if(o.termType!=='NamedNode' && o.termType!=='BlankNode' && o.termType!=='Literal') throw new Error('`object` must be a NamedNode/BlankNode/Literal'); 150 | 151 | if(typeof g=='string') g = new NamedNode(g); 152 | if(!api.RDFNode.is(g)) throw new Error('Quad graph is not an RDFNode'); 153 | if(g.termType!=='NamedNode' && g.termType!=='DefaultGraph') throw new Error('Quad `graph` must be a NamedNode/DefaultGraph'); 154 | 155 | this.subject = s; 156 | this.predicate = p; 157 | this.object = o; 158 | this.graph = g; 159 | }; 160 | api.Quad.prototype.size = 4; 161 | api.Quad.prototype.length = 4; 162 | api.Quad.prototype.toString = function() { 163 | return this.toNQ(); 164 | }; 165 | api.Quad.prototype.toNT = function toNT() { 166 | return this.subject.toNT() + " " + this.predicate.toNT() + " " + this.object.toNT() + " ."; 167 | }; 168 | api.Quad.prototype.toNQ = function toNQ() { 169 | if(this.graph){ 170 | return this.subject.toNT() + " " + this.predicate.toNT() + " " + this.object.toNT() + " " + this.graph.toNT() + " ."; 171 | }else{ 172 | // the NT form is compatible with N-Quads 173 | return this.toNT(); 174 | } 175 | }; 176 | api.Quad.prototype.toTurtle = function toTurtle(profile) { 177 | return this.subject.toTurtle(profile) + " " + this.predicate.toTurtle(profile) + " " + this.object.toTurtle(profile) + " ."; 178 | }; 179 | api.Quad.prototype.equals = function(t) { 180 | return RDFNodeEquals.call(this.subject,t.subject) && RDFNodeEquals.call(this.predicate,t.predicate) && RDFNodeEquals.call(this.object,t.object) && RDFNodeEquals.call(this.graph,t.graph); 181 | }; 182 | api.Quad.prototype.compare = function(other) { 183 | var r = 0; 184 | // test the return value, also assign to `r` 185 | if(r = this.subject.compare(other.subject)) return r; 186 | if(r = this.predicate.compare(other.predicate)) return r; 187 | if(r = this.object.compare(other.object)) return r; 188 | if(r = this.graph.compare(other.graph)) return r; 189 | }; 190 | 191 | /** 192 | * Implements RDFNode http://www.w3.org/TR/2011/WD-rdf-interfaces-20110510/#idl-def-RDFNode 193 | */ 194 | api.RDFNode = function RDFNode() {}; 195 | api.RDFNode.is = function isRDFNode(n){ 196 | if(!n) return false; 197 | if(n instanceof api.RDFNode) return true; 198 | if(typeof n.nodeType=='function') return true; 199 | return false; 200 | }; 201 | api.RDFNode.prototype.equals = api.RDFNodeEquals = RDFNodeEquals; 202 | api.RDFNode.prototype.compare = api.RDFNodeCompare = RDFNodeCompare; 203 | api.RDFNode.prototype.nodeType = function() { return "RDFNode"; }; 204 | api.RDFNode.prototype.toNT = function() { return ""; }; 205 | api.RDFNode.prototype.toCanonical = function() { return this.toNT(); }; 206 | api.RDFNode.prototype.toString = function() { return this.nominalValue; }; 207 | api.RDFNode.prototype.valueOf = function() { return this.nominalValue; }; 208 | // Alignment to "Interface Specification: RDF Representation" 209 | Object.defineProperty(api.RDFNode.prototype, 'value', { get: function(){ 210 | return this.nominalValue; 211 | } }); 212 | 213 | /** 214 | * BlankNode 215 | */ 216 | api.BlankNode = BlankNode; 217 | inherits(api.BlankNode, api.RDFNode); 218 | function BlankNode(id) { 219 | if(typeof id=='string' && id.substr(0,2)=='_:') this.nominalValue=id.substr(2); 220 | else if(id) this.nominalValue=id; 221 | else this.nominalValue = 'b'+(++api.BlankNode.NextId).toString(); 222 | } 223 | api.BlankNode.NextId = 0; 224 | api.BlankNode.prototype.nodeType = function() { return "BlankNode"; }; 225 | api.BlankNode.prototype.interfaceName = "BlankNode"; 226 | api.BlankNode.prototype.termType = "BlankNode"; 227 | api.BlankNode.prototype.toNT = function() { 228 | return "_:"+this.nominalValue; 229 | }; 230 | api.BlankNode.prototype.toTurtle = function toTurtle() { 231 | return this.toNT(); 232 | }; 233 | api.BlankNode.prototype.n3 = function() { 234 | return this.toNT(); 235 | }; 236 | api.BlankNode.prototype.toString = function() { 237 | return "_:"+this.nominalValue; 238 | }; 239 | 240 | /** 241 | * Implements Literal http://www.w3.org/TR/2011/WD-rdf-interfaces-20110510/#idl-def-Literal 242 | */ 243 | api.Literal = Literal; 244 | inherits(api.Literal, api.RDFNode); 245 | function Literal(value, type) { 246 | if(typeof value!='string') throw new TypeError('Expected argument[0] `value` to be a string'); 247 | if(type!==null && type!==undefined && typeof type!='string' && !(type instanceof api.NamedNode)) throw new TypeError('Expected optional argument[1] `type` to be a string/RDFNode'); 248 | this.nominalValue = value; 249 | if(type instanceof NamedNode){ 250 | this.datatype = type; 251 | this.language = null; 252 | }else if(typeof type=='string'){ 253 | if(type.match(/^[a-zA-Z]+(-[a-zA-Z0-9]+)*$/)){ 254 | this.datatype = rdflangString; 255 | this.language = type; 256 | }else if(type.match(/^@[a-zA-Z]+(-[a-zA-Z0-9]+)*$/)){ 257 | this.datatype = rdflangString; 258 | this.language = type.substring(1); 259 | }else if(type.match(/^[a-zA-Z][a-zA-Z0-9+.\-]*:/)){ 260 | this.datatype = new NamedNode(type); 261 | this.language = null; 262 | }else{ 263 | throw new Error('Expected argument[1] `type` to look like a LangTag or IRI'); 264 | } 265 | }else{ 266 | this.datatype = xsdstring; 267 | this.language = null; 268 | } 269 | } 270 | api.Literal.typed = function createTypedLiteral(value, datatype){ 271 | if(typeof value!='string') throw new Error('Expected argument[0] `value` to be a string'); 272 | if(typeof datatype!='string' && !(datatype instanceof api.NamedNode)) throw new Error('Expected argument[1] `datatype` to be a string'); 273 | if(!datatype.toString().match(/^[a-zA-Z][a-zA-Z0-9+.\-]*:/)) throw new Error('Expected argument[1] `datatype` to be an IRI'); 274 | var literal = new api.Literal(value); 275 | if(datatype.toString()!=='http://www.w3.org/2001/XMLSchema#string'){ 276 | literal.datatype = datatype; 277 | } 278 | return literal; 279 | }; 280 | api.Literal.language = function createLanguageLiteral(value, language){ 281 | if(typeof value!='string') throw new Error('Expected argument[0] `value` to be a string'); 282 | if(typeof language!='string') throw new Error('Expected argument[1] `language` to be a string'); 283 | if(!language.match(/^[a-zA-Z]+(-[a-zA-Z0-9]+)*$/)) throw new Error('Expected argument[1] `language` to be a BCP47 language tag'); 284 | var literal = new api.Literal(value); 285 | literal.language = language; 286 | return literal; 287 | }; 288 | api.Literal.prototype.nodeType = function() { 289 | if(rdflangString.equals(this.datatype) && this.language) return 'PlainLiteral'; 290 | if(xsdstring.equals(this.datatype)) return 'PlainLiteral'; 291 | return 'TypedLiteral'; 292 | }; 293 | api.Literal.prototype.interfaceName = "Literal"; 294 | api.Literal.prototype.termType = "Literal"; 295 | api.Literal.prototype.toNT = function toNT() { 296 | var string = '"'+encodeString(this.nominalValue)+'"'; 297 | if(this.language) return string+"@"+this.language; 298 | else if(xsdstring.equals(this.datatype)) return string; 299 | else if(this.datatype) return string+'^^<'+this.datatype+">"; 300 | throw new Error('Unknown datatype'); 301 | }; 302 | api.Literal.prototype.toTurtle = function toTurtle(profile){ 303 | if(xsdinteger.equals(this.datatype) && this.value.match(INTEGER)){ 304 | return this.value; 305 | } 306 | if(xsddecimal.equals(this.datatype) && this.value.match(DECIMAL)){ 307 | return this.value; 308 | } 309 | if(xsddouble.equals(this.datatype) && this.value.match(DOUBLE)){ 310 | return this.value; 311 | } 312 | if(xsdboolean.equals(this.datatype) && this.value.match(BOOLEAN)){ 313 | return this.value; 314 | } 315 | if(profile && this.type){ 316 | var shrunk = profile.shrink(this.datatype.toString()); 317 | if(shrunk!=this.datatype.toString()) return shrunk; 318 | } 319 | // TODO if it's xsd:integer/xsd:decimal/xsd:double/xsd:boolean, return simplified form 320 | return this.toNT(); 321 | }; 322 | api.Literal.prototype.n3 = function n3(profile){ 323 | return this.toTurtle(profile); 324 | }; 325 | // Literal#valueOf returns a language-native value - e.g. a number, boolean, or Date where possible 326 | api.Literal.prototype.valueOf = function() { 327 | if(this.datatype && typeof api.Literal.typeValueOf[this.datatype]=="function"){ 328 | return api.Literal.typeValueOf[this.datatype](this.nominalValue, this.datatype); 329 | } 330 | return this.nominalValue; 331 | }; 332 | Object.defineProperty(api.Literal.prototype, 'type', { get: function(){ 333 | if(rdflangString.equals(this.datatype)) return null; 334 | if(xsdstring.equals(this.datatype)) return null; 335 | return this.datatype.nominalValue; 336 | } }); 337 | 338 | 339 | api.Literal.typeValueOf = {}; 340 | api.Literal.registerTypeConversion = function(datatype, f){ 341 | api.Literal.typeValueOf[datatype] = f; 342 | }; 343 | require('./space.js').loadDefaultTypeConverters(api.Literal); 344 | 345 | /** 346 | * NamedNode 347 | */ 348 | api.NamedNode = NamedNode; 349 | inherits(api.NamedNode, api.RDFNode); 350 | function NamedNode(iri) { 351 | if(typeof iri!='string') throw new TypeError('argument iri not a string'); 352 | if(iri[0]=='_' && iri[1]==':') throw new Error('unexpected BlankNode syntax'); 353 | if(!iri.match(api.NamedNode.SCHEME_MATCH)) throw new Error('Expected arguments[0] `iri` to look like an IRI'); 354 | if(iri.indexOf(' ') >= 0) throw new Error('Unexpected whitespace in arguments[0] `iri`'); 355 | this.nominalValue = iri; 356 | } 357 | api.NamedNode.SCHEME_MATCH = new RegExp("^[a-z0-9-.+]+:", "i"); 358 | api.NamedNode.prototype.nodeType = function nodeType() { return "IRI"; }; 359 | api.NamedNode.prototype.interfaceName = "NamedNode"; 360 | api.NamedNode.prototype.termType = "NamedNode"; 361 | api.NamedNode.prototype.toNT = function toNT() { 362 | return "<" + encodeString(this.nominalValue) + ">"; 363 | }; 364 | api.NamedNode.prototype.toTurtle = function toTurtle(profile) { 365 | if(profile){ 366 | var shrunk = profile.shrink(this.nominalValue); 367 | if(shrunk!=this.nominalValue) return shrunk; 368 | } 369 | return this.toNT(); 370 | }; 371 | api.NamedNode.prototype.n3 = function n3(profile) { 372 | return this.toTurtle(profile); 373 | }; 374 | 375 | /** 376 | * TriplePattern 377 | */ 378 | api.TriplePattern = function TriplePattern(s, p, o) { 379 | if(typeof s=='string') s = new NamedNode(s); 380 | if(!api.RDFNode.is(s)) throw new Error('TriplePattern subject is not an RDFNode'); 381 | if(s.termType!=='NamedNode' && s.termType!=='BlankNode' && s.termType!=='Variable') throw new Error('subject must be a NamedNode/BlankNode/Variable'); 382 | 383 | if(typeof p=='string') p = new NamedNode(p); 384 | if(!api.RDFNode.is(p)) throw new Error('TriplePattern predicate is not an RDFNode'); 385 | if(p.termType!=='NamedNode' && p.termType!=='Variable') throw new Error('predicate must be a NamedNode/Variable'); 386 | 387 | if(typeof o=='string') o = new NamedNode(o); 388 | if(!api.RDFNode.is(o)) throw new Error('TriplePattern object is not an RDFNode'); 389 | if(o.termType!=='NamedNode' && o.termType!=='BlankNode' && o.termType!=='Literal' && o.termType!=='Variable') throw new Error('object must be a NamedNode/BlankNode/Literal/Variable'); 390 | 391 | this.subject = s; 392 | this.predicate = p; 393 | this.object = o; 394 | }; 395 | api.TriplePattern.prototype.size = 3; 396 | api.TriplePattern.prototype.length = 3; 397 | api.TriplePattern.prototype.toString = function() { 398 | return this.subject.n3() + " " + this.predicate.n3() + " " + this.object.n3() + " ."; 399 | }; 400 | api.TriplePattern.prototype.equals = function(t) { 401 | return RDFNodeEquals.call(this.subject,t.subject) && RDFNodeEquals.call(this.predicate,t.predicate) && RDFNodeEquals.call(this.object,t.object); 402 | }; 403 | 404 | /** 405 | * Variable 406 | */ 407 | api.Variable = Variable; 408 | inherits(api.Variable, api.RDFNode); 409 | function Variable(name) { 410 | if(typeof name!='string') throw new Error('Expected arguments[0] `name` to be a string'); 411 | if(name[0]=='?' || name[0]=='$') name = name.substring(1); 412 | this.nominalValue = name; 413 | } 414 | api.Variable.SCHEME_MATCH = new RegExp("^[a-z0-9-.+]+:", "i"); 415 | api.Variable.prototype.nodeType = function nodeType() { return "Variable"; }; 416 | api.Variable.prototype.interfaceName = "Variable"; 417 | api.Variable.prototype.termType = "Variable"; 418 | api.Variable.prototype.toNT = function() { 419 | throw new Error('Cannot serialize variable to N-Triples'); 420 | }; 421 | api.Variable.prototype.toTurtle = function toTurtle() { 422 | throw new Error('Cannot serialize variable to Turtle'); 423 | }; 424 | api.Variable.prototype.n3 = function n3() { 425 | return '?'+this.nominalValue; 426 | }; 427 | 428 | /* 429 | interface DefaultGraph : Term { 430 | attribute string termType; 431 | attribute string value; 432 | boolean equals(Term other); 433 | }; 434 | */ 435 | api.DefaultGraph = DefaultGraph; 436 | inherits(api.DefaultGraph, api.RDFNode); 437 | function DefaultGraph() { 438 | } 439 | api.DefaultGraph.prototype.interfaceName = "DefaultGraph"; 440 | api.DefaultGraph.prototype.termType = "DefaultGraph"; 441 | api.DefaultGraph.prototype.nominalValue = ""; 442 | api.DefaultGraph.prototype.toNT = function() { 443 | throw new Error('Cannot serialize DefaultGraph to N-Triples'); 444 | }; 445 | api.DefaultGraph.prototype.toTurtle = function toTurtle() { 446 | throw new Error('Cannot serialize DefaultGraph to Turtle'); 447 | }; 448 | api.DefaultGraph.prototype.n3 = function n3() { 449 | throw new Error('Cannot serialize DefaultGraph to n3'); 450 | }; 451 | 452 | // Constants needed for processing Literals 453 | var xsdstring = new NamedNode('http://www.w3.org/2001/XMLSchema#string'); 454 | var rdflangString = new NamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#langString'); 455 | 456 | // Shamelessly copied from Builtins.js, also found in TurtleParser.js 457 | var xsdns = require('./ns.js').xsdns; 458 | var INTEGER = new RegExp("^(-|\\+)?[0-9]+$", ""); 459 | var xsdinteger = new NamedNode(xsdns('integer')); 460 | var DOUBLE = new RegExp("^(-|\\+)?(([0-9]+\\.[0-9]*[eE]{1}(-|\\+)?[0-9]+)|(\\.[0-9]+[eE]{1}(-|\\+)?[0-9]+)|([0-9]+[eE]{1}(-|\\+)?[0-9]+))$", ""); 461 | var xsddouble = new NamedNode(xsdns('double')); 462 | var DECIMAL = new RegExp("^(-|\\+)?[0-9]*\\.[0-9]+?$", ""); 463 | var xsddecimal = new NamedNode(xsdns('decimal')); 464 | var BOOLEAN = new RegExp("^(true|false)", ""); 465 | var xsdboolean = new NamedNode(xsdns('boolean')); 466 | -------------------------------------------------------------------------------- /lib/ResultSet.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var Graph = require('./Graph.js'); 4 | var RDFNode = require('./RDFNode.js'); 5 | 6 | module.exports.ResultSet = ResultSet; 7 | function ResultSet(graph, initialNode){ 8 | if(typeof initialNode=='string') initialNode = new RDFNode.NamedNode(initialNode); 9 | if(!(graph instanceof Graph.Graph)) throw new TypeError('Expected argument[0] `graph` to be a Graph'); 10 | this.graph = graph; 11 | this.set = []; 12 | if(initialNode){ 13 | if(!RDFNode.RDFNode.is(initialNode)) throw new Error('Triple initialNode is not an RDFNode'); 14 | if(initialNode.termType!=='NamedNode' && initialNode.termType!=='BlankNode') throw new Error('subject must be a NamedNode/BlankNode'); 15 | this.set.push(initialNode); 16 | } 17 | } 18 | 19 | ResultSet.prototype.set = []; 20 | 21 | ResultSet.prototype.add = function(node){ 22 | // @@@TODO maybe verify that `node` is somewhere in the graph 23 | if(this.set.some(function(v){ return v.equals(node); })) return; 24 | this.set.push(node); 25 | }; 26 | 27 | ResultSet.prototype.rel = function(predicate){ 28 | if(typeof predicate=='string') predicate = new RDFNode.NamedNode(predicate); 29 | if(!RDFNode.RDFNode.is(predicate)) throw new Error('Expected argument[0] `predicate` to be an RDFNode'); 30 | if(predicate.termType!=='NamedNode') throw new Error('Expected argument[0] `predicate` to be a NamedNode'); 31 | var graph = this.graph; 32 | var set = this.set; 33 | var result = new ResultSet(graph); 34 | set.forEach(function(node){ 35 | if(node.termType!='NamedNode' && node.termType!='BlankNode') return; 36 | graph.match(node, predicate, null).forEach(function(triple){ 37 | result.add(triple.object); 38 | }); 39 | }); 40 | return result; 41 | }; 42 | 43 | ResultSet.prototype.rev = function rev(predicate){ 44 | if(typeof predicate=='string') predicate = new RDFNode.NamedNode(predicate); 45 | if(!RDFNode.RDFNode.is(predicate)) throw new Error('Expected argument[0] `predicate` to be an RDFNode'); 46 | if(predicate.termType!=='NamedNode') throw new Error('Expected argument[0] `predicate` to be a NamedNode'); 47 | var graph = this.graph; 48 | var set = this.set; 49 | var result = new ResultSet(graph); 50 | set.forEach(function(node){ 51 | graph.match(null, predicate, node).forEach(function(triple){ 52 | result.add(triple.subject); 53 | }); 54 | }); 55 | return result; 56 | }; 57 | 58 | ResultSet.prototype.toArray = function toArray(callback){ 59 | return this.set.slice(); 60 | }; 61 | 62 | ResultSet.prototype.some = function some(callback){ 63 | return this.set.some(callback); 64 | }; 65 | 66 | ResultSet.prototype.every = function every(callback){ 67 | return this.set.every(callback); 68 | }; 69 | 70 | ResultSet.prototype.filter = function filter(callback){ 71 | var result = new ResultSet(this.graph); 72 | // FIXME this can probably be optimized since we're only removing nodes 73 | this.set.filter(callback).forEach(function(node){ 74 | result.add(node); 75 | }); 76 | return result; 77 | }; 78 | 79 | ResultSet.prototype.forEach = function forEach(callback){ 80 | return this.set.forEach(callback); 81 | }; 82 | 83 | ResultSet.prototype.map = function map(callback){ 84 | var result = new ResultSet(this.graph); 85 | this.set.map(callback).forEach(function(node){ 86 | result.add(node); 87 | }); 88 | return result; 89 | }; 90 | 91 | ResultSet.prototype.reduce = function reduce(callback, initial){ 92 | return this.set.reduce(callback, initial); 93 | }; 94 | 95 | ResultSet.prototype.one = function one(callback){ 96 | if(this.set.length>1) throw new Error('Expected one match'); 97 | if(this.set.length===0) return null; 98 | return this.set[0]; 99 | }; 100 | 101 | Object.defineProperty(ResultSet.prototype, 'length', { get: function(){ return this.set.length; } }); 102 | -------------------------------------------------------------------------------- /lib/TurtleParser.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var parsers = exports; 4 | 5 | var IRI = require('iri').IRI; 6 | var env = require('./environment.js').environment; 7 | function rdfns(v){return 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'+v;} 8 | function xsdns(v){return 'http://www.w3.org/2001/XMLSchema#'+v;} 9 | 10 | parsers.u8 = new RegExp("\\\\U([0-9A-Fa-f]{8})", "g"); 11 | parsers.u4 = new RegExp("\\\\u([0-9A-Fa-f]{4})", "g"); 12 | parsers.hexToChar = function hexToChar(hex) { 13 | var result = ""; 14 | var n = parseInt(hex, 16); 15 | if(n <= 65535) { 16 | result += String.fromCharCode(n); 17 | } else if(n <= 1114111) { 18 | n -= 65536; 19 | result += String.fromCharCode(55296 + (n >> 10), 56320 + (n & 1023)); 20 | } else { 21 | throw new Error("code point isn't known: " + n); 22 | } 23 | return result; 24 | }; 25 | parsers.decodeString = function decodeString(str) { 26 | str = str.replace(parsers.u8, function(matchstr, parens) { return parsers.hexToChar(parens); }); 27 | str = str.replace(parsers.u4, function(matchstr, parens) { return parsers.hexToChar(parens); }); 28 | str = str.replace(new RegExp("\\\\t", "g"), "\t"); 29 | str = str.replace(new RegExp("\\\\b", "g"), "\b"); 30 | str = str.replace(new RegExp("\\\\n", "g"), "\n"); 31 | str = str.replace(new RegExp("\\\\r", "g"), "\r"); 32 | str = str.replace(new RegExp("\\\\f", "g"), "\f"); 33 | str = str.replace(new RegExp('\\\\"', "g"), '"'); 34 | str = str.replace(new RegExp("\\\\\\\\", "g"), "\\"); 35 | return str; 36 | }; 37 | parsers.decodePrefixedName = function(str){ 38 | var decoded = ''; 39 | for(var i=0; i 0) { 113 | s = this.skipWS(s); 114 | if(s.length == 0) return true; 115 | s = (s.charAt(0)=="@" || s.substring(0,4).toUpperCase()=='BASE' || s.substring(0,6).toUpperCase()=='PREFIX') ? this.consumeDirective(s) : this.consumeStatement(s); 116 | s = this.skipWS(s); 117 | } 118 | return true; 119 | }; 120 | Turtle.prototype.createTriple = function createTriple(s, p, o){ 121 | return env.createTriple(s, p, o); 122 | }; 123 | Turtle.prototype.createNamedNode = function createNamedNode(v){ 124 | return env.createNamedNode(v); 125 | }; 126 | Turtle.prototype.createBlankNode = function createBlankNode(){ 127 | return env.createBlankNode(); 128 | }; 129 | Turtle.prototype.createLiteral = function createLiteral(v, l, t){ 130 | return env.createLiteral(v, l, t); 131 | }; 132 | Turtle.prototype.add = function(t) { 133 | var $use = true; 134 | if(this.filter != null) $use = this.filter(t, null, null); 135 | if(!$use) return; 136 | this.processor ? this.processor(null, t) : this.graph.add(t); 137 | }; 138 | Turtle.prototype.consumeBlankNode = function(s, t) { 139 | t.o = this.createBlankNode(); 140 | s = this.skipWS(s.slice(1)); 141 | if(s.charAt(0) == "]") return s.slice(1); 142 | s = this.skipWS(this.consumePredicateObjectList(s, t)); 143 | this.expect(s, "]"); 144 | return this.skipWS(s.slice(1)); 145 | }; 146 | Turtle.prototype.consumeCollection = function(s, subject) { 147 | subject.o = this.createBlankNode(); 148 | var listject = this.t(); 149 | listject.o = subject.o; 150 | s = this.skipWS(s.slice(1)); 151 | var cont = s.charAt(0) != ")"; 152 | if(!cont) { subject.o = this.createNamedNode(rdfns("nil")); } 153 | while(cont) { 154 | var o = this.t(); 155 | switch(s.charAt(0)) { 156 | case "[": s = this.consumeBlankNode(s, o); break; 157 | case "_": s = this.consumeKnownBlankNode(s, o); break; 158 | case "(": s = this.consumeCollection(s, o); break; 159 | case "<": s = this.consumeURI(s, o); break; 160 | case '"': case "'": s = this.consumeLiteral(s, o); break; 161 | case '+': case '-': case '.': 162 | case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': 163 | var token; 164 | if(token = Turtle.tokenDouble.exec(s)){ 165 | token = token[0]; 166 | o.o = this.createLiteral(token, null, xsdns("double")); 167 | } else if(token = Turtle.tokenDecimal.exec(s)){ 168 | token = token[0]; 169 | o.o = this.createLiteral(token, null, xsdns("decimal")); 170 | } else if(token = Turtle.tokenInteger.exec(s)){ 171 | token = token[0]; 172 | o.o = this.createLiteral(token, null, xsdns("integer")); 173 | } else { 174 | throw new Error("Expected NumericLiteral"); 175 | } 176 | s = s.slice(token.length); 177 | break; 178 | default: 179 | var token = s.match(Turtle.simpleObjectToken).shift(); 180 | if(token.charAt(token.length - 1) == ")") { 181 | token = token.substring(0, token.length - 1); 182 | } 183 | if(token==="false" || token==="true"){ 184 | o.o = this.createLiteral(token, null, xsdns("boolean")); 185 | }else if(token.indexOf(":") >= 0) { 186 | o.o = this.createNamedNode(this.environment.resolve(token)); 187 | } 188 | s = s.slice(token.length); 189 | break; 190 | } 191 | this.add(this.createTriple(listject.o, this.createNamedNode(rdfns("first")), o.o)); 192 | s = this.skipWS(s); 193 | cont = s.charAt(0) != ")"; 194 | if(cont) { 195 | this.add(this.createTriple(listject.o, this.createNamedNode(rdfns("rest")), listject.o = this.createBlankNode())); 196 | } else { 197 | this.add(this.createTriple(listject.o, this.createNamedNode(rdfns("rest")), this.createNamedNode(rdfns("nil")))); 198 | } 199 | } 200 | return this.skipWS(s.slice(1)); 201 | }; 202 | Turtle.prototype.consumeDirective = function(s) { 203 | var p = 0; 204 | if(s.substring(1, 7) == "prefix") { 205 | s = this.skipWS(s.slice(7)); 206 | p = s.indexOf(":"); 207 | var prefix = s.substring(0, p); 208 | s = this.skipWS(s.slice(++p)); 209 | this.expect(s, "<"); 210 | this.environment.setPrefix(prefix, this.base.resolveReference(parsers.decodeIRIREF(s.substring(1, p = s.indexOf(">")))).toString()); 211 | s = this.skipWS(s.slice(++p)); 212 | this.expect(s, "."); 213 | s = s.slice(1); 214 | } else if(s.substring(0, 6).toUpperCase() == "PREFIX") { 215 | // SPARQL-style 216 | s = this.skipWS(s.slice(7)); 217 | p = s.indexOf(":"); 218 | var prefix = s.substring(0, p); 219 | s = this.skipWS(s.slice(++p)); 220 | this.expect(s, "<"); 221 | this.environment.setPrefix(prefix, this.base.resolveReference(parsers.decodeIRIREF(s.substring(1, p = s.indexOf(">")))).toString()); 222 | s = this.skipWS(s.slice(++p)); 223 | } else if(s.substring(1, 5) == "base") { 224 | s = this.skipWS(s.slice(5)); 225 | this.expect(s, "<"); 226 | this.base = this.base.resolveReference(parsers.decodeIRIREF(s.substring(1, p = s.indexOf(">")))); 227 | s = this.skipWS(s.slice(++p)); 228 | this.expect(s, "."); 229 | s = s.slice(1); 230 | } else if(s.substring(0, 4).toUpperCase() == "BASE") { 231 | // SPARQL-style 232 | s = this.skipWS(s.slice(5)); 233 | this.expect(s, "<"); 234 | this.base = this.base.resolveReference(parsers.decodeIRIREF(s.substring(1, p = s.indexOf(">")))); 235 | s = this.skipWS(s.slice(++p)); 236 | } else { 237 | throw new Error("Unknown directive: " + s.substring(0, 50)); 238 | } 239 | return s; 240 | }; 241 | Turtle.prototype.consumeKnownBlankNode = function(s, t) { 242 | this.expect(s, "_:"); 243 | var bname = s.slice(2).match(Turtle.simpleToken).shift(); 244 | t.o = this.getBlankNode(bname); 245 | return s.slice(bname.length + 2); 246 | }; 247 | Turtle.prototype.consumeLiteral = function(s, o) { 248 | var char = s[0]; 249 | var value = ""; 250 | var end = 0; 251 | var longchar = char+char+char; 252 | if(s.substring(0, 3) == longchar) { 253 | for(end=3; end"); 280 | if(iri_end<0) throw new Error('Could not find terminating ">"'); 281 | var iri_esc = s.substring(1, iri_end); 282 | iri_val = this.createNamedNode(this.base.resolveReference(parsers.decodeIRIREF(iri_esc)).toString()); 283 | s = this.skipWS(s.substring(iri_end+1)); 284 | }else{ 285 | var prefixedName = Turtle.PrefixedName.exec(s); 286 | if(!prefixedName) throw new Error('Expected PrefixedName'); 287 | prefixedName = prefixedName[0]; 288 | iri_val = this.environment.resolve(parsers.decodePrefixedName(prefixedName)); 289 | if(!iri_val) throw new Error('Could not resolve PrefixedName '+JSON.stringify(parsers.decodePrefixedName(prefixedName))); 290 | s = this.skipWS(s.slice(prefixedName.length)); 291 | } 292 | o.o = this.createLiteral(value, null, iri_val); 293 | break; 294 | default: 295 | o.o = this.createLiteral(value, null, null); 296 | break; 297 | } 298 | return s; 299 | }; 300 | Turtle.prototype.consumeObjectList = function(s, subject, property) { 301 | var cont = true; 302 | while(cont) { 303 | var o = this.t(); 304 | switch(s.charAt(0)) { 305 | case "[": s = this.consumeBlankNode(s, o); break; 306 | case "_": s = this.consumeKnownBlankNode(s, o); break; 307 | case "(": s = this.consumeCollection(s, o); break; 308 | case "<": s = this.consumeURI(s, o); break; 309 | case '"': case "'": s = this.consumeLiteral(s, o); break; 310 | case '+': case '-': case '.': 311 | case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': 312 | var token; 313 | if(token = Turtle.tokenDouble.exec(s)){ 314 | token = token[0]; 315 | o.o = this.createLiteral(token, null, xsdns("double")); 316 | } else if(token = Turtle.tokenDecimal.exec(s)){ 317 | token = token[0]; 318 | o.o = this.createLiteral(token, null, xsdns("decimal")); 319 | } else if(token = Turtle.tokenInteger.exec(s)){ 320 | token = token[0]; 321 | o.o = this.createLiteral(token, null, xsdns("integer")); 322 | } else { 323 | throw new Error("Expected NumericLiteral"); 324 | } 325 | s = s.slice(token.length); 326 | break; 327 | default: 328 | var token = s.match(Turtle.simpleObjectToken); 329 | var prefixedName; 330 | token = token&&token[0] || ""; 331 | if(token.charAt(token.length - 1) == ".") { 332 | token = token.substring(0, token.length - 1); 333 | } 334 | if(token==="true" || token==="false"){ 335 | o.o = this.createLiteral(token, null, xsdns("boolean")); 336 | s = s.slice(token.length); 337 | }else if(prefixedName=Turtle.PrefixedName.exec(token)) { 338 | var prefixedName = prefixedName[0]; 339 | var iri = this.environment.resolve(parsers.decodePrefixedName(prefixedName)); 340 | if(!iri) throw new Error('Could not resolve PrefixedName '+JSON.stringify(parsers.decodePrefixedName(prefixedName))); 341 | o.o = this.createNamedNode(iri); 342 | if(!o.o) throw new Error('Prefix not defined for '+token); 343 | s = s.slice(prefixedName.length); 344 | } else { 345 | throw new Error("Unrecognized token in ObjectList: " + token); 346 | } 347 | break; 348 | } 349 | s = this.skipWS(s); 350 | this.add(this.createTriple(subject.o, property, o.o)); 351 | cont = s.charAt(0)==","; 352 | if(cont) { s = this.skipWS(s.slice(1)); } 353 | } 354 | return s; 355 | }; 356 | Turtle.prototype.consumePredicateObjectList = function(s, subject) { 357 | var cont = true; 358 | while(cont) { 359 | var predicate = s.match(Turtle.PrefixedName); 360 | if(predicate){ 361 | predicate = predicate.shift(); 362 | var iri = this.environment.resolve(parsers.decodePrefixedName(predicate)); 363 | if(!iri) throw new Error('Could not resolve PrefixedName '+JSON.stringify(parsers.decodePrefixedName(predicate))); 364 | property = this.createNamedNode(iri); 365 | s = this.skipWS(s.slice(predicate.length)); 366 | s = this.consumeObjectList(s, subject, property); 367 | continue; 368 | } 369 | switch(s.charAt(0)) { 370 | case "a": 371 | var property = this.createNamedNode(rdfns("type")); 372 | s = this.skipWS(s.substring(1)); 373 | break; 374 | case "<": 375 | var iri_end = s.indexOf(">"); 376 | var iri = s.substring(1, iri_end); 377 | property = this.createNamedNode(this.base.resolveReference(parsers.decodeIRIREF(iri)).toString()); 378 | s = this.skipWS(s.substring(iri_end+1)); 379 | break; 380 | case "]": return s; 381 | case ".": return s; 382 | case ";": 383 | // empty predicate, skip 384 | s = this.skipWS(s.substring(1)); 385 | continue; 386 | default: 387 | throw new Error('Expected PrefixedName'); 388 | } 389 | s = this.consumeObjectList(s, subject, property); 390 | cont = s.charAt(0)==";"; 391 | if(cont) { s = this.skipWS(s.slice(1)); } 392 | } 393 | return s; 394 | }; 395 | Turtle.prototype.consumePrefixedName = function(s, t) { 396 | var name = s.match(Turtle.PrefixedName).shift(); 397 | var iri = this.environment.resolve(parsers.decodePrefixedName(name)); 398 | if(!iri) throw new Error('Could not resolve '+JSON.stringify(parsers.decodePrefixedName(name))); 399 | t.o = this.createNamedNode(iri); 400 | return s.slice(name.length); 401 | }; 402 | Turtle.prototype.consumeStatement = function(s) { 403 | var t = this.t(); 404 | switch(s.charAt(0)) { 405 | case "[": 406 | s = this.consumeBlankNode(s, t); 407 | if(s.charAt(0) == ".") return s.slice(1); 408 | break; 409 | case "_": s = this.consumeKnownBlankNode(s, t); break; 410 | case "(": s = this.consumeCollection(s, t); break; 411 | case "<": s = this.consumeURI(s, t); break; 412 | default: s = this.consumePrefixedName(s, t); break; 413 | } 414 | s = this.consumePredicateObjectList(this.skipWS(s), t); 415 | this.expect(s, "."); 416 | return s.slice(1); 417 | }; 418 | Turtle.prototype.consumeURI = function(s, t) { 419 | this.expect(s, "<"); 420 | var p = 0; 421 | t.o = this.createNamedNode(this.base.resolveReference(parsers.decodeIRIREF(s.substring(1, p=s.indexOf(">")))).toString()); 422 | return s.slice(++p); 423 | }; 424 | Turtle.prototype.getBlankNode = function(id) { 425 | if(this.bnHash[id]) return this.bnHash[id]; 426 | return this.bnHash[id]=this.createBlankNode(); 427 | }; 428 | Turtle.prototype.skipWS = function(s) { 429 | while(Turtle.isWhitespace.test(s.charAt(0))) { 430 | s = s.replace(Turtle.initialWhitespace, ""); 431 | if(s.charAt(0) == "#") { 432 | s = s.replace(Turtle.initialComment, ""); 433 | } 434 | } 435 | return s; 436 | }; 437 | -------------------------------------------------------------------------------- /lib/encodeString.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // #x22#x5C#xA#xD 4 | var encodeMap = { 5 | '"': '\\"', 6 | '\\': '\\\\', 7 | "\r": '\\r', 8 | "\n": '\\n', 9 | "\t": '\\t', 10 | }; 11 | 12 | // Takes a string and produces an escaped Turtle String production but without quotes 13 | module.exports = encodeASCIIString; 14 | 15 | // Use this to output the unicode character whenever it's legal in N-Triples 16 | // var encodeSearch = /["\r\n\\]/g; 17 | // function encodeString(str) { 18 | // return str.replace(encodeSearch, function(a, b){ 19 | // return encodeMap[b]; 20 | // }); 21 | // } 22 | 23 | var encodeASCIIStringSearch = /(["\r\n\t\\])|([\u0080-\uD7FF\uE000-\uFFFF])|([\uD800-\uDBFF][\uDC00-\uDFFF])/g; 24 | function encodeASCIIStringReplace(a, b, c, d){ 25 | if(b){ 26 | // These characters must be escaped 27 | // Actually \t doesn't have to, but it's allowed and common to do so 28 | return encodeMap[b]; 29 | } 30 | if(c){ 31 | // The match is a non-ASCII code point that's not a surrogate pair 32 | return '\\u'+('0000'+c.charCodeAt(0).toString(16).toUpperCase()).substr(-4); 33 | } 34 | if(d){ 35 | // The match is a UTF-16 surrogate pair, compute the UTF-32 codepoint 36 | var hig = d.charCodeAt(0); 37 | var low = d.charCodeAt(1); 38 | var code = (hig - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000; 39 | return '\\U'+('00000000'+code.toString(16).toUpperCase()).substr(-8); 40 | } 41 | } 42 | 43 | // Return a Turtle string with backslash escapes for all non-7-bit characters 44 | function encodeASCIIString(str){ 45 | return str.replace(encodeASCIIStringSearch, encodeASCIIStringReplace); 46 | } 47 | -------------------------------------------------------------------------------- /lib/environment.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var RDFEnvironment = require("./RDFEnvironment.js").RDFEnvironment; 4 | var DataFactory = require("./DataFactory.js").DataFactory; 5 | 6 | var env = exports.environment = new RDFEnvironment; 7 | require('./prefixes.js').loadDefaultPrefixMap(env); 8 | exports.factory = new DataFactory; 9 | -------------------------------------------------------------------------------- /lib/ns.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | exports.ns = function(prefix){ 4 | if(typeof prefix!='string') throw new TypeError('Expected argument[0] `prefix` to be a string'); 5 | return function(suffix){ 6 | if(typeof suffix!='string') throw new TypeError('Expected argument[0] `suffix` to be a string'); 7 | return prefix.concat(suffix); 8 | }; 9 | }; 10 | 11 | exports.rdfns = exports.ns('http://www.w3.org/1999/02/22-rdf-syntax-ns#'); 12 | exports.rdfsns = exports.ns('http://www.w3.org/2000/01/rdf-schema#'); 13 | exports.xsdns = exports.ns('http://www.w3.org/2001/XMLSchema#'); 14 | -------------------------------------------------------------------------------- /lib/prefixes.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | exports.loadRequiredPrefixMap = function(context){ 4 | context.setPrefix("owl", "http://www.w3.org/2002/07/owl#"); 5 | context.setPrefix("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"); 6 | context.setPrefix("rdfs", "http://www.w3.org/2000/01/rdf-schema#"); 7 | context.setPrefix("rdfa", "http://www.w3.org/ns/rdfa#"); 8 | context.setPrefix("xhv", "http://www.w3.org/1999/xhtml/vocab#"); 9 | context.setPrefix("xml", "http://www.w3.org/XML/1998/namespace"); 10 | context.setPrefix("xsd", "http://www.w3.org/2001/XMLSchema#"); 11 | }; 12 | exports.loadDefaultPrefixMap = function(context){ 13 | exports.loadRequiredPrefixMap(context); 14 | context.setPrefix("grddl", "http://www.w3.org/2003/g/data-view#"); 15 | context.setPrefix("powder", "http://www.w3.org/2007/05/powder#"); 16 | context.setPrefix("powders", "http://www.w3.org/2007/05/powder-s#"); 17 | context.setPrefix("rif", "http://www.w3.org/2007/rif#"); 18 | context.setPrefix("atom", "http://www.w3.org/2005/Atom/"); 19 | context.setPrefix("xhtml", "http://www.w3.org/1999/xhtml#"); 20 | context.setPrefix("formats", "http://www.w3.org/ns/formats/"); 21 | context.setPrefix("xforms", "http://www.w3.org/2002/xforms/"); 22 | context.setPrefix("xhtmlvocab", "http://www.w3.org/1999/xhtml/vocab/"); 23 | context.setPrefix("xpathfn", "http://www.w3.org/2005/xpath-functions#"); 24 | //context.setPrefix("http", "http://www.w3.org/2006/http#"); 25 | context.setPrefix("link", "http://www.w3.org/2006/link#"); 26 | context.setPrefix("time", "http://www.w3.org/2006/time#"); 27 | context.setPrefix("acl", "http://www.w3.org/ns/auth/acl#"); 28 | context.setPrefix("cert", "http://www.w3.org/ns/auth/cert#"); 29 | context.setPrefix("rsa", "http://www.w3.org/ns/auth/rsa#"); 30 | context.setPrefix("crypto", "http://www.w3.org/2000/10/swap/crypto#"); 31 | context.setPrefix("list", "http://www.w3.org/2000/10/swap/list#"); 32 | context.setPrefix("log", "http://www.w3.org/2000/10/swap/log#"); 33 | context.setPrefix("math", "http://www.w3.org/2000/10/swap/math#"); 34 | context.setPrefix("os", "http://www.w3.org/2000/10/swap/os#"); 35 | context.setPrefix("string", "http://www.w3.org/2000/10/swap/string#"); 36 | context.setPrefix("doc", "http://www.w3.org/2000/10/swap/pim/doc#"); 37 | context.setPrefix("contact", "http://www.w3.org/2000/10/swap/pim/contact#"); 38 | context.setPrefix("p3p", "http://www.w3.org/2002/01/p3prdfv1#"); 39 | context.setPrefix("swrl", "http://www.w3.org/2003/11/swrl#"); 40 | context.setPrefix("swrlb", "http://www.w3.org/2003/11/swrlb#"); 41 | context.setPrefix("exif", "http://www.w3.org/2003/12/exif/ns#"); 42 | context.setPrefix("earl", "http://www.w3.org/ns/earl#"); 43 | context.setPrefix("ma", "http://www.w3.org/ns/ma-ont#"); 44 | context.setPrefix("sawsdl", "http://www.w3.org/ns/sawsdl#"); 45 | context.setPrefix("sd", "http://www.w3.org/ns/sparql-service-description#"); 46 | context.setPrefix("skos", "http://www.w3.org/2004/02/skos/core#"); 47 | context.setPrefix("fresnel", "http://www.w3.org/2004/09/fresnel#"); 48 | context.setPrefix("gen", "http://www.w3.org/2006/gen/ont#"); 49 | context.setPrefix("timezone", "http://www.w3.org/2006/timezone#"); 50 | context.setPrefix("skosxl", "http://www.w3.org/2008/05/skos-xl#"); 51 | context.setPrefix("org", "http://www.w3.org/ns/org#"); 52 | context.setPrefix("ical", "http://www.w3.org/2002/12/cal/ical#"); 53 | context.setPrefix("wgs84", "http://www.w3.org/2003/01/geo/wgs84_pos#"); 54 | context.setPrefix("vcard", "http://www.w3.org/2006/vcard/ns#"); 55 | context.setPrefix("turtle", "http://www.w3.org/2008/turtle#"); 56 | context.setPrefix("pointers", "http://www.w3.org/2009/pointers#"); 57 | context.setPrefix("dcat", "http://www.w3.org/ns/dcat#"); 58 | context.setPrefix("imreg", "http://www.w3.org/2004/02/image-regions#"); 59 | context.setPrefix("rdfg", "http://www.w3.org/2004/03/trix/rdfg-1/"); 60 | context.setPrefix("swp", "http://www.w3.org/2004/03/trix/swp-2/"); 61 | context.setPrefix("rei", "http://www.w3.org/2004/06/rei#"); 62 | context.setPrefix("wairole", "http://www.w3.org/2005/01/wai-rdf/GUIRoleTaxonomy#"); 63 | context.setPrefix("states", "http://www.w3.org/2005/07/aaa#"); 64 | context.setPrefix("wn20schema", "http://www.w3.org/2006/03/wn/wn20/schema/"); 65 | context.setPrefix("httph", "http://www.w3.org/2007/ont/httph#"); 66 | context.setPrefix("act", "http://www.w3.org/2007/rif-builtin-action#"); 67 | context.setPrefix("common", "http://www.w3.org/2007/uwa/context/common.owl#"); 68 | context.setPrefix("dcn", "http://www.w3.org/2007/uwa/context/deliverycontext.owl#"); 69 | context.setPrefix("hard", "http://www.w3.org/2007/uwa/context/hardware.owl#"); 70 | context.setPrefix("java", "http://www.w3.org/2007/uwa/context/java.owl#"); 71 | context.setPrefix("loc", "http://www.w3.org/2007/uwa/context/location.owl#"); 72 | context.setPrefix("net", "http://www.w3.org/2007/uwa/context/network.owl#"); 73 | context.setPrefix("push", "http://www.w3.org/2007/uwa/context/push.owl#"); 74 | context.setPrefix("soft", "http://www.w3.org/2007/uwa/context/software.owl#"); 75 | context.setPrefix("web", "http://www.w3.org/2007/uwa/context/web.owl#"); 76 | context.setPrefix("content", "http://www.w3.org/2008/content#"); 77 | context.setPrefix("vs", "http://www.w3.org/2003/06/sw-vocab-status/ns#"); 78 | context.setPrefix("air", "http://dig.csail.mit.edu/TAMI/2007/amord/air#"); 79 | context.setPrefix("ex", "http://example.org/"); 80 | context.setPrefix("dc", "http://purl.org/dc/terms/"); 81 | context.setPrefix("dc11", "http://purl.org/dc/elements/1.1/"); 82 | context.setPrefix("dctype", "http://purl.org/dc/dcmitype/"); 83 | context.setPrefix("foaf", "http://xmlns.com/foaf/0.1/"); 84 | context.setPrefix("cc", "http://creativecommons.org/ns#"); 85 | context.setPrefix("opensearch", "http://a9.com/-/spec/opensearch/1.1/"); 86 | context.setPrefix("void", "http://rdfs.org/ns/void#"); 87 | context.setPrefix("sioc", "http://rdfs.org/sioc/ns#"); 88 | context.setPrefix("sioca", "http://rdfs.org/sioc/actions#"); 89 | context.setPrefix("sioct", "http://rdfs.org/sioc/types#"); 90 | context.setPrefix("lgd", "http://linkedgeodata.org/vocabulary#"); 91 | context.setPrefix("moat", "http://moat-project.org/ns#"); 92 | context.setPrefix("days", "http://ontologi.es/days#"); 93 | context.setPrefix("giving", "http://ontologi.es/giving#"); 94 | context.setPrefix("lang", "http://ontologi.es/lang/core#"); 95 | context.setPrefix("like", "http://ontologi.es/like#"); 96 | context.setPrefix("status", "http://ontologi.es/status#"); 97 | context.setPrefix("og", "http://opengraphprotocol.org/schema/"); 98 | context.setPrefix("protege", "http://protege.stanford.edu/system#"); 99 | context.setPrefix("dady", "http://purl.org/NET/dady#"); 100 | context.setPrefix("uri", "http://purl.org/NET/uri#"); 101 | context.setPrefix("audio", "http://purl.org/media/audio#"); 102 | context.setPrefix("video", "http://purl.org/media/video#"); 103 | context.setPrefix("gridworks", "http://purl.org/net/opmv/types/gridworks#"); 104 | context.setPrefix("hcterms", "http://purl.org/uF/hCard/terms/"); 105 | context.setPrefix("bio", "http://purl.org/vocab/bio/0.1/"); 106 | context.setPrefix("cs", "http://purl.org/vocab/changeset/schema#"); 107 | context.setPrefix("geographis", "http://telegraphis.net/ontology/geography/geography#"); 108 | context.setPrefix("doap", "http://usefulinc.com/ns/doap#"); 109 | context.setPrefix("daml", "http://www.daml.org/2001/03/daml+oil#"); 110 | context.setPrefix("geonames", "http://www.geonames.org/ontology#"); 111 | context.setPrefix("sesame", "http://www.openrdf.org/schema/sesame#"); 112 | context.setPrefix("cv", "http://rdfs.org/resume-rdf/"); 113 | context.setPrefix("wot", "http://xmlns.com/wot/0.1/"); 114 | context.setPrefix("media", "http://purl.org/microformat/hmedia/"); 115 | context.setPrefix("ctag", "http://commontag.org/ns#"); 116 | }; 117 | -------------------------------------------------------------------------------- /lib/space.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | function xsdns(v){ return 'http://www.w3.org/2001/XMLSchema#'.concat(v); } 4 | 5 | exports.stringConverter = function stringConverter(value, inputType) { 6 | return new String(value).valueOf(); 7 | }; 8 | exports.booleanConverter = function booleanConverter(value, inputType) { 9 | switch(value){ 10 | case "false":case "0": return false; 11 | case "true":case "1": return true; 12 | } 13 | return(new Boolean(value)).valueOf(); 14 | }; 15 | exports.numberConverter = function numberConverter(value, inputType) { 16 | return(new Number(value)).valueOf(); 17 | }; 18 | exports.floatConverter = function floatConverter(value, inputType) { 19 | switch(value){ 20 | case "INF": return Number.POSITIVE_INFINITY; 21 | case "-INF": return Number.NEGATIVE_INFINITY; 22 | default: return exports.numberConverter(value, inputType); 23 | } 24 | }; 25 | exports.dateConverter = function dateConverter(value, inputType) { 26 | return new Date(value); 27 | }; 28 | 29 | exports.loadDefaultTypeConverters = function(context){ 30 | context.registerTypeConversion(xsdns("string"), exports.stringConverter); 31 | context.registerTypeConversion(xsdns("boolean"), exports.booleanConverter); 32 | context.registerTypeConversion(xsdns("float"), exports.floatConverter); 33 | context.registerTypeConversion(xsdns("integer"), exports.numberConverter); 34 | context.registerTypeConversion(xsdns("long"), exports.numberConverter); 35 | context.registerTypeConversion(xsdns("double"), exports.numberConverter); 36 | context.registerTypeConversion(xsdns("decimal"), exports.numberConverter); 37 | context.registerTypeConversion(xsdns("nonPositiveInteger"), exports.numberConverter); 38 | context.registerTypeConversion(xsdns("nonNegativeInteger"), exports.numberConverter); 39 | context.registerTypeConversion(xsdns("negativeInteger"), exports.numberConverter); 40 | context.registerTypeConversion(xsdns("int"), exports.numberConverter); 41 | context.registerTypeConversion(xsdns("unsignedLong"), exports.numberConverter); 42 | context.registerTypeConversion(xsdns("positiveInteger"), exports.numberConverter); 43 | context.registerTypeConversion(xsdns("short"), exports.numberConverter); 44 | context.registerTypeConversion(xsdns("unsignedInt"), exports.numberConverter); 45 | context.registerTypeConversion(xsdns("byte"), exports.numberConverter); 46 | context.registerTypeConversion(xsdns("unsignedShort"), exports.numberConverter); 47 | context.registerTypeConversion(xsdns("unsignedByte"), exports.numberConverter); 48 | context.registerTypeConversion(xsdns("date"), exports.dateConverter); 49 | context.registerTypeConversion(xsdns("time"), exports.dateConverter); 50 | context.registerTypeConversion(xsdns("dateTime"), exports.dateConverter); 51 | }; 52 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rdf", 3 | "description": "RDF datatype integration, RDF Interfaces API, and utility functions", 4 | "homepage": "https://github.com/awwright/node-rdf", 5 | "author": "Austin Wright", 6 | "keywords": [ 7 | "RDF", 8 | "RDF Interfaces", 9 | "IRI", 10 | "Turtle" 11 | ], 12 | "dependencies": { 13 | "iri": "~1" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "git://github.com/awwright/node-rdf.git", 18 | "web": "https://github.com/awwright/node-rdf" 19 | }, 20 | "main": "index.js", 21 | "scripts": { 22 | "test": "mocha" 23 | }, 24 | "license": "Unlicense", 25 | "devDependencies": { 26 | "mocha": "^10.0.0", 27 | "nyc": "^15.1.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/.eslintrc.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | module.exports = { 3 | "env": { 4 | "mocha": true, 5 | }, 6 | "extends": "eslint:recommended", 7 | "parserOptions": { 8 | "ecmaVersion": 5, 9 | }, 10 | "rules": { 11 | "indent": [ "error", "tab", { 12 | SwitchCase: 1, 13 | } ], 14 | "no-unreachable": [ "error" ], 15 | "linebreak-style": [ "error", "unix" ], 16 | //"semi": [ "error", "always" ], 17 | "comma-dangle": [ "error", "always-multiline" ], 18 | "no-console": [ "error" ], 19 | }, 20 | }; 21 | -------------------------------------------------------------------------------- /test/BlankNode.test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var rdf = require('..'); 3 | 4 | describe('BlankNode', function(){ 5 | it("instance", function(){ 6 | var t = new rdf.BlankNode(); 7 | assert.ok(t instanceof rdf.BlankNode); 8 | assert.strictEqual(t.nodeType(), 'BlankNode'); 9 | assert.strictEqual(t.interfaceName, 'BlankNode'); // 2012 Note variant 10 | assert.strictEqual(t.termType, 'BlankNode'); // 2017 Community Group variant 11 | assert.strictEqual(t.toNT(), t.n3()); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /test/BlankNodeMap.test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var rdf = require('..'); 3 | 4 | function BlankNodeMapTests(){ 5 | it("instance", function(){ 6 | var bn = rdf.BlankNodeMap(); 7 | assert(bn instanceof rdf.BlankNodeMap); 8 | }); 9 | } 10 | 11 | describe('BlankNodeMap', BlankNodeMapTests); 12 | 13 | describe('BlankNodeMap (with builtins)', function(){ 14 | before(function(){ 15 | rdf.setBuiltins(); 16 | }); 17 | after(function(){ 18 | rdf.unsetBuiltins(); 19 | }); 20 | BlankNodeMapTests(); 21 | }); 22 | -------------------------------------------------------------------------------- /test/DataFactory.test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var rdf = require('..'); 3 | var factory = rdf.factory; 4 | 5 | /* 6 | // Presumably these are implemented by the same object, even though the WebIDL doesn't seem to indicate as such 7 | 8 | interface DataFactory { 9 | NamedNode namedNode(string value); 10 | BlankNode blankNode(optional string value); 11 | Literal literal(string value, optional (string or NamedNode) languageOrDatatype); 12 | Variable variable(string value); 13 | DefaultGraph defaultGraph(); 14 | Quad quad(Term subject, Term predicate, Term object, optional Term? graph); 15 | Term fromTerm(Term original); 16 | Quad fromQuad(Quad original); 17 | }; 18 | interface DatasetCoreFactory { 19 | DatasetCore dataset (optional sequence quads); 20 | }; 21 | */ 22 | 23 | function DataFactoryTests(){ 24 | it("default instance", function(){ 25 | assert(rdf.factory instanceof rdf.DataFactory); 26 | }); 27 | it("namedNode", function(){ 28 | assert(factory.namedNode("http://example.com/") instanceof rdf.NamedNode); 29 | assert(factory.namedNode("http://example.com/").equals(new rdf.NamedNode('http://example.com/'))); 30 | assert(!factory.namedNode("http://example.com/").equals(new rdf.NamedNode('http://foo.example.net/'))); 31 | }); 32 | it("blankNode", function(){ 33 | assert(factory.blankNode() instanceof rdf.BlankNode); 34 | assert(factory.blankNode("foo") instanceof rdf.BlankNode); 35 | }); 36 | it("literal", function(){ 37 | assert(factory.literal("foo bar") instanceof rdf.Literal); 38 | assert(factory.literal("foo bar").equals(new rdf.Literal('foo bar'))); 39 | assert(!factory.literal("foo bar").equals(new rdf.Literal('foo bar', '@en'))); 40 | }); 41 | it("variable", function(){ 42 | assert(factory.variable("n") instanceof rdf.Variable); 43 | assert(factory.variable("n").equals(new rdf.Variable('n'))); 44 | assert(!factory.variable("n").equals(new rdf.Variable('q'))); 45 | }); 46 | it("defaultGraph", function(){ 47 | assert(factory.defaultGraph() instanceof rdf.DefaultGraph); 48 | assert(factory.defaultGraph()===factory.defaultGraph()); 49 | }); 50 | it("triple", function(){ 51 | assert(factory.triple(factory.namedNode("http://example.com/"), factory.namedNode("http://example.com/"), factory.namedNode("http://example.com/")) instanceof rdf.Triple); 52 | assert(factory.triple(factory.namedNode("http://example.com/"), factory.namedNode("http://example.com/"), factory.namedNode("http://example.com/")).equals(new rdf.Triple(new rdf.NamedNode("http://example.com/"), new rdf.NamedNode("http://example.com/"), new rdf.NamedNode("http://example.com/"), new rdf.NamedNode("http://example.com/")))); 53 | }); 54 | it("quad", function(){ 55 | assert(factory.quad(factory.namedNode("http://example.com/"), factory.namedNode("http://example.com/"), factory.namedNode("http://example.com/")) instanceof rdf.Quad); 56 | assert(factory.quad(factory.namedNode("http://example.com/"), factory.namedNode("http://example.com/"), factory.namedNode("http://example.com/")).equals(new rdf.Quad(new rdf.NamedNode("http://example.com/"), new rdf.NamedNode("http://example.com/"), new rdf.NamedNode("http://example.com/"), new rdf.DefaultGraph))); 57 | }); 58 | it("dataset", function(){ 59 | assert(factory.dataset() instanceof rdf.Dataset); 60 | }); 61 | describe("fromTerm", function(){ 62 | it("fromTerm(NamedNode)", function(){ 63 | var term = factory.fromTerm({termType:'NamedNode', value:'http://example.com/'}); 64 | assert(term instanceof rdf.NamedNode); 65 | assert(term.equals(new rdf.NamedNode('http://example.com/'))); 66 | assert(!term.equals(new rdf.NamedNode('http://foo.example.net/'))); 67 | }); 68 | it("fromTerm(BlankNode)", function(){ 69 | var term = factory.fromTerm({termType:'BlankNode', value:'b1'}); 70 | assert(term instanceof rdf.BlankNode); 71 | }); 72 | it("fromTerm(xsd:string)", function(){ 73 | var term = factory.fromTerm({termType:'Literal', value:'foo', datatype:{termType:"NamedNode", value:rdf.xsdns("string")}}); 74 | assert(term instanceof rdf.Literal); 75 | assert(term.equals(new rdf.Literal('foo', rdf.xsdns("string")))); 76 | assert(term.equals(new rdf.Literal('foo'))); 77 | assert(!term.equals(new rdf.Literal('foo', '@en'))); 78 | }); 79 | it("fromTerm(xsd:boolean)", function(){ 80 | var term = factory.fromTerm({termType:'Literal', value:'foo', datatype:{termType:"NamedNode", value:rdf.xsdns("boolean")}}); 81 | assert(term instanceof rdf.Literal); 82 | assert(term.equals(new rdf.Literal('foo', rdf.xsdns("boolean")))); 83 | assert(!term.equals(new rdf.Literal('foo'))); 84 | }); 85 | it("fromTerm(rdf:langString)", function(){ 86 | var term = factory.fromTerm({termType:'Literal', value:'foo', datatype:{termType:"NamedNode", value:rdf.rdfns("langString")}, language:"en"}); 87 | assert(term instanceof rdf.Literal); 88 | assert(term.equals(new rdf.Literal('foo', '@en'))); 89 | assert(!term.equals(new rdf.Literal('foo'))); 90 | }); 91 | it("fromTerm(Variable)", function(){ 92 | var term = factory.fromTerm({termType:'Variable', value:'name'}); 93 | assert(term instanceof rdf.Variable); 94 | assert(term.equals(new rdf.Variable('name'))); 95 | assert(!term.equals(new rdf.Variable('baz'))); 96 | }); 97 | it("fromTerm(DefaultGraph)", function(){ 98 | var term = factory.fromTerm({termType:'DefaultGraph', value:''}); 99 | assert(term instanceof rdf.DefaultGraph); 100 | assert(term.equals(factory.defaultGraph())); 101 | assert(!term.equals(factory.namedNode('http://example.com/'))); 102 | }); 103 | }); 104 | it("fromTriple", function(){ 105 | var quad = factory.fromTriple({ 106 | subject: {termType:"NamedNode", value:"http://example.com/"}, 107 | predicate: {termType:"NamedNode", value:"http://example.com/"}, 108 | object: {termType:"NamedNode", value:"http://example.com/"}, 109 | }); 110 | assert(quad instanceof rdf.Triple); 111 | assert(quad.equals(new rdf.Triple('http://example.com/', 'http://example.com/', 'http://example.com/'))); 112 | assert(!quad.equals(new rdf.Triple('http://example.com/', 'http://example.com/', 'http://foo.example.net/'))); 113 | }); 114 | it("fromQuad", function(){ 115 | var quad = factory.fromQuad({ 116 | subject: {termType:"NamedNode", value:"http://example.com/"}, 117 | predicate: {termType:"NamedNode", value:"http://example.com/"}, 118 | object: {termType:"NamedNode", value:"http://example.com/"}, 119 | graph: {termType:"DefaultGraph"}, 120 | }); 121 | assert(quad instanceof rdf.Quad); 122 | assert(quad.equals(new rdf.Quad('http://example.com/', 'http://example.com/', 'http://example.com/', factory.defaultGraph()))); 123 | assert(!quad.equals(new rdf.Quad('http://example.com/', 'http://example.com/', 'http://foo.example.net/', factory.defaultGraph()))); 124 | }); 125 | } 126 | 127 | describe('factory', DataFactoryTests); 128 | 129 | describe('factory (with builtins)', function(){ 130 | before(function(){ 131 | rdf.setBuiltins(); 132 | }); 133 | after(function(){ 134 | rdf.unsetBuiltins(); 135 | }); 136 | DataFactoryTests(); 137 | }); 138 | -------------------------------------------------------------------------------- /test/DefaultGraph.test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var rdf = require('..'); 3 | 4 | function DefaultGraphTests(){ 5 | it("RDF Representation", function(){ 6 | /* 7 | interface DefaultGraph : Term { 8 | attribute string termType; 9 | attribute string value; 10 | boolean equals(Term other); 11 | }; 12 | */ 13 | var t = rdf.factory.defaultGraph(); 14 | assert(t instanceof rdf.Term); 15 | assert.strictEqual(t.termType, 'DefaultGraph'); 16 | assert.strictEqual(t.value, ''); 17 | }); 18 | it("DefaultGraph#toNT", function(){ 19 | var t = rdf.factory.defaultGraph(); 20 | assert.throws(function(){ t.toNT(); }); 21 | }); 22 | it("DefaultGraph#toTurtle", function(){ 23 | var t = rdf.factory.defaultGraph(); 24 | assert.throws(function(){ t.toTurtle(); }); 25 | }); 26 | it("DefaultGraph#toString", function(){ 27 | var t = rdf.factory.defaultGraph(); 28 | assert.strictEqual(t.toString(), ''); 29 | }); 30 | it("DefaultGraph#equals", function(){ 31 | var t1 = rdf.factory.defaultGraph(); 32 | var t2 = rdf.factory.defaultGraph(); 33 | assert(t1.equals(t2)); 34 | }); 35 | } 36 | 37 | describe('DefaultGraph', DefaultGraphTests); 38 | 39 | describe('DefaultGraph (with builtins)', function(){ 40 | before(function(){ 41 | rdf.setBuiltins(); 42 | }); 43 | after(function(){ 44 | rdf.unsetBuiltins(); 45 | }); 46 | DefaultGraphTests(); 47 | }); 48 | -------------------------------------------------------------------------------- /test/Literal.test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var rdf = require('..'); 3 | 4 | function LiteralTests(){ 5 | it("js3", function(){ 6 | var t = new rdf.Literal("A String"); 7 | assert.strictEqual(t.nodeType(), 'PlainLiteral'); 8 | assert.strictEqual(t.type, null); 9 | assert.strictEqual(t.language, null); 10 | assert.strictEqual(t.toNT(), '"A String"'); 11 | assert.strictEqual(t.toTurtle(), '"A String"'); 12 | assert.strictEqual(t.n3(), '"A String"'); 13 | }); 14 | it("RDF Interfaces", function(){ 15 | /* 16 | [NoInterfaceObject] 17 | interface Literal : RDFNode { 18 | readonly attribute DOMString nominalValue; 19 | readonly attribute DOMString? language; 20 | readonly attribute NamedNode? datatype; 21 | any valueOf (); 22 | }; 23 | [NoInterfaceObject] 24 | interface RDFNode { 25 | readonly attribute any nominalValue; 26 | readonly attribute DOMString interfaceName; 27 | DOMString toString (); 28 | any valueOf (); 29 | DOMString toNT (); 30 | boolean equals (any tocompare); 31 | }; 32 | */ 33 | var t = new rdf.Literal("A String"); 34 | assert(t instanceof rdf.RDFNode); 35 | assert.strictEqual(t.nominalValue, "A String"); 36 | assert.strictEqual(t.datatype.nominalValue, "http://www.w3.org/2001/XMLSchema#string"); 37 | assert.strictEqual(t.language, null); 38 | assert.strictEqual(t.toNT(), '"A String"'); 39 | assert(t.equals(new rdf.Literal("A String"))); 40 | }); 41 | it("RDF Representation", function(){ 42 | /* 43 | interface Literal : Term { 44 | attribute string termType; 45 | attribute string value; 46 | attribute string language; 47 | attribute NamedNode datatype; 48 | boolean equals(Term other); 49 | }; 50 | interface Term { 51 | attribute string termType; 52 | attribute string value; 53 | boolean equals(Term other); 54 | }; 55 | */ 56 | var t = new rdf.Literal("A String"); 57 | assert(t instanceof rdf.Term); 58 | assert.strictEqual(t.termType, 'Literal'); 59 | assert.strictEqual(t.value, 'A String'); 60 | assert.strictEqual(t.datatype.value, 'http://www.w3.org/2001/XMLSchema#string'); 61 | }); 62 | it("Language instance @en", function(){ 63 | var t = new rdf.Literal('That Seventies Show', '@en'); 64 | assert.strictEqual(t.nodeType(), 'PlainLiteral'); 65 | assert.strictEqual(t.termType, 'Literal'); 66 | assert.strictEqual(t.datatype.value, 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString'); 67 | assert.strictEqual(t.language, 'en'); 68 | assert.strictEqual(t.toNT(), '"That Seventies Show"@en'); 69 | assert.strictEqual(t.toTurtle(), '"That Seventies Show"@en'); 70 | assert.strictEqual(t.toTurtle(), '"That Seventies Show"@en'); 71 | // Equality tests 72 | assert.ok(t.equals(new rdf.Literal('That Seventies Show', '@en'))); 73 | //assert.ok(t.equals('That Seventies Show')); 74 | assert.ok(!t.equals(new rdf.Literal('String', '@en'))); 75 | assert.ok(!t.equals(new rdf.Literal('That Seventies Show', '@fr-be'))); 76 | //assert.ok(!t.equals('Cette Série des Années Septante')); 77 | }); 78 | it("Language instance @fr-be", function(){ 79 | var t = new rdf.Literal('Cette Série des Années Septante', 'fr-be'); 80 | assert.strictEqual(t.nodeType(), 'PlainLiteral'); 81 | assert.strictEqual(t.termType, 'Literal'); 82 | assert.strictEqual(t.datatype.toString(), 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString'); 83 | assert.strictEqual(t.language, 'fr-be'); 84 | assert.strictEqual(t.toNT(), '"Cette S\\u00E9rie des Ann\\u00E9es Septante"@fr-be'); 85 | assert.strictEqual(t.toTurtle(), '"Cette S\\u00E9rie des Ann\\u00E9es Septante"@fr-be'); 86 | // Equality tests 87 | assert.ok(t.equals(new rdf.Literal('Cette Série des Années Septante', '@fr-be'))); 88 | assert.ok(!t.equals(new rdf.Literal('Cette Serie des Annees Septante', '@fr-be'))); 89 | assert.ok(!t.equals(new rdf.Literal('Cette Série des Années Septante', '@en'))); 90 | assert.ok(!t.equals('Cette Série des Années Septante')); 91 | assert.ok(!t.equals('That Seventies Show')); 92 | }); 93 | it("Typed instance (string)", function(){ 94 | var t = new rdf.Literal('123', 'http://www.w3.org/2001/XMLSchema#integer'); 95 | assert.strictEqual(t.nodeType(), 'TypedLiteral'); 96 | assert.strictEqual(t.termType, 'Literal'); 97 | assert.equal(t.datatype.toString(), 'http://www.w3.org/2001/XMLSchema#integer'); 98 | assert.strictEqual(t.language, null); 99 | assert.strictEqual(t.toNT(), '"123"^^'); 100 | assert.strictEqual(t.toTurtle(), '123'); 101 | // Equality tests 102 | assert.ok(t.equals(new rdf.Literal('123', 'http://www.w3.org/2001/XMLSchema#integer'))); 103 | assert.ok(!t.equals('123')); 104 | assert.ok(!t.equals(new rdf.Literal('1', 'http://www.w3.org/2001/XMLSchema#integer'))); 105 | assert.ok(!t.equals(new rdf.Literal('123', 'http://www.w3.org/2001/XMLSchema#decimal'))); 106 | assert.ok(!t.equals('1')); 107 | }); 108 | it("Typed instance (NamedNode)", function(){ 109 | var t = new rdf.Literal('123', new rdf.NamedNode('http://www.w3.org/2001/XMLSchema#integer')); 110 | assert.ok(t instanceof rdf.Literal); 111 | assert.strictEqual(t.nodeType(), 'TypedLiteral'); 112 | assert.strictEqual(t.termType, 'Literal'); 113 | assert.equal(t.datatype.toString(), 'http://www.w3.org/2001/XMLSchema#integer'); 114 | assert.strictEqual(t.language, null); 115 | assert.strictEqual(t.toNT(), '"123"^^'); 116 | assert.strictEqual(t.toTurtle(), '123'); 117 | assert.ok(t.equals(new rdf.Literal('123', 'http://www.w3.org/2001/XMLSchema#integer'))); 118 | assert.ok(!t.equals('123')); 119 | assert.ok(!t.equals(new rdf.Literal('1', 'http://www.w3.org/2001/XMLSchema#integer'))); 120 | assert.ok(!t.equals(new rdf.Literal('123', 'http://www.w3.org/2001/XMLSchema#decimal'))); 121 | assert.ok(!t.equals('1')); 122 | }); 123 | it("Typed instance (string) (xsd:string)", function(){ 124 | var t = new rdf.Literal('123', 'http://www.w3.org/2001/XMLSchema#string'); 125 | assert.ok(t instanceof rdf.Literal); 126 | // This datatype causes this exeption 127 | assert.strictEqual(t.nodeType(), 'PlainLiteral'); 128 | assert.strictEqual(t.termType, 'Literal'); 129 | assert.equal(t.datatype.toString(), 'http://www.w3.org/2001/XMLSchema#string'); 130 | assert.strictEqual(t.language, null); 131 | assert.strictEqual(t.toNT(), '"123"'); 132 | //assert.strictEqual(t.toTurtle(), '123'); 133 | assert.ok(t.equals(new rdf.Literal('123', 'http://www.w3.org/2001/XMLSchema#string'))); 134 | assert.ok(t.equals(new rdf.Literal('123'))); 135 | assert.ok(!t.equals('123')); 136 | assert.ok(!t.equals(new rdf.Literal('1', 'http://www.w3.org/2001/XMLSchema#integer'))); 137 | assert.ok(!t.equals(new rdf.Literal('123', 'http://www.w3.org/2001/XMLSchema#decimal'))); 138 | assert.ok(!t.equals('1')); 139 | }); 140 | it("Language string (rdf:langString)", function(){ 141 | var t = new rdf.Literal('123', '@en', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString'); 142 | assert.ok(t instanceof rdf.Literal); 143 | // Leave this behavior undefined for now, consider this deprecated anyways 144 | //assert.strictEqual(t.nodeType(), 'TypedLiteral'); 145 | assert.strictEqual(t.termType, 'Literal'); 146 | assert.equal(t.datatype.toString(), 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString'); 147 | assert.strictEqual(t.language, 'en'); 148 | assert.strictEqual(t.toNT(), '"123"@en'); 149 | assert.strictEqual(t.toTurtle(), '"123"@en'); 150 | assert.ok(t.equals(new rdf.Literal('123', '@en'))); 151 | assert.ok(!t.equals('123')); 152 | assert.ok(!t.equals(new rdf.Literal('123'))); 153 | assert.ok(!t.equals(new rdf.Literal('123', 'http://www.w3.org/2001/XMLSchema#string'))); 154 | assert.ok(!t.equals('1')); 155 | }); 156 | it("Typed instance (NamedNode) (xsd:string)", function(){ 157 | var t = new rdf.Literal('123', new rdf.NamedNode('http://www.w3.org/2001/XMLSchema#string')); 158 | assert.ok(t instanceof rdf.Literal); 159 | //assert.strictEqual(t.nodeType(), 'TypedLiteral'); 160 | assert.strictEqual(t.termType, 'Literal'); 161 | assert.equal(t.datatype.toString(), 'http://www.w3.org/2001/XMLSchema#string'); 162 | assert.strictEqual(t.language, null); 163 | assert.strictEqual(t.toNT(), '"123"'); 164 | assert.strictEqual(t.toTurtle(), '"123"'); 165 | assert.ok(t.equals(new rdf.Literal('123', 'http://www.w3.org/2001/XMLSchema#string'))); 166 | assert.ok(t.equals(new rdf.Literal('123'))); 167 | assert.ok(!t.equals('123')); 168 | assert.ok(!t.equals(new rdf.Literal('1', 'http://www.w3.org/2001/XMLSchema#integer'))); 169 | assert.ok(!t.equals(new rdf.Literal('123', 'http://www.w3.org/2001/XMLSchema#decimal'))); 170 | }); 171 | describe("toTurtle", function(){ 172 | it("TypedLiteral xsd:integer", function(){ 173 | var t = new rdf.Literal('123', new rdf.NamedNode('http://www.w3.org/2001/XMLSchema#integer')); 174 | assert.strictEqual(t.toNT(), '"123"^^'); 175 | assert.strictEqual(t.toTurtle(), '123'); 176 | }); 177 | it("TypedLiteral invalid xsd:integer", function(){ 178 | var t = new rdf.Literal('something', new rdf.NamedNode('http://www.w3.org/2001/XMLSchema#integer')); 179 | assert.strictEqual(t.toNT(), '"something"^^'); 180 | assert.strictEqual(t.toTurtle(), '"something"^^'); 181 | }); 182 | it("TypedLiteral xsd:string", function(){ 183 | var t = new rdf.Literal('a string', new rdf.NamedNode('http://www.w3.org/2001/XMLSchema#string')); 184 | assert.strictEqual(t.toNT(), '"a string"'); // NT strips xsd:string as a historical relic 185 | assert.strictEqual(t.toTurtle(), '"a string"'); 186 | }); 187 | it("TypedLiteral xsd:decimal", function(){ 188 | var t = new rdf.Literal('123.0', new rdf.NamedNode('http://www.w3.org/2001/XMLSchema#decimal')); 189 | assert.strictEqual(t.toNT(), '"123.0"^^'); 190 | assert.strictEqual(t.toTurtle(), '123.0'); 191 | }); 192 | it("TypedLiteral xsd:double", function(){ 193 | var t = new rdf.Literal('4.2E9', new rdf.NamedNode('http://www.w3.org/2001/XMLSchema#double')); 194 | assert.strictEqual(t.toNT(), '"4.2E9"^^'); 195 | assert.strictEqual(t.toTurtle(), '4.2E9'); 196 | }); 197 | it("TypedLiteral xsd:boolean", function(){ 198 | var t = new rdf.Literal('true', new rdf.NamedNode('http://www.w3.org/2001/XMLSchema#boolean')); 199 | assert.strictEqual(t.toNT(), '"true"^^'); 200 | assert.strictEqual(t.toTurtle(), 'true'); 201 | }); 202 | it("TypedLiteral xsd:boolean (number)", function(){ 203 | var t = new rdf.Literal('1', new rdf.NamedNode('http://www.w3.org/2001/XMLSchema#boolean')); 204 | assert.strictEqual(t.toNT(), '"1"^^'); 205 | assert.strictEqual(t.toTurtle(), '"1"^^'); 206 | }); 207 | }); 208 | describe("valueOf", function(){ 209 | testValueOf("A STRING", 'string', "A STRING"); 210 | testValueOf("true", "boolean", true); 211 | testValueOf("1", "boolean", true); 212 | testValueOf("false", "boolean", false); 213 | testValueOf("0", "boolean", false); 214 | testValueOf("0.5", "float", 0.5); 215 | testValueOf("INF", "float", Number.POSITIVE_INFINITY); 216 | testValueOf("-INF", "float", Number.NEGATIVE_INFINITY); 217 | testValueOf("NaN", "float", 0/0); 218 | testValueOf("-14000", "integer", -14000); 219 | testValueOf("-9223372036854775808", "long", -9223372036854775808); 220 | testValueOf("9223372036854775807", "long", 9223372036854775807); 221 | testValueOf("1.578125", "float", 1.578125); 222 | testValueOf("-1.2344e56", "float", -1.2344e56); 223 | testValueOf("-42", "nonPositiveInteger", -42); 224 | testValueOf("0", "nonPositiveInteger", 0); 225 | testValueOf("42", "nonNegativeInteger", 42); 226 | testValueOf("0", "nonNegativeInteger", 0); 227 | testValueOf("-42", "negativeInteger", -42); 228 | testValueOf("-2147483648", "long", -2147483648); 229 | testValueOf("2147483647", "long", 2147483647); 230 | testValueOf("2000-01-01", "date", new Date('Sat, 01 Jan 2000 00:00:00 GMT')); 231 | //testValueOf("21:32:52", "time", new Date('Sat, 01 Jan 2000 00:00:00 GMT')); // There's no good way to represent just time-of-day... Ignore this guy? 232 | testValueOf("2001-10-26T21:32:52.12679", "dateTime", new Date('2001-10-26T21:32:52.12679')); 233 | // TODO probbly should verify the inputs are of the correct range? 234 | }); 235 | } 236 | 237 | describe('Literal', LiteralTests); 238 | 239 | describe('Literal (with builtins)', function(){ 240 | before(function(){ 241 | rdf.setBuiltins(); 242 | }); 243 | after(function(){ 244 | rdf.unsetBuiltins(); 245 | }); 246 | LiteralTests(); 247 | }); 248 | 249 | function testValueOf(literal, type, test){ 250 | // Literal must be a string 251 | it('Literal('+JSON.stringify(literal)+', xsd:'+type+').valueOf()', function(){ 252 | var value = new rdf.Literal(literal, rdf.xsdns(type)).valueOf(); 253 | if(type=='date' || type=='dateTime'){ 254 | assert.ok(value instanceof Date); 255 | assert.strictEqual(value.getTime(), test.getTime()); 256 | }else if(Number.isNaN(test)){ 257 | assert.ok(Number.isNaN(value)); 258 | }else{ 259 | assert.strictEqual(value, test); 260 | } 261 | }); 262 | } 263 | -------------------------------------------------------------------------------- /test/NamedNode.test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var rdf = require('..'); 3 | 4 | function NamedNodeTests(){ 5 | it("js3", function(){ 6 | var t = new rdf.NamedNode('http://example.com/'); 7 | assert.strictEqual(t.nodeType(), 'IRI'); 8 | assert.strictEqual(t.toNT(), ''); 9 | assert.strictEqual(t.toTurtle(), ''); 10 | assert.strictEqual(t.n3(), ''); 11 | }); 12 | it("RDF Interfaces", function(){ 13 | /* 14 | [NoInterfaceObject] 15 | interface NamedNode : RDFNode { 16 | readonly attribute any nominalValue; 17 | }; 18 | [NoInterfaceObject] 19 | interface RDFNode { 20 | readonly attribute any nominalValue; 21 | readonly attribute DOMString interfaceName; 22 | DOMString toString (); 23 | any valueOf (); 24 | DOMString toNT (); 25 | boolean equals (any tocompare); 26 | }; 27 | */ 28 | var t = new rdf.NamedNode('http://example.com/'); 29 | assert.strictEqual(t.nominalValue, 'http://example.com/'); 30 | assert(t instanceof rdf.RDFNode); 31 | assert.strictEqual(t.interfaceName, 'NamedNode'); 32 | assert.strictEqual(t.toString(), 'http://example.com/'); 33 | assert.strictEqual(t.valueOf(), 'http://example.com/'); 34 | assert.strictEqual(t.toNT(), ''); 35 | assert(t.equals('http://example.com/')); 36 | assert(t.equals(new rdf.NamedNode('http://example.com/'))); 37 | }); 38 | it("RDF Representation", function(){ 39 | /* 40 | interface NamedNode : Term { 41 | attribute string termType; 42 | attribute string value; 43 | boolean equals(Term other); 44 | }; 45 | interface Term { 46 | attribute string termType; 47 | attribute string value; 48 | boolean equals(Term other); 49 | }; 50 | */ 51 | var t = new rdf.NamedNode('http://example.com/'); 52 | assert(t instanceof rdf.Term); 53 | assert.strictEqual(t.termType, 'NamedNode'); // 2017 Community Group variant 54 | assert.strictEqual(t.value, 'http://example.com/'); // 2017 CG variant 55 | assert(t.equals(new rdf.NamedNode('http://example.com/'))); 56 | }); 57 | it("valueOf", function(){ 58 | var t = new rdf.NamedNode('http://example.com/'); 59 | assert.strictEqual(t.toString(), 'http://example.com/'); 60 | }); 61 | it("toNT", function(){ 62 | var t = new rdf.NamedNode('http://example.com/'); 63 | assert.strictEqual(t.toNT(), ''); 64 | }); 65 | it("toTurtle", function(){ 66 | var t = new rdf.NamedNode('http://example.com/'); 67 | assert.strictEqual(t.toTurtle(), ''); 68 | }); 69 | it("n3", function(){ 70 | var t = new rdf.NamedNode('http://example.com/'); 71 | assert.strictEqual(t.n3(), ''); 72 | }); 73 | it("equals", function(){ 74 | var t = new rdf.NamedNode('http://example.com/'); 75 | assert.ok(t.equals(new rdf.NamedNode('http://example.com/'))); 76 | assert.ok(!t.equals(new rdf.NamedNode('http://example.com'))); 77 | assert.ok(t.equals('http://example.com/')); 78 | assert.ok(!t.equals('http://example.com')); 79 | }); 80 | } 81 | 82 | describe('NamedNode', NamedNodeTests); 83 | 84 | describe('NamedNode (with builtins)', function(){ 85 | before(function(){ 86 | rdf.setBuiltins(); 87 | }); 88 | after(function(){ 89 | rdf.unsetBuiltins(); 90 | }); 91 | NamedNodeTests(); 92 | }); 93 | -------------------------------------------------------------------------------- /test/PrefixMap.test.js: -------------------------------------------------------------------------------- 1 | 2 | var assert = require('assert'); 3 | var rdf = require('..'); 4 | 5 | /* 6 | [NoInterfaceObject] 7 | interface PrefixMap { 8 | omittable getter DOMString get (DOMString prefix); 9 | omittable setter void set (DOMString prefix, DOMString iri); 10 | omittable deleter void remove (DOMString prefix); 11 | DOMString resolve (DOMString curie); 12 | DOMString shrink (DOMString iri); 13 | void setDefault (DOMString iri); 14 | PrefixMap addAll (PrefixMap prefixes, optional boolean override); 15 | }; 16 | */ 17 | 18 | describe('PrefixMap', function(){ 19 | it('PrefixMap#get(string, string)', function(){ 20 | var map = new rdf.PrefixMap; 21 | assert.equal(typeof map.get, 'function'); 22 | }); 23 | it('PrefixMap#set(string, string)', function(){ 24 | var map = new rdf.PrefixMap; 25 | assert.equal(typeof map.set, 'function'); 26 | assert.equal(typeof map.set('ex', 'http://example.com/'), 'undefined'); 27 | assert.equal(map.resolve('ex:type'), 'http://example.com/type'); 28 | }); 29 | it('PrefixMap#setDefault(string)', function(){ 30 | var map = new rdf.PrefixMap; 31 | assert.equal(typeof map.set, 'function'); 32 | assert.equal(typeof map.setDefault('http://example.com/'), 'undefined'); 33 | assert.equal(map.resolve(':type'), 'http://example.com/type'); 34 | }); 35 | it("PrefixMap#set negative tests", function(){ 36 | var map = new rdf.PrefixMap; 37 | assert.equal(typeof map.set, 'function'); 38 | assert.throws(function(){ 39 | map.set('0', 'http://example.com/'); 40 | }); 41 | assert.throws(function(){ 42 | map.set('::', 'http://example.com/'); 43 | }); 44 | assert.throws(function(){ 45 | map.set(' ', 'http://example.com/'); 46 | }); 47 | assert.throws(function(){ 48 | map.set('.', 'http://example.com/'); 49 | }); 50 | }); 51 | it("PrefixMap#remove(string)", function(){ 52 | var map = new rdf.PrefixMap; 53 | map.set('prefix', 'http://example.com/vocab/foo/'); 54 | map.remove('prefix'); 55 | assert.strictEqual(map.resolve('prefix:foo'), null); 56 | }); 57 | it("PrefixMap#resolve(string)", function(){ 58 | var map = new rdf.PrefixMap; 59 | map.set('ex', 'http://example.com/'); 60 | assert.equal(typeof map.resolve, 'function'); 61 | assert.equal(typeof map.resolve('ex:type'), 'string'); 62 | assert.equal(map.resolve('undefinedTerm'), null); 63 | }); 64 | it("PrefixMap#shrink(string)", function(){ 65 | var map = new rdf.PrefixMap; 66 | map.set('ex2', 'http://example.com/vocab/foo/'); 67 | map.set('ex', 'http://example.com/'); 68 | map.set('exv', 'http://example.com/vocab/'); 69 | map.set('🐉', 'http://example.com/vocab/dragon/'); 70 | 71 | assert.equal(map.shrink('http://example.com/vocab/a'), 'exv:a'); 72 | assert.equal(map.shrink('http://example.com/vocab/foo/b'), 'ex2:b'); 73 | assert.equal(map.shrink('http://example.com/c'), 'ex:c'); 74 | // File is UTF-8 (probably), but escape sequence UTF-16 surrogate pairs 75 | // idk I didn't invent it, man 76 | assert.equal(map.shrink('http://example.com/vocab/dragon/🐲'), '\uD83D\uDC09:\uD83D\uDC32'); 77 | assert.equal(map.shrink('http://example.com/vocab/dragon/🐲🐧'), '\uD83D\uDC09:\uD83D\uDC32\uD83D\uDC27'); 78 | }); 79 | it("PrefixMap#addAll", function(){ 80 | var map = new rdf.PrefixMap; 81 | assert.equal(typeof map.addAll, 'function'); 82 | map.set('ex', 'http://example.com/'); 83 | 84 | var other = new rdf.PrefixMap; 85 | other.set('ex', 'http://example.org/vocab/'); 86 | other.set('fx', 'http://example.org/vocab/'); 87 | 88 | map.addAll(other); 89 | assert.equal(map.resolve('ex:a'), 'http://example.com/a'); 90 | assert.equal(map.resolve('fx:a'), 'http://example.org/vocab/a'); 91 | assert.strictEqual(map.resolve('c:foo'), null); 92 | }); 93 | it("PrefixMap#addAll (overwrite=false)", function(){ 94 | var map = new rdf.PrefixMap; 95 | map.set('ex', 'http://example.com/'); 96 | 97 | var other = new rdf.PrefixMap; 98 | other.set('ex', 'http://example.org/vocab/'); 99 | other.set('fx', 'http://example.org/vocab/'); 100 | 101 | map.addAll(other, false); 102 | assert.equal(map.resolve('ex:a'), 'http://example.com/a'); 103 | assert.equal(map.resolve('fx:a'), 'http://example.org/vocab/a'); 104 | assert.strictEqual(map.resolve('c:foo'), null); 105 | }); 106 | it("PrefixMap#addAll (overwrite=true)", function(){ 107 | var map = new rdf.PrefixMap; 108 | map.set('ex', 'http://example.com/'); 109 | 110 | var other = new rdf.PrefixMap; 111 | other.set('ex', 'http://example.org/vocab/'); 112 | other.set('fx', 'http://example.org/vocab/'); 113 | 114 | map.addAll(other, true); 115 | assert.equal(map.resolve('ex:a'), 'http://example.org/vocab/a'); 116 | assert.equal(map.resolve('fx:a'), 'http://example.org/vocab/a'); 117 | assert.strictEqual(map.resolve('c:foo'), null); 118 | }); 119 | it("PrefixMap#list", function(){ 120 | var map = new rdf.PrefixMap; 121 | assert.equal(map.list().length, 0); 122 | map.set('ex', 'http://example.com/'); 123 | var list = map.list(); 124 | assert.equal(list.length, 1); 125 | assert.equal(list[0], 'ex'); 126 | }); 127 | }); 128 | -------------------------------------------------------------------------------- /test/Profile.test.js: -------------------------------------------------------------------------------- 1 | 2 | var assert = require('assert'); 3 | var rdf = require('..'); 4 | 5 | /* 6 | [NoInterfaceObject] 7 | interface Profile { 8 | readonly attribute PrefixMap prefixes; 9 | readonly attribute TermMap terms; 10 | DOMString resolve (DOMString toresolve); 11 | void setDefaultVocabulary (DOMString iri); 12 | void setDefaultPrefix (DOMString iri); 13 | void setTerm (DOMString term, DOMString iri); 14 | void setPrefix (DOMString prefix, DOMString iri); 15 | Profile importProfile (Profile profile, optional boolean override); 16 | }; 17 | */ 18 | 19 | describe('Profile', function(){ 20 | it("prefixes", function(){ 21 | var profile = new rdf.Profile; 22 | assert.equal(typeof profile.prefixes, 'object'); 23 | }); 24 | it("terms", function(){ 25 | var profile = new rdf.Profile; 26 | assert.equal(typeof profile.terms, 'object'); 27 | }); 28 | it('builtin prefixes', function(){ 29 | var env = new rdf.RDFEnvironment; 30 | assert.strictEqual(env.resolve("rdf:type"), "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"); 31 | assert.strictEqual(env.resolve("rdfs:Class"), "http://www.w3.org/2000/01/rdf-schema#Class"); 32 | assert.strictEqual(env.resolve("unknownprefix2:foo"), null); 33 | }); 34 | it('define prefix', function(){ 35 | var env = new rdf.RDFEnvironment; 36 | assert.strictEqual(env.resolve("unkfoo:foo"), null); 37 | env.setPrefix("unkfoo", "http://example.com/1/ex/42/"); 38 | assert.strictEqual(env.resolve("unkfoo:foo"), "http://example.com/1/ex/42/foo"); 39 | }); 40 | it('define default prefix', function(){ 41 | var env = new rdf.RDFEnvironment; 42 | assert.strictEqual(env.resolve(":bar"), null); 43 | env.setDefaultPrefix("http://example.com/2/ex/42/"); 44 | assert.strictEqual(env.resolve(":answer"), "http://example.com/2/ex/42/answer"); 45 | }); 46 | it("resolve", function(){ 47 | var profile = new rdf.Profile; 48 | profile.setPrefix('ex', 'http://example.com/'); 49 | assert.equal(typeof profile.resolve, 'function'); 50 | assert.equal(typeof profile.resolve('ex:type'), 'string'); 51 | assert.equal(profile.resolve('undefinedTerm'), null); 52 | }); 53 | it("setDefaultVocabulary", function(){ 54 | var profile = new rdf.Profile; 55 | assert.equal(typeof profile.setDefaultVocabulary, 'function'); 56 | assert.equal(typeof profile.setDefaultVocabulary('http://example.com/q/'), 'undefined'); 57 | assert.equal(profile.resolve('Friend'), 'http://example.com/q/Friend'); 58 | assert.equal(profile.terms.resolve('Friend'), 'http://example.com/q/Friend'); 59 | }); 60 | it("setDefaultPrefix", function(){ 61 | var profile = new rdf.Profile; 62 | assert.equal(typeof profile.setDefaultPrefix, 'function'); 63 | assert.equal(typeof profile.setDefaultPrefix('http://example.org/vocab/'), 'undefined'); 64 | assert.equal(profile.resolve(':Friend'), 'http://example.org/vocab/Friend'); 65 | assert.equal(profile.prefixes.resolve(':Friend'), 'http://example.org/vocab/Friend'); 66 | }); 67 | it("setTerm", function(){ 68 | var profile = new rdf.Profile; 69 | assert.equal(typeof profile.setTerm, 'function'); 70 | assert.equal(typeof profile.setTerm('a', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 'undefined'); 71 | assert.equal(profile.resolve('a'), 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'); 72 | assert.equal(profile.terms.resolve('a'), 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'); 73 | }); 74 | it("setPrefix", function(){ 75 | var profile = new rdf.Profile; 76 | assert.equal(typeof profile.setPrefix, 'function'); 77 | assert.equal(typeof profile.setPrefix('ex', 'http://example.com/'), 'undefined'); 78 | assert.equal(profile.prefixes.resolve('ex:type'), 'http://example.com/type'); 79 | assert.equal(profile.resolve('ex:type'), 'http://example.com/type'); 80 | }); 81 | it("setPrefix negative tests", function(){ 82 | var profile = new rdf.Profile; 83 | assert.equal(typeof profile.setPrefix, 'function'); 84 | assert.throws(function(){ 85 | profile.setPrefix('0', 'http://example.com/'); 86 | }); 87 | assert.throws(function(){ 88 | profile.setPrefix('::', 'http://example.com/'); 89 | }); 90 | assert.throws(function(){ 91 | profile.setPrefix(' ', 'http://example.com/'); 92 | }); 93 | assert.throws(function(){ 94 | profile.setPrefix('.', 'http://example.com/'); 95 | }); 96 | }); 97 | it("importProfile", function(){ 98 | var profile = new rdf.Profile; 99 | assert.equal(typeof profile.importProfile, 'function'); 100 | profile.setPrefix('ex', 'http://example.com/'); 101 | profile.setTerm('a', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'); 102 | 103 | var other = new rdf.Profile; 104 | other.setPrefix('ex', 'http://example.org/vocab/'); 105 | other.setTerm('a', 'http://example.org/type'); 106 | other.setPrefix('fx', 'http://example.org/vocab/'); 107 | other.setTerm('b', 'http://example.org/type'); 108 | 109 | profile.importProfile(other); 110 | assert.equal(profile.resolve('ex:a'), 'http://example.com/a'); 111 | assert.equal(profile.resolve('a'), 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'); 112 | assert.equal(profile.resolve('fx:a'), 'http://example.org/vocab/a'); 113 | assert.equal(profile.resolve('b'), 'http://example.org/type'); 114 | assert.strictEqual(profile.resolve('term'), null); 115 | assert.strictEqual(profile.resolve('c:foo'), null); 116 | }); 117 | it("importProfile (overwrite=false)", function(){ 118 | var profile = new rdf.Profile; 119 | profile.setPrefix('ex', 'http://example.com/'); 120 | profile.setTerm('a', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'); 121 | 122 | var other = new rdf.Profile; 123 | other.setPrefix('ex', 'http://example.org/vocab/'); 124 | other.setTerm('a', 'http://example.org/type'); 125 | other.setPrefix('fx', 'http://example.org/vocab/'); 126 | other.setTerm('b', 'http://example.org/type'); 127 | 128 | profile.importProfile(other, false); 129 | assert.equal(profile.resolve('ex:a'), 'http://example.com/a'); 130 | assert.equal(profile.resolve('a'), 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'); 131 | assert.equal(profile.resolve('fx:a'), 'http://example.org/vocab/a'); 132 | assert.equal(profile.resolve('b'), 'http://example.org/type'); 133 | assert.strictEqual(profile.resolve('term'), null); 134 | assert.strictEqual(profile.resolve('c:foo'), null); 135 | }); 136 | it("importProfile (overwrite=true)", function(){ 137 | var profile = new rdf.Profile; 138 | profile.setPrefix('ex', 'http://example.com/'); 139 | profile.setTerm('a', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'); 140 | 141 | var other = new rdf.Profile; 142 | other.setPrefix('ex', 'http://example.org/vocab/'); 143 | other.setTerm('a', 'http://example.org/type'); 144 | other.setPrefix('fx', 'http://example.org/vocab/'); 145 | other.setTerm('b', 'http://example.org/type'); 146 | 147 | profile.importProfile(other, true); 148 | assert.equal(profile.resolve('ex:a'), 'http://example.org/vocab/a'); 149 | assert.equal(profile.resolve('a'), 'http://example.org/type'); 150 | assert.equal(profile.resolve('fx:a'), 'http://example.org/vocab/a'); 151 | assert.equal(profile.resolve('b'), 'http://example.org/type'); 152 | assert.strictEqual(profile.resolve('term'), null); 153 | assert.strictEqual(profile.resolve('c:foo'), null); 154 | }); 155 | it("shrink", function(){ 156 | var profile = new rdf.Profile; 157 | profile.setTerm('a', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'); 158 | profile.setPrefix('ex2', 'http://example.com/vocab/foo/'); 159 | profile.setPrefix('ex', 'http://example.com/'); 160 | profile.setPrefix('exv', 'http://example.com/vocab/'); 161 | profile.setPrefix('🐉', 'http://example.com/vocab/dragon/'); 162 | 163 | assert.equal(profile.shrink('http://example.com/vocab/a'), 'exv:a'); 164 | assert.equal(profile.shrink('http://example.com/vocab/foo/b'), 'ex2:b'); 165 | assert.equal(profile.shrink('http://example.com/c'), 'ex:c'); 166 | // File is UTF-8 (probably), but escape sequence UTF-16 surrogate pairs 167 | // idk I didn't invent it, man 168 | assert.equal(profile.shrink('http://example.com/vocab/dragon/🐲'), '\uD83D\uDC09:\uD83D\uDC32'); 169 | assert.equal(profile.shrink('http://example.com/vocab/dragon/🐲🐧'), '\uD83D\uDC09:\uD83D\uDC32\uD83D\uDC27'); 170 | assert.equal(profile.shrink('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 'a'); 171 | }); 172 | it("remove", function(){ 173 | var profile = new rdf.Profile; 174 | profile.setTerm('term', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'); 175 | profile.setPrefix('prefix', 'http://example.com/vocab/foo/'); 176 | profile.terms.remove('term'); 177 | profile.prefixes.remove('prefix'); 178 | assert.strictEqual(profile.resolve('term'), null); 179 | assert.strictEqual(profile.resolve('prefix:foo'), null); 180 | }); 181 | }); 182 | -------------------------------------------------------------------------------- /test/Quad.test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var rdf = require('..'); 3 | 4 | describe('Quad', function(){ 5 | it('Quad(iri, iri, iri)', function(){ 6 | var env = new rdf.RDFEnvironment; 7 | var t = new rdf.Quad( 8 | env.createNamedNode('http://example.com/foo'), 9 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 10 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 11 | env.createNamedNode('http://example.com/graph'), 12 | ); 13 | assert.ok(t); 14 | }); 15 | it('Quad(bnode, iri, bnode)', function(){ 16 | var env = new rdf.RDFEnvironment; 17 | var t = new rdf.Quad( 18 | env.createNamedNode('http://example.com/foo'), 19 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 20 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 21 | env.createNamedNode('http://example.com/graph'), 22 | ); 23 | assert.ok(t); 24 | }); 25 | it('Quad(iri, iri, literal)', function(){ 26 | var env = new rdf.RDFEnvironment; 27 | var t = new rdf.Quad( 28 | env.createNamedNode('http://example.com/foo'), 29 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 30 | env.createLiteral('string!'), 31 | env.createNamedNode('http://example.com/graph'), 32 | ); 33 | assert.ok(t); 34 | }); 35 | it('Quad: literal subject throws', function(){ 36 | var env = new rdf.RDFEnvironment; 37 | assert.throws(function(){ 38 | new rdf.Quad( 39 | env.createLiteral('string!'), 40 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 41 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 42 | ); 43 | }); 44 | }); 45 | it('Quad: bnode predicate throws', function(){ 46 | var env = new rdf.RDFEnvironment; 47 | assert.throws(function(){ 48 | new rdf.Quad( 49 | env.createNamedNode('http://example.com/foo'), 50 | env.createBlankNode(), 51 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 52 | ); 53 | }); 54 | }); 55 | it('Quad: literal predicate throws', function(){ 56 | var env = new rdf.RDFEnvironment; 57 | assert.throws(function(){ 58 | new rdf.Quad( 59 | env.createNamedNode('http://example.com/foo'), 60 | env.createLiteral('string!'), 61 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 62 | ); 63 | }); 64 | }); 65 | it('Quad: variable subject throws', function(){ 66 | var env = new rdf.RDFEnvironment; 67 | assert.throws(function(){ 68 | new rdf.Quad( 69 | new rdf.Variable('s'), 70 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 71 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 72 | ); 73 | }); 74 | }); 75 | it('Quad: variable predicate throws', function(){ 76 | var env = new rdf.RDFEnvironment; 77 | assert.throws(function(){ 78 | new rdf.Quad( 79 | env.createNamedNode('http://example.com/foo'), 80 | new rdf.Variable('p'), 81 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 82 | ); 83 | }); 84 | }); 85 | it('Quad: variable object throws', function(){ 86 | var env = new rdf.RDFEnvironment; 87 | assert.throws(function(){ 88 | new rdf.Quad( 89 | env.createNamedNode('http://example.com/foo'), 90 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 91 | new rdf.Variable('o'), 92 | ); 93 | }); 94 | }); 95 | it('Quad: null subject throws', function(){ 96 | var env = new rdf.RDFEnvironment; 97 | assert.throws(function(){ 98 | new rdf.Quad( 99 | null, 100 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 101 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 102 | ); 103 | }); 104 | }); 105 | it('Quad: null predicate throws', function(){ 106 | var env = new rdf.RDFEnvironment; 107 | assert.throws(function(){ 108 | new rdf.Quad( 109 | env.createNamedNode('http://example.com/foo'), 110 | null, 111 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 112 | ); 113 | }); 114 | }); 115 | it('Quad: null object throws', function(){ 116 | var env = new rdf.RDFEnvironment; 117 | assert.throws(function(){ 118 | new rdf.Quad( 119 | env.createNamedNode('http://example.com/foo'), 120 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 121 | null, 122 | ); 123 | }); 124 | }); 125 | it('Quad: string subject', function(){ 126 | var env = new rdf.RDFEnvironment; 127 | new rdf.Quad( 128 | 'http://example.com/foo', 129 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 130 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 131 | env.createNamedNode('http://example.com/graph'), 132 | ); 133 | }); 134 | it('Quad: string predicate', function(){ 135 | var env = new rdf.RDFEnvironment; 136 | new rdf.Quad( 137 | env.createNamedNode('http://example.com/foo'), 138 | 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', 139 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 140 | env.createNamedNode('http://example.com/graph'), 141 | ); 142 | }); 143 | it('Quad: string object', function(){ 144 | var env = new rdf.RDFEnvironment; 145 | new rdf.Quad( 146 | env.createNamedNode('http://example.com/foo'), 147 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 148 | 'http://www.w3.org/2000/01/rdf-schema#Class', 149 | env.createNamedNode('http://example.com/graph'), 150 | ); 151 | }); 152 | it('Quad: string graph', function(){ 153 | var env = new rdf.RDFEnvironment; 154 | new rdf.Quad( 155 | env.createNamedNode('http://example.com/foo'), 156 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 157 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 158 | 'http://example.com/graph', 159 | ); 160 | }); 161 | it("toString", function(){ 162 | var nn = new rdf.NamedNode('http://example.com/'); 163 | var t = new rdf.Quad(nn, nn, nn, nn); 164 | assert.strictEqual(t.toString(), ' .'); 165 | }); 166 | it("equals", function(){ 167 | var nn = new rdf.NamedNode('http://example.com/'); 168 | var t = new rdf.Quad(nn, nn, nn, nn); 169 | var nn2 = new rdf.NamedNode('http://example.com/'); 170 | assert.ok(t.equals(new rdf.Quad(nn2, nn2, nn2, nn2))); 171 | }); 172 | it("equals (negative subject)", function(){ 173 | var nn = new rdf.NamedNode('http://example.com/'); 174 | var t = new rdf.Quad(nn, nn, nn, nn); 175 | var nn2 = new rdf.NamedNode('http://example.com/'); 176 | var nn3 = new rdf.NamedNode('http://example.org/foo'); 177 | assert(!t.equals(new rdf.Quad(nn3, nn2, nn2, nn2))); 178 | }); 179 | it("equals (negative predicate)", function(){ 180 | var nn = new rdf.NamedNode('http://example.com/'); 181 | var t = new rdf.Quad(nn, nn, nn, nn); 182 | var nn2 = new rdf.NamedNode('http://example.com/'); 183 | var nn3 = new rdf.NamedNode('http://example.org/foo'); 184 | assert(!t.equals(new rdf.Quad(nn2, nn3, nn2, nn2))); 185 | }); 186 | it("equals (negative object)", function(){ 187 | var nn = new rdf.NamedNode('http://example.com/'); 188 | var t = new rdf.Quad(nn, nn, nn, nn); 189 | var nn2 = new rdf.NamedNode('http://example.com/'); 190 | var nn3 = new rdf.NamedNode('http://example.org/foo'); 191 | assert(!t.equals(new rdf.Quad(nn2, nn2, nn3, nn2))); 192 | }); 193 | it("equals (negative graph)", function(){ 194 | var nn = new rdf.NamedNode('http://example.com/'); 195 | var t = new rdf.Quad(nn, nn, nn, nn); 196 | var nn2 = new rdf.NamedNode('http://example.com/'); 197 | var nn3 = new rdf.NamedNode('http://example.org/foo'); 198 | assert(!t.equals(new rdf.Quad(nn2, nn2, nn2, nn3))); 199 | }); 200 | }); 201 | -------------------------------------------------------------------------------- /test/RDF-MT.test.js: -------------------------------------------------------------------------------- 1 | // This expects the RDF Semantics test suite to be extracted, 2 | // with the manifest file at ./rdf-mt-tests/manifest.ttl 3 | // Run `make test` to download this 4 | 5 | var assert = require('assert'); 6 | var fs = require('fs'); 7 | var rdf = require('..'); 8 | var TurtleParser = rdf.TurtleParser; 9 | 10 | var m$ = rdf.ns('http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#'); 11 | var PositiveEntailmentTest = m$('PositiveEntailmentTest'); 12 | var NegativeEntailmentTest = m$('NegativeEntailmentTest'); 13 | 14 | var manifestBase = 'http://www.w3.org/2013/rdf-mt-tests/manifest.ttl'; 15 | //var manifestBase = 'file://'+__dirname+'/rdf-mt-tests/manifest.ttl'; 16 | var manifestData = require('fs').readFileSync('test/rdf-mt-tests/manifest.ttl'); 17 | var manifestParse = TurtleParser.parse(manifestData, manifestBase); 18 | var manifestGraph = manifestParse.graph; 19 | 20 | var manifest = manifestGraph.match(manifestBase, m$('entries'), null).toArray(); 21 | var manifestTests = manifestGraph.getCollection(manifest[0].object); 22 | 23 | describe('RDF Semantics test suite', function(){ 24 | it('Parse Turtle test suite manifest', function(){ 25 | assert.ok(manifestTests.length); 26 | }); 27 | describe('test', function(){ 28 | manifestTests.forEach(function(test){ 29 | // Each test is one of the above kinds of tests. All tests have 30 | // - a name (mf:name), 31 | var testName = manifestGraph.reference(test).rel(m$('name')).one().toString(); 32 | // - an input RDF graph URL (mf:action), 33 | var testInputURI = manifestGraph.reference(test).rel(m$('action')).one().toString(); 34 | var testInputFile = testInputURI.replace('http://www.w3.org/2013/', 'test/'); 35 | // - an output RDF graph URL or the special marker false (mf:result), 36 | var testOutputURI = manifestGraph.reference(test).rel(m$('result')).one().toString(); 37 | var testOutputFile = testOutputURI.replace('http://www.w3.org/2013/', 'test/'); 38 | // - an entailment regime, which is "simple", "RDF", or "RDFS" (mf:entailmentRegime), 39 | var entailmentRegime = manifestGraph.reference(test).rel(m$('entailmentRegime')).one().toString(); 40 | // - a list of recognized datatypes (mf:recognizedDatatypes), 41 | // - a list of unrecognized datatypes (mf:unrecognizedDatatypes). 42 | if(entailmentRegime!=='simple') return; 43 | var types = manifestGraph.reference(test).rel(rdf.rdfns('type')).toArray(); 44 | for(var j=0; jSome Literal

', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral'); 56 | assert.ok(t instanceof rdf.Literal); 57 | assert.equal(t.toString(), '

Some Literal

'); 58 | assert.equal(t.datatype.toString(), 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral'); 59 | assert.equal(t.language, null); 60 | }); 61 | it('createLiteral(value, NamedNode)', function(){ 62 | var env = new rdf.RDFEnvironment; 63 | var t = env.createLiteral('

Some Literal

', new rdf.NamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral')); 64 | assert.ok(t instanceof rdf.Literal); 65 | assert.equal(t.toString(), '

Some Literal

'); 66 | assert.equal(t.datatype.toString(), 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral'); 67 | assert.equal(t.language, null); 68 | }); 69 | it('createLiteral(value, language)', function(){ 70 | var env = new rdf.RDFEnvironment; 71 | var t = env.createLiteral('Some Literal', 'en'); 72 | assert.ok(t instanceof rdf.Literal); 73 | assert.equal(t.toString(), 'Some Literal'); 74 | assert.equal(t.datatype.toString(), 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString'); 75 | assert.equal(t.language, 'en'); 76 | }); 77 | it('createLiteral(value, LangTag)', function(){ 78 | var env = new rdf.RDFEnvironment; 79 | var t = env.createLiteral('Some Literal', '@en'); 80 | assert.ok(t instanceof rdf.Literal); 81 | assert.equal(t.toString(), 'Some Literal'); 82 | assert.equal(t.datatype.toString(), 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString'); 83 | assert.equal(t.language, 'en'); 84 | }); 85 | it('createLiteral(value, null, datatype)', function(){ 86 | var env = new rdf.RDFEnvironment; 87 | var t = env.createLiteral('

Some Literal

', null, 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral'); 88 | assert.ok(t instanceof rdf.Literal); 89 | assert.equal(t.toString(), '

Some Literal

'); 90 | assert.equal(t.datatype.toString(), 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral'); 91 | assert.equal(t.language, null); 92 | }); 93 | it('createLiteral(value, null, NamedNode)', function(){ 94 | var env = new rdf.RDFEnvironment; 95 | var t = env.createLiteral('

Some Literal

', null, new rdf.NamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral')); 96 | assert.ok(t instanceof rdf.Literal); 97 | assert.equal(t.toString(), '

Some Literal

'); 98 | assert.equal(t.datatype.toString(), 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral'); 99 | assert.equal(t.language, null); 100 | }); 101 | it('createLanguageLiteral(value) throws', function(){ 102 | var env = new rdf.RDFEnvironment; 103 | assert.throws(function(){ 104 | var t = env.createLanguageLiteral('

Some Literal

'); 105 | }); 106 | }); 107 | it('createLanguageLiteral(value, datatype) throws', function(){ 108 | var env = new rdf.RDFEnvironment; 109 | assert.throws(function(){ 110 | var t = env.createLanguageLiteral('

Some Literal

', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral'); 111 | }); 112 | }); 113 | it('createLanguageLiteral(value, language)', function(){ 114 | var env = new rdf.RDFEnvironment; 115 | var t = env.createLiteral('Some Literal', 'en'); 116 | assert.ok(t instanceof rdf.Literal); 117 | assert.equal(t.toString(), 'Some Literal'); 118 | assert.equal(t.datatype.toString(), 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString'); 119 | assert.equal(t.language, 'en'); 120 | }); 121 | it('createTypedLiteral(value) throws', function(){ 122 | var env = new rdf.RDFEnvironment; 123 | assert.throws(function(){ 124 | env.createTypedLiteral('

Some Literal

'); 125 | }); 126 | }); 127 | it('createTypedLiteral(value, datatype)', function(){ 128 | var env = new rdf.RDFEnvironment; 129 | var t = env.createTypedLiteral('

Some Literal

', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral'); 130 | assert.ok(t instanceof rdf.Literal); 131 | assert.equal(t.toString(), '

Some Literal

'); 132 | assert.equal(t.datatype.toString(), 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral'); 133 | assert.equal(t.language, null); 134 | }); 135 | it('createTypedLiteral(value, NamedNode)', function(){ 136 | var env = new rdf.RDFEnvironment; 137 | var t = env.createTypedLiteral('

Some Literal

', new rdf.NamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral')); 138 | assert.ok(t instanceof rdf.Literal); 139 | assert.equal(t.toString(), '

Some Literal

'); 140 | assert.equal(t.datatype.toString(), 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral'); 141 | assert.equal(t.language, null); 142 | }); 143 | it('createTypedLiteral(value, language) throws', function(){ 144 | var env = new rdf.RDFEnvironment; 145 | assert.throws(function(){ 146 | var t = env.createTypedLiteral('Some Literal', 'en'); 147 | }); 148 | }); 149 | it('createTriple(iri, iri, iri)', function(){ 150 | var env = new rdf.RDFEnvironment; 151 | var t = env.createTriple( 152 | env.createNamedNode('http://example.com/foo'), 153 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 154 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 155 | ); 156 | assert.ok(t); 157 | }); 158 | it('createTriple(bnode, iri, bnode)', function(){ 159 | var env = new rdf.RDFEnvironment; 160 | var t = env.createTriple( 161 | env.createNamedNode('http://example.com/foo'), 162 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 163 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 164 | ); 165 | assert.ok(t); 166 | }); 167 | it('createTriple(iri, iri, literal)', function(){ 168 | var env = new rdf.RDFEnvironment; 169 | var t = env.createTriple( 170 | env.createNamedNode('http://example.com/foo'), 171 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 172 | env.createLiteral('string!'), 173 | ); 174 | assert.ok(t); 175 | }); 176 | it('createTriple: no literal subject', function(){ 177 | var env = new rdf.RDFEnvironment; 178 | assert.throws(function(){ 179 | env.createTriple( 180 | env.createLiteral('string!'), 181 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 182 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 183 | ); 184 | }); 185 | }); 186 | it('createTriple: no bnode predicate', function(){ 187 | var env = new rdf.RDFEnvironment; 188 | assert.throws(function(){ 189 | env.createTriple( 190 | env.createNamedNode('http://example.com/foo'), 191 | env.createBlankNode(), 192 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 193 | ); 194 | }); 195 | }); 196 | it('createTriple: no literal predicate', function(){ 197 | var env = new rdf.RDFEnvironment; 198 | assert.throws(function(){ 199 | env.createTriple( 200 | env.createNamedNode('http://example.com/foo'), 201 | env.createLiteral('string!'), 202 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 203 | ); 204 | }); 205 | }); 206 | it('createProfile', function(){ 207 | var env = new rdf.RDFEnvironment; 208 | var t = env.createProfile(); 209 | assert.ok(t instanceof rdf.Profile); 210 | }); 211 | it('createTermMap', function(){ 212 | var env = new rdf.RDFEnvironment; 213 | var t = env.createTermMap(); 214 | assert.ok(t instanceof rdf.TermMap); 215 | }); 216 | it('createPrefixMap', function(){ 217 | var env = new rdf.RDFEnvironment; 218 | var t = env.createPrefixMap(); 219 | assert.ok(t instanceof rdf.PrefixMap); 220 | }); 221 | }); 222 | -------------------------------------------------------------------------------- /test/RDFNode.test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var rdf = require('..'); 3 | 4 | function LiteralTests(){ 5 | it("compare (via sort)", function(){ 6 | // Array to be sorted via RDFNode#compare 7 | var bros = [ 8 | new rdf.BlankNode('_:a'), 9 | new rdf.Literal("A String", '@en-GB'), 10 | new rdf.Literal("A"), 11 | new rdf.Literal("A String"), 12 | new rdf.Literal("true", rdf.xsdns('boolean')), 13 | new rdf.Literal("A String", '@ja'), 14 | new rdf.Literal("false", rdf.xsdns('boolean')), 15 | new rdf.BlankNode('b'), 16 | new rdf.NamedNode("http://example.com/"), 17 | new rdf.Literal("A String", '@en'), 18 | new rdf.NamedNode("http://example.com/a"), 19 | new rdf.BlankNode('_:c'), 20 | new rdf.NamedNode("http://example.com/b"), 21 | ]; 22 | bros.sort(function(a, b){ return a.compare(b); }); 23 | //bros.forEach(function(v){ console.log(v.toNT()); }); 24 | // I don't know if this order means much to people, but it's an order 25 | [ 26 | new rdf.NamedNode("http://example.com/"), 27 | new rdf.NamedNode("http://example.com/a"), 28 | new rdf.NamedNode("http://example.com/b"), 29 | new rdf.BlankNode('a'), 30 | new rdf.BlankNode('b'), 31 | new rdf.BlankNode('c'), 32 | new rdf.Literal("A"), 33 | new rdf.Literal("A String"), 34 | new rdf.Literal("A String", '@en'), 35 | new rdf.Literal("A String", '@en-GB'), 36 | new rdf.Literal("A String", '@ja'), 37 | new rdf.Literal("false", rdf.xsdns('boolean')), 38 | new rdf.Literal("true", rdf.xsdns('boolean')), 39 | ].forEach(function(t, i){ 40 | assert(t.equals(bros[i]), 'item '+i+' mismatch'); 41 | }); 42 | }); 43 | } 44 | 45 | describe('RDFNode', LiteralTests); 46 | 47 | describe('RDFNode (with builtins)', function(){ 48 | before(function(){ 49 | rdf.setBuiltins(); 50 | }); 51 | after(function(){ 52 | rdf.unsetBuiltins(); 53 | }); 54 | LiteralTests(); 55 | }); 56 | -------------------------------------------------------------------------------- /test/TermMap.test.js: -------------------------------------------------------------------------------- 1 | 2 | var assert = require('assert'); 3 | var rdf = require('..'); 4 | 5 | /* 6 | [NoInterfaceObject] 7 | interface TermMap { 8 | omittable getter DOMString get (DOMString term); 9 | omittable setter void set (DOMString term, DOMString iri); 10 | omittable deleter void remove (DOMString term); 11 | DOMString resolve (DOMString term); 12 | DOMString shrink (DOMString iri); 13 | void setDefault (DOMString iri); 14 | TermMap addAll (TermMap terms, optional boolean override); // Corrected typo 15 | }; 16 | */ 17 | 18 | describe('TermMap', function(){ 19 | it('TermMap#get(string, string)', function(){ 20 | var map = new rdf.TermMap; 21 | assert.equal(typeof map.get, 'function'); 22 | }); 23 | it('TermMap#set(string, string)', function(){ 24 | var map = new rdf.TermMap; 25 | assert.equal(typeof map.set, 'function'); 26 | assert.equal(typeof map.set('type', 'http://example.com/type'), 'undefined'); 27 | assert.equal(map.get('type'), 'http://example.com/type'); 28 | assert.equal(map.resolve('type'), 'http://example.com/type'); 29 | }); 30 | it('TermMap#setDefault(string)', function(){ 31 | var map = new rdf.TermMap; 32 | assert.equal(typeof map.set, 'function'); 33 | assert.equal(typeof map.setDefault('http://example.com/'), 'undefined'); 34 | assert.equal(map.resolve('type'), 'http://example.com/type'); 35 | }); 36 | it("TermMap#set negative tests", function(){ 37 | var map = new rdf.TermMap; 38 | assert.equal(typeof map.set, 'function'); 39 | assert.throws(function(){ 40 | map.set('0', 'http://example.com/'); 41 | }); 42 | assert.throws(function(){ 43 | map.set('::', 'http://example.com/'); 44 | }); 45 | assert.throws(function(){ 46 | map.set(' ', 'http://example.com/'); 47 | }); 48 | assert.throws(function(){ 49 | map.set('.', 'http://example.com/'); 50 | }); 51 | }); 52 | it("TermMap#remove(string)", function(){ 53 | var map = new rdf.TermMap; 54 | map.set('foo', 'http://example.com/vocab/foo/'); 55 | map.remove('foo'); 56 | assert.strictEqual(map.resolve('foo'), null); 57 | }); 58 | it("TermMap#resolve(string)", function(){ 59 | var map = new rdf.TermMap; 60 | map.set('type', 'http://example.com/'); 61 | assert.equal(typeof map.resolve, 'function'); 62 | assert.equal(typeof map.resolve('type'), 'string'); 63 | assert.equal(map.resolve('undefinedTerm'), null); 64 | }); 65 | it("TermMap#shrink(string)", function(){ 66 | var map = new rdf.TermMap; 67 | map.set('ex', 'http://example.com/ex'); 68 | map.setDefault('http://example.com/vocab/🐉/'); 69 | 70 | assert.equal(map.shrink('http://example.com/ex'), 'ex'); 71 | // File is UTF-8 (probably), but escape sequence UTF-16 surrogate pairs 72 | // idk I didn't invent it, man 73 | assert.equal(map.shrink('http://example.com/vocab/🐉/🐲'), '\uD83D\uDC32'); 74 | }); 75 | it("addAll", function(){ 76 | var map = new rdf.TermMap; 77 | assert.equal(typeof map.addAll, 'function'); 78 | map.set('a', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'); 79 | 80 | var other = new rdf.TermMap; 81 | other.set('a', 'http://example.org/type'); 82 | other.set('b', 'http://example.org/type'); 83 | 84 | map.addAll(other); 85 | assert.equal(map.resolve('a'), 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'); 86 | assert.equal(map.resolve('b'), 'http://example.org/type'); 87 | assert.strictEqual(map.resolve('term'), null); 88 | }); 89 | it("addAll (overwrite=false)", function(){ 90 | var map = new rdf.TermMap; 91 | map.set('a', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'); 92 | 93 | var other = new rdf.TermMap; 94 | other.set('a', 'http://example.org/type'); 95 | other.set('b', 'http://example.org/type'); 96 | 97 | map.addAll(other, false); 98 | assert.equal(map.resolve('a'), 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'); 99 | assert.equal(map.resolve('b'), 'http://example.org/type'); 100 | assert.strictEqual(map.resolve('term'), null); 101 | }); 102 | it("addAll (overwrite=true)", function(){ 103 | var map = new rdf.TermMap; 104 | map.set('a', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'); 105 | 106 | var other = new rdf.TermMap; 107 | other.set('a', 'http://example.org/type'); 108 | other.set('b', 'http://example.org/type'); 109 | 110 | map.addAll(other, true); 111 | assert.equal(map.resolve('a'), 'http://example.org/type'); 112 | assert.equal(map.resolve('b'), 'http://example.org/type'); 113 | assert.strictEqual(map.resolve('term'), null); 114 | }); 115 | it("TermMap#list", function(){ 116 | var map = new rdf.TermMap; 117 | assert.equal(map.list().length, 0); 118 | map.set('ex', 'http://example.com/'); 119 | var list = map.list(); 120 | assert.equal(list.length, 1); 121 | assert.equal(list[0], 'ex'); 122 | }); 123 | }); 124 | -------------------------------------------------------------------------------- /test/Triple.test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var rdf = require('..'); 3 | 4 | describe('Triple', function(){ 5 | it('Triple(iri, iri, iri)', function(){ 6 | var env = new rdf.RDFEnvironment; 7 | var t = new rdf.Triple( 8 | env.createNamedNode('http://example.com/foo'), 9 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 10 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 11 | ); 12 | assert.ok(t); 13 | }); 14 | it('Triple(bnode, iri, bnode)', function(){ 15 | var env = new rdf.RDFEnvironment; 16 | var t = new rdf.Triple( 17 | env.createNamedNode('http://example.com/foo'), 18 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 19 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 20 | ); 21 | assert.ok(t); 22 | }); 23 | it('Triple(iri, iri, literal)', function(){ 24 | var env = new rdf.RDFEnvironment; 25 | var t = new rdf.Triple( 26 | env.createNamedNode('http://example.com/foo'), 27 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 28 | env.createLiteral('string!'), 29 | ); 30 | assert.ok(t); 31 | }); 32 | it('Triple: literal subject throws', function(){ 33 | var env = new rdf.RDFEnvironment; 34 | assert.throws(function(){ 35 | new rdf.Triple( 36 | env.createLiteral('string!'), 37 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 38 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 39 | ); 40 | }); 41 | }); 42 | it('Triple: bnode predicate throws', function(){ 43 | var env = new rdf.RDFEnvironment; 44 | assert.throws(function(){ 45 | new rdf.Triple( 46 | env.createNamedNode('http://example.com/foo'), 47 | env.createBlankNode(), 48 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 49 | ); 50 | }); 51 | }); 52 | it('Triple: literal predicate throws', function(){ 53 | var env = new rdf.RDFEnvironment; 54 | assert.throws(function(){ 55 | new rdf.Triple( 56 | env.createNamedNode('http://example.com/foo'), 57 | env.createLiteral('string!'), 58 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 59 | ); 60 | }); 61 | }); 62 | it('Triple: variable subject throws', function(){ 63 | var env = new rdf.RDFEnvironment; 64 | assert.throws(function(){ 65 | new rdf.Triple( 66 | new rdf.Variable('s'), 67 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 68 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 69 | ); 70 | }); 71 | }); 72 | it('Triple: variable predicate throws', function(){ 73 | var env = new rdf.RDFEnvironment; 74 | assert.throws(function(){ 75 | new rdf.Triple( 76 | env.createNamedNode('http://example.com/foo'), 77 | new rdf.Variable('p'), 78 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 79 | ); 80 | }); 81 | }); 82 | it('Triple: variable object throws', function(){ 83 | var env = new rdf.RDFEnvironment; 84 | assert.throws(function(){ 85 | new rdf.Triple( 86 | env.createNamedNode('http://example.com/foo'), 87 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 88 | new rdf.Variable('o'), 89 | ); 90 | }); 91 | }); 92 | it('Triple: null subject throws', function(){ 93 | var env = new rdf.RDFEnvironment; 94 | assert.throws(function(){ 95 | new rdf.Triple( 96 | null, 97 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 98 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 99 | ); 100 | }); 101 | }); 102 | it('Triple: null predicate throws', function(){ 103 | var env = new rdf.RDFEnvironment; 104 | assert.throws(function(){ 105 | new rdf.Triple( 106 | env.createNamedNode('http://example.com/foo'), 107 | null, 108 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 109 | ); 110 | }); 111 | }); 112 | it('Triple: null object throws', function(){ 113 | var env = new rdf.RDFEnvironment; 114 | assert.throws(function(){ 115 | new rdf.Triple( 116 | env.createNamedNode('http://example.com/foo'), 117 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 118 | null, 119 | ); 120 | }); 121 | }); 122 | it('Triple: string subject', function(){ 123 | var env = new rdf.RDFEnvironment; 124 | new rdf.Triple( 125 | 'http://example.com/foo', 126 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 127 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 128 | ); 129 | }); 130 | it('Triple: string predicate', function(){ 131 | var env = new rdf.RDFEnvironment; 132 | new rdf.Triple( 133 | env.createNamedNode('http://example.com/foo'), 134 | 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', 135 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 136 | ); 137 | }); 138 | it('Triple: string object', function(){ 139 | var env = new rdf.RDFEnvironment; 140 | new rdf.Triple( 141 | env.createNamedNode('http://example.com/foo'), 142 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 143 | 'http://www.w3.org/2000/01/rdf-schema#Class', 144 | ); 145 | }); 146 | it("toString", function(){ 147 | var nn = new rdf.NamedNode('http://example.com/'); 148 | var t = new rdf.Triple(nn, nn, nn); 149 | assert.strictEqual(t.toString(), ' .'); 150 | }); 151 | it("equals", function(){ 152 | var nn = new rdf.NamedNode('http://example.com/'); 153 | var t = new rdf.Triple(nn, nn, nn); 154 | var nn2 = new rdf.NamedNode('http://example.com/'); 155 | assert.ok(t.equals(new rdf.Triple(nn2, nn2, nn2))); 156 | }); 157 | it("equals (negative subject)", function(){ 158 | var nn = new rdf.NamedNode('http://example.com/'); 159 | var t = new rdf.Triple(nn, nn, nn); 160 | var nn2 = new rdf.NamedNode('http://example.com/'); 161 | var nn3 = new rdf.NamedNode('http://example.org/foo'); 162 | assert(!t.equals(new rdf.Triple(nn3, nn2, nn2))); 163 | }); 164 | it("equals (negative predicate)", function(){ 165 | var nn = new rdf.NamedNode('http://example.com/'); 166 | var t = new rdf.Triple(nn, nn, nn); 167 | var nn2 = new rdf.NamedNode('http://example.com/'); 168 | var nn3 = new rdf.NamedNode('http://example.org/foo'); 169 | assert(!t.equals(new rdf.Triple(nn2, nn3, nn2))); 170 | }); 171 | it("equals (negative object)", function(){ 172 | var nn = new rdf.NamedNode('http://example.com/'); 173 | var t = new rdf.Triple(nn, nn, nn); 174 | var nn2 = new rdf.NamedNode('http://example.com/'); 175 | var nn3 = new rdf.NamedNode('http://example.org/foo'); 176 | assert(!t.equals(new rdf.Triple(nn2, nn2, nn3))); 177 | }); 178 | // TODO: behavior for testing equal of things that are not Triple 179 | }); 180 | -------------------------------------------------------------------------------- /test/TriplePattern.test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var rdf = require('..'); 3 | 4 | describe('TriplePattern', function(){ 5 | it('TriplePattern(iri, iri, iri)', function(){ 6 | var env = new rdf.RDFEnvironment; 7 | var t = new rdf.TriplePattern( 8 | env.createNamedNode('http://example.com/foo'), 9 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 10 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 11 | ); 12 | assert.ok(t); 13 | }); 14 | it('TriplePattern(variable, variable, variable)', function(){ 15 | var env = new rdf.RDFEnvironment; 16 | var t = new rdf.TriplePattern( 17 | new rdf.Variable('s'), 18 | new rdf.Variable('p'), 19 | new rdf.Variable('o'), 20 | ); 21 | assert.ok(t); 22 | }); 23 | it('TriplePattern(bnode, iri, bnode)', function(){ 24 | var env = new rdf.RDFEnvironment; 25 | var t = new rdf.TriplePattern( 26 | env.createNamedNode('http://example.com/foo'), 27 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 28 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 29 | ); 30 | assert.ok(t); 31 | }); 32 | it('TriplePattern(iri, iri, literal)', function(){ 33 | var env = new rdf.RDFEnvironment; 34 | var t = new rdf.TriplePattern( 35 | env.createNamedNode('http://example.com/foo'), 36 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 37 | env.createLiteral('string!'), 38 | ); 39 | assert.ok(t); 40 | }); 41 | it('TriplePattern: literal subject throws', function(){ 42 | var env = new rdf.RDFEnvironment; 43 | assert.throws(function(){ 44 | new rdf.TriplePattern( 45 | env.createLiteral('string!'), 46 | env.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 47 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 48 | ); 49 | }); 50 | }); 51 | it('TriplePattern: bnode predicate throws', function(){ 52 | var env = new rdf.RDFEnvironment; 53 | assert.throws(function(){ 54 | new rdf.TriplePattern( 55 | env.createNamedNode('http://example.com/foo'), 56 | env.createBlankNode(), 57 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 58 | ); 59 | }); 60 | }); 61 | it('TriplePattern: literal predicate throws', function(){ 62 | var env = new rdf.RDFEnvironment; 63 | assert.throws(function(){ 64 | new rdf.TriplePattern( 65 | env.createNamedNode('http://example.com/foo'), 66 | env.createLiteral('string!'), 67 | env.createNamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 68 | ); 69 | }); 70 | }); 71 | it("toString", function(){ 72 | var t = new rdf.TriplePattern( 73 | new rdf.Variable('s'), 74 | new rdf.Variable('p'), 75 | new rdf.Variable('o'), 76 | ); 77 | assert.strictEqual(t.toString(), '?s ?p ?o .'); 78 | }); 79 | it("equals", function(){ 80 | var nn = new rdf.NamedNode('http://example.com/'); 81 | var t = new rdf.TriplePattern(nn, nn, nn); 82 | var nn2 = new rdf.NamedNode('http://example.com/'); 83 | assert.ok(t.equals(new rdf.TriplePattern(nn2, nn2, nn2))); 84 | }); 85 | }); 86 | -------------------------------------------------------------------------------- /test/TurtleParser.test.js: -------------------------------------------------------------------------------- 1 | // This expects the RDF Semantics test suite to be extracted, 2 | // with the manifest file at ./TurtleTests/manifest.ttl 3 | // Run `make test` to download this 4 | 5 | var assert = require('assert'); 6 | var fs = require('fs'); 7 | var rdf = require('..'); 8 | var TurtleParser = rdf.TurtleParser; 9 | 10 | var m$ = rdf.ns('http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#'); 11 | 12 | var manifestBase = 'http://www.w3.org/2013/TurtleTests/manifest.ttl'; 13 | //var manifestBase = 'file://'+__dirname+'/TurtleTests/manifest.ttl'; 14 | var manifestData = require('fs').readFileSync('test/TurtleTests/manifest.ttl'); 15 | var manifestParse = TurtleParser.parse(manifestData, manifestBase); 16 | var manifestGraph = manifestParse.graph; 17 | 18 | var manifest = manifestGraph.match(manifestBase, m$('entries'), null).toArray(); 19 | var manifestTests = manifestGraph.getCollection(manifest[0].object); 20 | 21 | describe('TurtleParser', function(){ 22 | it('TurtleParser.parse', function(){ 23 | var parse = rdf.TurtleParser.parse('<> a .', 'http://example.com/'); 24 | assert.equal(parse.graph.toArray().join("\n"), ' .'); 25 | }); 26 | }); 27 | 28 | describe('Turtle test suite', function(){ 29 | it('Parse Turtle test suite manifest', function(){ 30 | assert.ok(manifestTests.length); 31 | }); 32 | describe('test', function(){ 33 | 34 | manifestTests.forEach(function(test){ 35 | var types = manifestGraph.reference(test).rel(rdf.rdfns('type')).toArray(); 36 | var fileURI = manifestGraph.reference(test).rel(m$('action')).one().toString(); 37 | var filename = fileURI.replace('http://www.w3.org/2013/', 'test/'); 38 | 39 | for(var j=0; j', function(done){ 43 | // First parse the expected data (in N-Triples format) 44 | var resultURI = manifestGraph.reference(test).rel(m$('result')).one().toString(); 45 | var resultFile = resultURI.replace('http://www.w3.org/2013/', 'test/'); 46 | fs.readFile(resultFile, 'utf8', function(err, data){ 47 | if(err) throw err; 48 | var expectedParser = TurtleParser.parse(data, resultURI); 49 | var expectedGraph = expectedParser.graph; 50 | // Now parse the Turtle file 51 | fs.readFile(filename, 'utf8', function(err, data){ 52 | if(err) throw err; 53 | var parser = TurtleParser.parse(data, fileURI); 54 | var graph = parser.graph; 55 | // Have the data, compare 56 | var expectedTriples = expectedGraph.toArray().sort(); 57 | var outputTriples = graph.toArray().sort(); 58 | 59 | if(!expectedGraph.isomorphic(graph)){ 60 | assert.equal(outputTriples.join('\n'), expectedTriples.join('\n')); 61 | assert.ok(expectedGraph.isomorphic(graph)); 62 | } 63 | done(); 64 | }); 65 | }); 66 | }); 67 | break; 68 | case 'http://www.w3.org/ns/rdftest#TestTurtlePositiveSyntax': 69 | it('positive test <'+filename+'>', function(done){ 70 | fs.readFile(filename, 'utf8', function(err, data){ 71 | if(err) throw err; 72 | var parser = TurtleParser.parse(data, fileURI); 73 | assert(parser.graph); 74 | done(); 75 | }); 76 | }); 77 | break; 78 | case 'http://www.w3.org/ns/rdftest#TestTurtleNegativeSyntax': 79 | case 'http://www.w3.org/ns/rdftest#TestTurtleNegativeEval': 80 | it('negative test <'+filename+'>', function(done){ 81 | fs.readFile(filename, 'utf8', function(err, data){ 82 | if(err) throw err; 83 | assert.throws(function(){ 84 | TurtleParser.parse(data, file); 85 | }); 86 | done(); 87 | }); 88 | }); 89 | break; 90 | default: 91 | break; 92 | } 93 | } 94 | }); 95 | }); 96 | }); 97 | -------------------------------------------------------------------------------- /test/Variable.test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var rdf = require('..'); 3 | 4 | describe('Variable', function(){ 5 | it("instance", function(){ 6 | var t = new rdf.Variable('name'); 7 | assert.ok(t instanceof rdf.Variable); 8 | assert.strictEqual(t.nodeType(), 'Variable'); 9 | assert.strictEqual(t.interfaceName, 'Variable'); // 2012 Note variant 10 | assert.strictEqual(t.termType, 'Variable'); // 2017 Community Group variant 11 | }); 12 | it("Variable(undefined) requires string argument", function(){ 13 | assert.throws(function(){ 14 | var t = new rdf.Variable(); 15 | }); 16 | }); 17 | it("Variable(null) requires string argument", function(){ 18 | assert.throws(function(){ 19 | var t = new rdf.Variable(null); 20 | }); 21 | }); 22 | it("toNT throws", function(){ 23 | var t = new rdf.Variable('name'); 24 | assert.throws(function(){ 25 | t.toNT(); 26 | }); 27 | }); 28 | it("n3", function(){ 29 | var t = new rdf.Variable('name'); 30 | assert.strictEqual(t.n3(), '?name'); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /test/builtins-Number.test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var rdf = require('..'); 3 | var util = require('util'); 4 | 5 | function addNumberTest(t, nodeType, datatype, n3rep){ 6 | it('('+util.inspect(t)+')', function(){ 7 | assert.strictEqual(typeof t.n3, 'function'); 8 | assert.strictEqual(typeof t.toNT, 'function'); 9 | assert.strictEqual(typeof t.nodeType, 'function'); 10 | assert.strictEqual(t.nodeType(), nodeType); 11 | assert.strictEqual(t.n3(), n3rep); 12 | assert.strictEqual(t.datatype, datatype); 13 | }); 14 | } 15 | 16 | describe('Number builtins', function(){ 17 | before(function(){ 18 | rdf.setBuiltins(); 19 | }); 20 | after(function(){ 21 | rdf.unsetBuiltins(); 22 | }); 23 | 24 | addNumberTest(Number.POSITIVE_INFINITY, "TypedLiteral", "http://www.w3.org/2001/XMLSchema#double", '"INF"^^'); 25 | addNumberTest(Number.NEGATIVE_INFINITY, "TypedLiteral", "http://www.w3.org/2001/XMLSchema#double", '"-INF"^^'); 26 | addNumberTest(Number.NaN, "TypedLiteral", "http://www.w3.org/2001/XMLSchema#double", '"NaN"^^'); 27 | addNumberTest(8.5432, "TypedLiteral", "http://www.w3.org/2001/XMLSchema#decimal", '8.5432'); 28 | addNumberTest(42, "TypedLiteral", "http://www.w3.org/2001/XMLSchema#integer", '42'); 29 | addNumberTest(-42, "TypedLiteral", "http://www.w3.org/2001/XMLSchema#integer", '-42'); 30 | addNumberTest(0, "TypedLiteral", "http://www.w3.org/2001/XMLSchema#integer", '0'); 31 | }); 32 | -------------------------------------------------------------------------------- /test/builtins-Object.test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var rdf = require('..'); 3 | var env = rdf.environment; 4 | 5 | function triple(s, p, o){ 6 | // Don't normally use `new rdf.BlankNode`, except where determinism in output is needed 7 | return rdf.environment.createTriple( 8 | typeof s=='string' ? (s.substring(0,2)=='_:' ? new rdf.BlankNode(s) : rdf.environment.createNamedNode(s)) : s , 9 | typeof p=='string' ? (p.substring(0,2)=='_:' ? new rdf.BlankNode(p) : rdf.environment.createNamedNode(p)) : p , 10 | typeof o=='string' ? (o.substring(0,2)=='_:' ? new rdf.BlankNode(o) : rdf.environment.createNamedNode(o)) : o 11 | ); 12 | } 13 | 14 | function generateRefTest(subject, topic, expectedn3, expectedNT, expectedtriples){ 15 | // Setup tests 16 | var expectedGraph = new rdf.Graph; 17 | expectedGraph.addAll(expectedtriples); 18 | 19 | // Test interface 20 | it('('+subject+').ref() methods', function(){ 21 | var t = topic().ref(subject); 22 | assert.equal(typeof t.n3, 'function'); 23 | assert.equal(typeof t.toNT, 'function'); 24 | assert.equal(typeof t.graphify, 'function'); 25 | }); 26 | it('('+subject+').ref().graphify()', function(){ 27 | var t = topic().ref(subject); 28 | // test graphify 29 | var outputGraph = t.graphify(); 30 | // Have the data, compare 31 | var expectedTriples = expectedGraph.toArray().sort(); 32 | var outputTriples = outputGraph.toArray().sort(); 33 | if(!expectedGraph.equals(outputGraph)){ 34 | assert.equal(outputTriples.join('\n'), expectedTriples.join('\n')); 35 | assert(expectedGraph.equals(outputGraph)); 36 | } 37 | }); 38 | it('('+subject+').ref().n3() expected output', function(){ 39 | var t = topic().ref(subject); 40 | var n3 = t.n3(); 41 | // test n3 42 | assert.equal(n3, expectedn3); 43 | }); 44 | it('('+subject+').ref().n3() parse graph', function(){ 45 | var t = topic().ref(subject); 46 | var n3 = t.n3(); 47 | // Parse the generated n3 as Turtle 48 | var outputGraph = env.createGraph(); 49 | var parser = new rdf.TurtleParser(t.getProfile()); 50 | parser.parse(n3, undefined, 'http://example.com/', null, outputGraph); 51 | // Have the data, compare 52 | var expectedTriples = expectedGraph.toArray().sort(); 53 | var outputTriples = outputGraph.toArray().sort(); 54 | if(!expectedGraph.equals(outputGraph)){ 55 | assert.equal(outputTriples.join('\n'), expectedTriples.join('\n')); 56 | assert(expectedGraph.equals(outputGraph)); 57 | } 58 | }); 59 | if(expectedNT) it('('+subject+').ref().toNT() expected output', function(){ 60 | var t = topic().ref(subject); 61 | var NT = t.toNT().replace(/_:b\d+/g, '_:bn'); 62 | // test toNT 63 | assert.equal(NT, expectedNT); 64 | }); 65 | it('('+subject+').ref().toNT() parsed graph', function(){ 66 | var t = topic().ref(subject); 67 | var NT = t.toNT(); 68 | // Parse the generated N-Triples 69 | var outputGraph = env.createGraph(); 70 | var parser = new rdf.TurtleParser; 71 | parser.parse(NT, undefined, 'http://example.com/', null, outputGraph); 72 | // Have the data, compare 73 | var expectedTriples = expectedGraph.toArray().sort(); 74 | var outputTriples = outputGraph.toArray().sort(); 75 | if(!expectedGraph.equals(outputGraph)){ 76 | assert.equal(outputTriples.join('\n'), expectedTriples.join('\n')); 77 | assert(expectedGraph.equals(outputGraph)); 78 | } 79 | }); 80 | } 81 | 82 | describe('Object builtins', function(){ 83 | before(function(){ 84 | rdf.setBuiltins(); 85 | }); 86 | after(function(){ 87 | rdf.unsetBuiltins(); 88 | }); 89 | 90 | describe('().ref the a keyword', function(){ 91 | generateRefTest('_:topic1', 92 | function(){ 93 | return {a: 'rdfs:Class'}; 94 | }, 95 | '_:topic1 rdf:type rdfs:Class .', 96 | '_:topic1 .', 97 | [ triple('_:topic1', "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", 'http://www.w3.org/2000/01/rdf-schema#Class') ] 98 | ); 99 | }); 100 | describe('().ref integer', function(){ 101 | generateRefTest('_:integer', 102 | function(){ 103 | return {rdf$value: 42}; 104 | }, 105 | '_:integer rdf:value 42 .', 106 | '_:integer "42"^^ .', 107 | [ triple('_:integer', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#value', new rdf.Literal('42','http://www.w3.org/2001/XMLSchema#integer')) ] 108 | ); 109 | }); 110 | describe('().ref decimal', function(){ 111 | generateRefTest('_:decimal', 112 | function(){ 113 | return {rdf$value: 4.4}; 114 | }, 115 | '_:decimal rdf:value 4.4 .', 116 | '_:decimal "4.4"^^ .', 117 | [ triple('_:decimal', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#value', new rdf.Literal('4.4','http://www.w3.org/2001/XMLSchema#decimal')) ] 118 | ); 119 | }); 120 | describe('(_:topic4).ref string spaces', function(){ 121 | generateRefTest('_:topic4', 122 | function(){ 123 | return {rdf$value: env.createLiteral("A string 2000.")}; 124 | }, 125 | '_:topic4 rdf:value "A string 2000." .', 126 | '_:topic4 "A string 2000." .', 127 | [ triple('_:topic4', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#value', new rdf.Literal("A string 2000.")) ] 128 | ); 129 | }); 130 | describe('(_:topic5).ref language literal', function(){ 131 | generateRefTest('_:topic5', 132 | function(){ 133 | return {rdf$value: "The Hobbit".l('en')}; 134 | }, 135 | '_:topic5 rdf:value "The Hobbit"@en .', 136 | '_:topic5 "The Hobbit"@en .', 137 | [ triple('_:topic5', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#value', new rdf.Literal("The Hobbit",'@en')) ] 138 | ); 139 | }); 140 | describe('(_:topic6).ref', function(){ 141 | // Normally, use env.createBlankNode 142 | // For deterministic tests, we use BlankNode with a name 143 | generateRefTest('_:topic6', 144 | function(){ 145 | return {rdf$value: new rdf.BlankNode('_:target')}; 146 | }, 147 | '_:topic6 rdf:value _:target .', 148 | '_:topic6 _:target .', 149 | [ triple('_:topic6', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#value', '_:target') ] 150 | ); 151 | }); 152 | describe('(_:mval).ref multiple values', function(){ 153 | // Normally, use env.createBlankNode 154 | // For deterministic tests, we use BlankNode with a name 155 | generateRefTest('_:mval', 156 | function(){ return { 157 | rdfs$label: [ 158 | env.createLiteral("Harry Potter and the Philosopher's Stone", '@en'), 159 | env.createLiteral("Harry Potter and the Sorcerer's Stone", "@en-US"), 160 | ], 161 | }; }, 162 | '_:mval rdfs:label "Harry Potter and the Philosopher\'s Stone"@en, "Harry Potter and the Sorcerer\'s Stone"@en-US .', 163 | null, 164 | [ 165 | triple('_:mval', 'http://www.w3.org/2000/01/rdf-schema#label', new rdf.Literal("Harry Potter and the Philosopher's Stone", '@en')), 166 | triple('_:mval', 'http://www.w3.org/2000/01/rdf-schema#label', new rdf.Literal("Harry Potter and the Sorcerer's Stone", '@en-US')), 167 | ] 168 | ); 169 | }); 170 | describe('(_:mval).ref multiple values with bnode', function(){ 171 | // Normally, use env.createBlankNode 172 | // For deterministic tests, we use BlankNode with a name 173 | generateRefTest('_:mval', 174 | function(){ return { 175 | rdfs$label: [ 176 | env.createLiteral("Harry Potter and the Philosopher's Stone", '@en'), 177 | { 178 | rdf$type: "http://example.com/", 179 | rdfs$label: new rdf.Literal("Harry Potter and the Sorcerer's Stone", '@en-US'), 180 | }, 181 | ], 182 | }; }, 183 | '_:mval rdfs:label "Harry Potter and the Philosopher\'s Stone"@en, [\n\t\trdf:type ;\n\t\trdfs:label "Harry Potter and the Sorcerer\'s Stone"@en-US\n\t\t] .', 184 | null, 185 | [ 186 | triple('_:mval', 'http://www.w3.org/2000/01/rdf-schema#label', new rdf.Literal("Harry Potter and the Philosopher's Stone", '@en')), 187 | triple('_:mval', 'http://www.w3.org/2000/01/rdf-schema#label', new rdf.BlankNode('_:a')), 188 | triple('_:a', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', new rdf.NamedNode('http://example.com/')), 189 | triple('_:a', 'http://www.w3.org/2000/01/rdf-schema#label', new rdf.Literal("Harry Potter and the Sorcerer's Stone", '@en-US')), 190 | ]); 191 | }); 192 | describe('(_:topic7).ref objects are unlabeled blank nodes', function(){ 193 | var b1 = new rdf.BlankNode('_:b1'); 194 | var b2 = new rdf.BlankNode('_:target'); 195 | generateRefTest('_:topic7', 196 | function(){ 197 | return {rdf$value: {rdf$value: '_:target'}}; 198 | }, 199 | '_:topic7 rdf:value [\n\t\trdf:value _:target\n\t\t] .', 200 | '_:topic7 _:bn .\n_:bn _:target .', 201 | [ 202 | triple('_:topic7', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#value', b1), 203 | triple(b1, 'http://www.w3.org/1999/02/22-rdf-syntax-ns#value', b2), 204 | ] 205 | ); 206 | }); 207 | describe('(_:set).ref lists with @set', function(){ 208 | generateRefTest('_:set', 209 | function(){ 210 | return {rdf$value: {'@set': ['http://example.com/1', 'http://example.com/2']}}; 211 | }, 212 | '_:set rdf:value , .', 213 | '_:set .\n_:set .', 214 | [ 215 | triple('_:set', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#value', 'http://example.com/1'), 216 | triple('_:set', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#value', 'http://example.com/2'), 217 | ] 218 | ); 219 | }); 220 | describe('(_:list).ref collections with @list', function(){ 221 | var b1 = new rdf.BlankNode('_:b1'); 222 | var b2 = new rdf.BlankNode('_:target'); 223 | generateRefTest('_:list', 224 | function(){ 225 | return {rdf$value: {'@list': ['http://example.com/1', 'http://example.com/2']}}; 226 | }, 227 | '_:list rdf:value ( ) .', 228 | null, 229 | [ 230 | triple('_:list', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#value', b1), 231 | triple(b1, 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'http://example.com/1'), 232 | triple(b1, 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', b2), 233 | triple(b2, 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'http://example.com/2'), 234 | triple(b2, 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'), 235 | ] 236 | ); 237 | }); 238 | describe('(dbr:Albert_Einstein).ref', function(){ 239 | /* 240 | dbp:dateOfBirth "1879-03-14"^^xsd:date ; # we only produce xsd:dateTime 241 | foaf:depiction . 242 | */ 243 | generateRefTest( 'http://dbpedia.org/resource/Albert_Einstein', 244 | function(){ 245 | return { 246 | $context: { 247 | 'dbr': 'http://dbpedia.org/resource/', 248 | 'dbp': 'http://dbpedia.org/property/', 249 | 'foaf': 'http://xmlns.com/foaf/0.1/', 250 | }, 251 | dbp$dateOfBirth: new Date("1879-03-14"), 252 | 'foaf:depiction': 'http://en.wikipedia.org/wiki/Image:Albert_Einstein_Head.jpg', 253 | }; 254 | }, 255 | 'dbr:Albert_Einstein\n\tdbp:dateOfBirth "1879-03-14T00:00:00Z"^^xsd:dateTime;\n\tfoaf:depiction .', 256 | ' "1879-03-14T00:00:00Z"^^ .\n .', 257 | [ 258 | triple("http://dbpedia.org/resource/Albert_Einstein", "http://xmlns.com/foaf/0.1/depiction", 'http://en.wikipedia.org/wiki/Image:Albert_Einstein_Head.jpg'), 259 | triple("http://dbpedia.org/resource/Albert_Einstein", "http://dbpedia.org/property/dateOfBirth", new rdf.Literal("1879-03-14T00:00:00Z",rdf.xsdns('dateTime'))), 260 | ] 261 | ); 262 | }); 263 | describe('(webr3).ref()', function(){ 264 | generateRefTest('http://webr3.org/#me', 265 | function(){ 266 | return { 267 | '@id': 'http://webr3.org/#me', 268 | '@context': { 269 | '@vocab': 'http://xmlns.com/foaf/0.1/', 270 | 'dbr': 'http://dbpedia.org/resource/', 271 | 'dbp': 'http://dbpedia.org/property/', 272 | 'foaf': 'http://xmlns.com/foaf/0.1/', 273 | }, 274 | a: 'foaf:Person', // a CURIE 275 | foaf$name: env.createLiteral('Nathan'), 276 | foaf$age: 2018 - 1981, 277 | foaf$holdsAccount: { 278 | a: 'OnlineAccount', 279 | rdfs$label: rdf.environment.createLiteral("Nathan's twitter account", 'en'), 280 | accountName: env.createLiteral('webr3'), 281 | homepage: 'http://twitter.com/webr3', 282 | }, 283 | foaf$nick: [env.createLiteral('webr3'), env.createLiteral('nath')], 284 | foaf$homepage: 'http://webr3.org/', 285 | }; 286 | }, 287 | '\n' 288 | + '\trdf:type foaf:Person;\n' 289 | + '\tfoaf:name "Nathan";\n' 290 | + '\tfoaf:age 37;\n' 291 | + '\tfoaf:holdsAccount [\n' 292 | + '\t\trdf:type foaf:OnlineAccount;\n' 293 | + '\t\trdfs:label "Nathan\'s twitter account"@en;\n' 294 | + '\t\tfoaf:accountName "webr3";\n' 295 | + '\t\tfoaf:homepage \n' 296 | + '\t\t];\n' 297 | + '\tfoaf:nick "webr3", "nath";\n' 298 | + '\tfoaf:homepage .' 299 | , 300 | null, 301 | [ 302 | triple("http://webr3.org/#me", 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', 'http://xmlns.com/foaf/0.1/Person'), 303 | triple("http://webr3.org/#me", "http://xmlns.com/foaf/0.1/name", new rdf.Literal("Nathan")), 304 | triple("http://webr3.org/#me", "http://xmlns.com/foaf/0.1/age", new rdf.Literal("37",rdf.xsdns('integer'))), 305 | triple("http://webr3.org/#me", "http://xmlns.com/foaf/0.1/homepage", 'http://webr3.org/'), 306 | triple("http://webr3.org/#me", "http://xmlns.com/foaf/0.1/holdsAccount", '_:account'), 307 | triple("http://webr3.org/#me", "http://xmlns.com/foaf/0.1/nick", new rdf.Literal('webr3')), 308 | triple("http://webr3.org/#me", "http://xmlns.com/foaf/0.1/nick", new rdf.Literal('nath')), 309 | triple("_:account", "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", 'http://xmlns.com/foaf/0.1/OnlineAccount'), 310 | triple("_:account", "http://www.w3.org/2000/01/rdf-schema#label", new rdf.Literal('Nathan\'s twitter account', '@en')), 311 | triple("_:account", "http://xmlns.com/foaf/0.1/accountName", new rdf.Literal('webr3')), 312 | triple("_:account", "http://xmlns.com/foaf/0.1/homepage", 'http://twitter.com/webr3'), 313 | ]); 314 | }); 315 | }); 316 | -------------------------------------------------------------------------------- /test/builtins-String.test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var rdf = require('..'); 3 | 4 | describe('String builtins', function(){ 5 | before(function(){ 6 | rdf.setBuiltins(); 7 | }); 8 | after(function(){ 9 | rdf.unsetBuiltins(); 10 | }); 11 | 12 | it("String.prototype.profile", function(){ 13 | var t = "".profile; 14 | assert(t instanceof rdf.Profile); 15 | assert.strictEqual(t, rdf.environment); 16 | }); 17 | it("String.resolve rdf:type", function(){ 18 | var t = "rdf:type".resolve(); 19 | assert.strictEqual(t, "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"); 20 | }); 21 | it("String.resolve rdfs:Class", function(){ 22 | var t = "rdfs:Class".resolve(); 23 | assert.strictEqual(t, "http://www.w3.org/2000/01/rdf-schema#Class"); 24 | assert.equal(typeof t, 'string'); 25 | }); 26 | it("String.resolve unknown CURIE", function(){ 27 | var t = "unknownprefixfoo2:bar".resolve(); 28 | assert.strictEqual(t, "unknownprefixfoo2:bar"); 29 | assert.equal(t, "unknownprefixfoo2:bar"); 30 | assert.equal(typeof t, "string"); 31 | assert.ok("unknownprefixfoo2:bar".equals(t)); 32 | }); 33 | it("String.resolve defined CURIE", function(){ 34 | assert.strictEqual("unknownprefixfoo2:answer".resolve(), 'unknownprefixfoo2:answer'); 35 | rdf.environment.setPrefix("unknownprefixfoo2", "http://example.com/2/ex/42/"); 36 | var t = "unknownprefixfoo2:answer".resolve(); 37 | assert.strictEqual(t, "http://example.com/2/ex/42/answer"); 38 | assert.strictEqual(t.valueOf(), "http://example.com/2/ex/42/answer"); 39 | assert.ok("http://example.com/2/ex/42/answer".equals(t)); 40 | rdf.environment.setPrefix("unknownprefixfoo2", null); 41 | assert.strictEqual("unknownprefixfoo2:answer".resolve(), 'unknownprefixfoo2:answer'); 42 | }); 43 | it("String.resolve defined term", function(){ 44 | assert.strictEqual("term2".resolve(), 'term2'); 45 | rdf.environment.setTerm("term2", "http://example.com/2/ex/42"); 46 | var t = "term2".resolve(); 47 | assert.strictEqual(t, "http://example.com/2/ex/42"); 48 | //assert.strictEqual(t.valueOf(), "http://example.com/2/ex/42"); 49 | //assert.ok("http://example.com/2/ex/42".equals(t)); 50 | rdf.environment.setTerm("term2", null); 51 | assert.strictEqual("term2".resolve(), 'term2'); 52 | }); 53 | it("String.resolve http: URI", function(){ 54 | assert.strictEqual("http://example.com/foo".resolve(), 'http://example.com/foo'); 55 | }); 56 | it("String.resolve https: URI", function(){ 57 | assert.strictEqual("https://example.com/foo".resolve(), 'https://example.com/foo'); 58 | }); 59 | it("String.resolve urn:uuid: URI", function(){ 60 | assert.strictEqual("urn:uuid:76E923E9-67CD-47AC-AB72-1C339A31CE57".resolve(), 'urn:uuid:76E923E9-67CD-47AC-AB72-1C339A31CE57'); 61 | }); 62 | it("string.resolve() resolved URI", function(){ 63 | var t = "http://slashdot.org/".resolve(); 64 | assert.strictEqual(t, 'http://slashdot.org/'); 65 | }); 66 | it("string.resolve() bnode syntax", function(){ 67 | var t = "_:someBlankNode".resolve(); 68 | assert.strictEqual(t, '_:someBlankNode'); 69 | }); 70 | it("string.n3()", function(){ 71 | var t = "http://slashdot.org/".n3(); 72 | assert.strictEqual(t, ''); 73 | }); 74 | it("string.toNT()", function(){ 75 | var t = "http://slashdot.org/".toNT(); 76 | assert.strictEqual(t, ''); 77 | }); 78 | it('string.l().n3()', function(){ 79 | var t = "PLAINLITERAL".l().n3(); 80 | assert.strictEqual(t, '"PLAINLITERAL"'); 81 | }); 82 | it('string.l().toNT()', function(){ 83 | var t = "PLAINLITERAL".l().toNT(); 84 | assert.strictEqual(t, '"PLAINLITERAL"'); 85 | }); 86 | it('string.l().n3()', function(){ 87 | var t = "PLAIN LITERAL WITH A SPACE".l().n3(); 88 | assert.strictEqual(t, '"PLAIN LITERAL WITH A SPACE"'); 89 | }); 90 | it('string.l().toNT()', function(){ 91 | var t = "PLAIN LITERAL WITH A SPACE".l().toNT(); 92 | assert.strictEqual(t, '"PLAIN LITERAL WITH A SPACE"'); 93 | }); 94 | it('string.l(en).n3()', function(){ 95 | var t = "English language literal".l("en").n3(); 96 | assert.strictEqual(t, '"English language literal"@en'); 97 | }); 98 | it('string.l(en).toNT()', function(){ 99 | var t = "English language literal".l("en").toNT(); 100 | assert.strictEqual(t, '"English language literal"@en'); 101 | }); 102 | it('string.tl(xsd:string).n3()', function(){ 103 | var t = "XSD String".tl("xsd:string".resolve()).n3(); 104 | assert.strictEqual(t, '"XSD String"'); 105 | }); 106 | it('string.tl(xsd:string).toNT()', function(){ 107 | var t = "XSD String".tl("xsd:string".resolve()).toNT(); 108 | assert.strictEqual(t, '"XSD String"'); 109 | }); 110 | }); 111 | -------------------------------------------------------------------------------- /test/environment.test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var rdf = require('..'); 3 | 4 | describe('rdf.environment', function(){ 5 | it("instance", function(){ 6 | var t = rdf.environment; 7 | assert(t instanceof rdf.RDFEnvironment); 8 | }); 9 | it("environment.prefixes.resolve rdf:type", function(){ 10 | var t = rdf.environment.prefixes.resolve("rdf:type"); 11 | assert.strictEqual(t, "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"); 12 | }); 13 | it("environment.prefixes.resolve rdfs:Class", function(){ 14 | var t = rdf.environment.prefixes.resolve("rdfs:Class"); 15 | assert.strictEqual(t, "http://www.w3.org/2000/01/rdf-schema#Class"); 16 | }); 17 | it("environment.prefixes.resolve unknown CURIE", function(){ 18 | var t = rdf.environment.prefixes.resolve("unkfoo:bar"); 19 | assert.equal(t, null); 20 | }); 21 | it("environment.prefixes.resolve default prefix", function(){ 22 | var t = rdf.environment.prefixes.resolve(":bar"); 23 | assert.equal(t, null); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /test/ns.test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var rdf = require('..'); 3 | 4 | describe('ns', function(){ 5 | it('rdf.ns', function(){ 6 | var foaf = rdf.ns('http://xmlns.com/foaf/0.1/'); 7 | assert.equal(foaf('name'), 'http://xmlns.com/foaf/0.1/name'); 8 | }); 9 | it('rdf.ns expects string', function(){ 10 | assert.throws(function(){ 11 | rdf.ns(1); 12 | }); 13 | }); 14 | it('rdf.ns output function expects string', function(){ 15 | var foaf = rdf.ns('http://xmlns.com/foaf/0.1/'); 16 | assert.throws(function(){ 17 | foaf(2); 18 | }); 19 | }); 20 | }); 21 | describe('ns builtins', function(){ 22 | it('rdf.rdfns', function(){ 23 | assert.equal(rdf.rdfns('type'), 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'); 24 | }); 25 | it('rdf.rdfsns', function(){ 26 | assert.equal(rdf.rdfsns('Class'), 'http://www.w3.org/2000/01/rdf-schema#Class'); 27 | }); 28 | it('rdf.xsdns', function(){ 29 | assert.equal(rdf.xsdns('integer'), 'http://www.w3.org/2001/XMLSchema#integer'); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /test/parse.test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var rdf = require('..'); 3 | var env = rdf.environment; 4 | 5 | function triple(s, p, o){ 6 | // Don't normally use `new rdf.BlankNode`, except where determinism in output is needed 7 | return rdf.environment.createTriple( 8 | typeof s=='string' ? (s.substring(0,2)=='_:' ? new rdf.BlankNode(s) : rdf.environment.createNamedNode(s)) : s , 9 | typeof p=='string' ? (p.substring(0,2)=='_:' ? new rdf.BlankNode(p) : rdf.environment.createNamedNode(p)) : p , 10 | typeof o=='string' ? (o.substring(0,2)=='_:' ? new rdf.BlankNode(o) : rdf.environment.createNamedNode(o)) : o 11 | ); 12 | } 13 | 14 | function generateRefTest(subject, topic, expectedn3, expectedNT, expectedtriples){ 15 | // Setup tests 16 | var expectedGraph = new rdf.Graph; 17 | expectedGraph.addAll(expectedtriples); 18 | 19 | // Test interface 20 | it('parse('+subject+') methods', function(){ 21 | var t = rdf.parse(topic(), subject); 22 | assert.equal(typeof t.n3, 'function'); 23 | assert.equal(typeof t.toNT, 'function'); 24 | assert.equal(typeof t.graphify, 'function'); 25 | }); 26 | it('parse('+subject+').graphify()', function(){ 27 | var t = rdf.parse(topic(), subject); 28 | // test graphify 29 | var outputGraph = t.graphify(); 30 | // Have the data, compare 31 | var expectedTriples = expectedGraph.toArray().sort(); 32 | var outputTriples = outputGraph.toArray().sort(); 33 | if(!expectedGraph.isomorphic(outputGraph)){ 34 | assert.equal(outputTriples.join('\n'), expectedTriples.join('\n')); 35 | assert(expectedGraph.isomorphic(outputGraph)); 36 | } 37 | }); 38 | it('parse('+subject+').n3() expected output', function(){ 39 | var t = rdf.parse(topic(), subject); 40 | var n3 = t.n3(); 41 | // test n3 42 | assert.equal(n3, expectedn3); 43 | }); 44 | it('parse('+subject+').n3() parse graph', function(){ 45 | var t = rdf.parse(topic(), subject); 46 | var n3 = t.n3(); 47 | // Parse the generated n3 as Turtle 48 | var outputGraph = env.createGraph(); 49 | var parser = new rdf.TurtleParser(t.getProfile()); 50 | parser.parse(n3, undefined, 'http://example.com/', null, outputGraph); 51 | // Have the data, compare 52 | var expectedTriples = expectedGraph.toArray().sort(); 53 | var outputTriples = outputGraph.toArray().sort(); 54 | if(!expectedGraph.isomorphic(outputGraph)){ 55 | assert.equal(outputTriples.join('\n'), expectedTriples.join('\n')); 56 | assert(expectedGraph.isomorphic(outputGraph)); 57 | } 58 | }); 59 | if(expectedNT) it('parse('+subject+').toNT() expected output', function(){ 60 | var t = rdf.parse(topic(), subject); 61 | var NT = t.toNT().replace(/_:b\d+/g, '_:bn'); 62 | // test toNT 63 | assert.equal(NT, expectedNT); 64 | }); 65 | it('parse('+subject+').toNT() parsed graph', function(){ 66 | var t = rdf.parse(topic(), subject); 67 | var NT = t.toNT(); 68 | // Parse the generated N-Triples 69 | var outputGraph = env.createGraph(); 70 | var parser = new rdf.TurtleParser; 71 | parser.parse(NT, undefined, 'http://example.com/', null, outputGraph); 72 | // Have the data, compare 73 | var expectedTriples = expectedGraph.toArray().sort(); 74 | var outputTriples = outputGraph.toArray().sort(); 75 | if(!expectedGraph.isomorphic(outputGraph)){ 76 | assert.equal(outputTriples.join('\n'), expectedTriples.join('\n')); 77 | assert(expectedGraph.isomorphic(outputGraph)); 78 | } 79 | }); 80 | } 81 | 82 | describe('parse', function(){ 83 | describe('parse(_:topic1)', function(){ 84 | generateRefTest('_:topic1', 85 | function(){ 86 | return {a: 'rdfs:Class'}; 87 | }, 88 | '_:topic1 rdf:type rdfs:Class .', 89 | '_:topic1 .', 90 | [ triple('_:topic1', "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", 'http://www.w3.org/2000/01/rdf-schema#Class') ] 91 | ); 92 | }); 93 | describe('parse(_:integer)', function(){ 94 | generateRefTest('_:integer', 95 | function(){ 96 | return {rdf$value: 42}; 97 | }, 98 | '_:integer rdf:value 42 .', 99 | '_:integer "42"^^ .', 100 | [ triple('_:integer', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#value', new rdf.Literal('42','http://www.w3.org/2001/XMLSchema#integer')) ] 101 | ); 102 | }); 103 | describe('parse(_:decimal)', function(){ 104 | generateRefTest('_:decimal', 105 | function(){ 106 | return {rdf$value: 4.4}; 107 | }, 108 | '_:decimal rdf:value 4.4 .', 109 | '_:decimal "4.4"^^ .', 110 | [ triple('_:decimal', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#value', new rdf.Literal('4.4','http://www.w3.org/2001/XMLSchema#decimal')) ] 111 | ); 112 | }); 113 | describe('parse(_:topic4) string spaces', function(){ 114 | generateRefTest('_:topic4', 115 | function(){ 116 | return {rdf$value: env.createLiteral("A string 2000.")}; 117 | }, 118 | '_:topic4 rdf:value "A string 2000." .', 119 | '_:topic4 "A string 2000." .', 120 | [ triple('_:topic4', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#value', new rdf.Literal("A string 2000.")) ] 121 | ); 122 | }); 123 | describe('parse(_:topic5) language literal', function(){ 124 | generateRefTest('_:topic5', 125 | function(){ 126 | return {rdf$value: env.createLiteral("The Hobbit", '@en')}; 127 | }, 128 | '_:topic5 rdf:value "The Hobbit"@en .', 129 | '_:topic5 "The Hobbit"@en .', 130 | [ triple('_:topic5', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#value', new rdf.Literal("The Hobbit",'@en')) ] 131 | ); 132 | }); 133 | describe('parse(_:topic6)', function(){ 134 | // Normally, use env.createBlankNode 135 | // For deterministic tests, we use BlankNode with a name 136 | generateRefTest('_:topic6', 137 | function(){ 138 | return {rdf$value: new rdf.BlankNode('_:target')}; 139 | }, 140 | '_:topic6 rdf:value _:target .', 141 | '_:topic6 _:target .', 142 | [ triple('_:topic6', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#value', '_:target') ] 143 | ); 144 | }); 145 | describe('parse(_:mval) multiple values', function(){ 146 | // Normally, use env.createBlankNode 147 | // For deterministic tests, we use BlankNode with a name 148 | generateRefTest('_:mval', 149 | function(){ return { 150 | rdfs$label: [ 151 | env.createLiteral("Harry Potter and the Philosopher's Stone", '@en'), 152 | env.createLiteral("Harry Potter and the Sorcerer's Stone", "@en-US"), 153 | ], 154 | }; }, 155 | '_:mval rdfs:label "Harry Potter and the Philosopher\'s Stone"@en, "Harry Potter and the Sorcerer\'s Stone"@en-US .', 156 | null, 157 | [ 158 | triple('_:mval', 'http://www.w3.org/2000/01/rdf-schema#label', new rdf.Literal("Harry Potter and the Philosopher's Stone", '@en')), 159 | triple('_:mval', 'http://www.w3.org/2000/01/rdf-schema#label', new rdf.Literal("Harry Potter and the Sorcerer's Stone", '@en-US')), 160 | ] 161 | ); 162 | }); 163 | describe('parse(_:mval) multiple values with bnode', function(){ 164 | // Normally, use env.createBlankNode 165 | // For deterministic tests, we use BlankNode with a name 166 | generateRefTest('_:mval', 167 | function(){ return { 168 | rdfs$label: [ 169 | env.createLiteral("Harry Potter and the Philosopher's Stone", '@en'), 170 | { 171 | rdf$type: "http://example.com/", 172 | rdfs$label: new rdf.Literal("Harry Potter and the Sorcerer's Stone", '@en-US'), 173 | }, 174 | ], 175 | }; }, 176 | '_:mval rdfs:label "Harry Potter and the Philosopher\'s Stone"@en, [\n\t\trdf:type ;\n\t\trdfs:label "Harry Potter and the Sorcerer\'s Stone"@en-US\n\t\t] .', 177 | null, 178 | [ 179 | triple('_:mval', 'http://www.w3.org/2000/01/rdf-schema#label', new rdf.Literal("Harry Potter and the Philosopher's Stone", '@en')), 180 | triple('_:mval', 'http://www.w3.org/2000/01/rdf-schema#label', new rdf.BlankNode('_:a')), 181 | triple('_:a', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', new rdf.NamedNode('http://example.com/')), 182 | triple('_:a', 'http://www.w3.org/2000/01/rdf-schema#label', new rdf.Literal("Harry Potter and the Sorcerer's Stone", '@en-US')), 183 | ] 184 | ); 185 | }); 186 | describe('parse(_:topic7) objects are unlabeled blank nodes', function(){ 187 | var b1 = new rdf.BlankNode('_:b1'); 188 | var b2 = new rdf.BlankNode('_:target'); 189 | generateRefTest('_:topic7', 190 | function(){ 191 | return {rdf$value: {rdf$value: '_:target'}}; 192 | }, 193 | '_:topic7 rdf:value [\n\t\trdf:value _:target\n\t\t] .', 194 | '_:topic7 _:bn .\n_:bn _:target .', 195 | [ 196 | triple('_:topic7', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#value', b1), 197 | triple(b1, 'http://www.w3.org/1999/02/22-rdf-syntax-ns#value', b2), 198 | ]); 199 | }); 200 | describe('parse(_:set) lists with @set', function(){ 201 | generateRefTest('_:set', 202 | function(){ 203 | return {rdf$value: {'@set': ['http://example.com/1', 'http://example.com/2']}}; 204 | }, 205 | '_:set rdf:value , .', 206 | '_:set .\n_:set .', 207 | [ 208 | triple('_:set', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#value', 'http://example.com/1'), 209 | triple('_:set', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#value', 'http://example.com/2'), 210 | ]); 211 | }); 212 | describe('parse(_:list) collections with @list', function(){ 213 | var b1 = new rdf.BlankNode('_:b1'); 214 | var b2 = new rdf.BlankNode('_:target'); 215 | generateRefTest('_:list', 216 | function(){ 217 | return {rdf$value: {'@list': ['http://example.com/1', 'http://example.com/2']}}; 218 | }, 219 | '_:list rdf:value ( ) .', 220 | null, 221 | [ 222 | triple('_:list', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#value', b1), 223 | triple(b1, 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'http://example.com/1'), 224 | triple(b1, 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', b2), 225 | triple(b2, 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'http://example.com/2'), 226 | triple(b2, 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'), 227 | ] 228 | ); 229 | }); 230 | describe('parse(dbr:Albert_Einstein)', function(){ 231 | /* 232 | dbp:dateOfBirth "1879-03-14"^^xsd:date ; # we only produce xsd:dateTime 233 | foaf:depiction . 234 | */ 235 | generateRefTest( 'http://dbpedia.org/resource/Albert_Einstein', 236 | function(){ 237 | return { 238 | $context: { 239 | 'dbr': 'http://dbpedia.org/resource/', 240 | 'dbp': 'http://dbpedia.org/property/', 241 | 'foaf': 'http://xmlns.com/foaf/0.1/', 242 | }, 243 | dbp$dateOfBirth: new Date("1879-03-14"), 244 | 'foaf:depiction': 'http://en.wikipedia.org/wiki/Image:Albert_Einstein_Head.jpg', 245 | }; 246 | }, 247 | 'dbr:Albert_Einstein\n\tdbp:dateOfBirth "1879-03-14T00:00:00Z"^^xsd:dateTime;\n\tfoaf:depiction .', 248 | ' "1879-03-14T00:00:00Z"^^ .\n .', 249 | [ 250 | triple("http://dbpedia.org/resource/Albert_Einstein", "http://xmlns.com/foaf/0.1/depiction", 'http://en.wikipedia.org/wiki/Image:Albert_Einstein_Head.jpg'), 251 | triple("http://dbpedia.org/resource/Albert_Einstein", "http://dbpedia.org/property/dateOfBirth", new rdf.Literal("1879-03-14T00:00:00Z",rdf.xsdns('dateTime'))), 252 | ] 253 | ); 254 | }); 255 | describe('parse(webr3)', function(){ 256 | generateRefTest('http://webr3.org/#me', 257 | function(){ 258 | return { 259 | '@id': 'http://webr3.org/#me', 260 | '@context': { 261 | '@vocab': 'http://xmlns.com/foaf/0.1/', 262 | 'dbr': 'http://dbpedia.org/resource/', 263 | 'dbp': 'http://dbpedia.org/property/', 264 | 'foaf': 'http://xmlns.com/foaf/0.1/', 265 | }, 266 | a: 'foaf:Person', // a CURIE 267 | foaf$name: env.createLiteral('Nathan'), 268 | foaf$age: 2018 - 1981, 269 | foaf$holdsAccount: { 270 | a: 'OnlineAccount', 271 | rdfs$label: rdf.environment.createLiteral("Nathan's twitter account", 'en'), 272 | accountName: env.createLiteral('webr3'), 273 | homepage: 'http://twitter.com/webr3', 274 | }, 275 | foaf$nick: [env.createLiteral('webr3'), env.createLiteral('nath')], 276 | foaf$homepage: 'http://webr3.org/', 277 | }; 278 | }, 279 | '\n' 280 | + '\trdf:type foaf:Person;\n' 281 | + '\tfoaf:name "Nathan";\n' 282 | + '\tfoaf:age 37;\n' 283 | + '\tfoaf:holdsAccount [\n' 284 | + '\t\trdf:type foaf:OnlineAccount;\n' 285 | + '\t\trdfs:label "Nathan\'s twitter account"@en;\n' 286 | + '\t\tfoaf:accountName "webr3";\n' 287 | + '\t\tfoaf:homepage \n' 288 | + '\t\t];\n' 289 | + '\tfoaf:nick "webr3", "nath";\n' 290 | + '\tfoaf:homepage .' 291 | , 292 | null, 293 | [ 294 | triple("http://webr3.org/#me", 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', 'http://xmlns.com/foaf/0.1/Person'), 295 | triple("http://webr3.org/#me", "http://xmlns.com/foaf/0.1/name", new rdf.Literal("Nathan")), 296 | triple("http://webr3.org/#me", "http://xmlns.com/foaf/0.1/age", new rdf.Literal("37",rdf.xsdns('integer'))), 297 | triple("http://webr3.org/#me", "http://xmlns.com/foaf/0.1/homepage", 'http://webr3.org/'), 298 | triple("http://webr3.org/#me", "http://xmlns.com/foaf/0.1/holdsAccount", '_:account'), 299 | triple("http://webr3.org/#me", "http://xmlns.com/foaf/0.1/nick", new rdf.Literal('webr3')), 300 | triple("http://webr3.org/#me", "http://xmlns.com/foaf/0.1/nick", new rdf.Literal('nath')), 301 | triple("_:account", "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", 'http://xmlns.com/foaf/0.1/OnlineAccount'), 302 | triple("_:account", "http://www.w3.org/2000/01/rdf-schema#label", new rdf.Literal('Nathan\'s twitter account', '@en')), 303 | triple("_:account", "http://xmlns.com/foaf/0.1/accountName", new rdf.Literal('webr3')), 304 | triple("_:account", "http://xmlns.com/foaf/0.1/homepage", 'http://twitter.com/webr3'), 305 | ] 306 | ); 307 | }); 308 | }); 309 | --------------------------------------------------------------------------------