diff --git a/README.md b/README.md index cf5e554d..3eb3b824 100644 --- a/README.md +++ b/README.md @@ -12,14 +12,14 @@ It offers: [TriG](https://www.w3.org/TR/trig/), [N-Triples](https://www.w3.org/TR/n-triples/), [N-Quads](https://www.w3.org/TR/n-quads/), - [RDF*](https://blog.liu.se/olafhartig/2019/01/10/position-statement-rdf-star-and-sparql-star/) + [RDF-star](https://www.w3.org/2021/12/rdf-star.html) and [Notation3 (N3)](https://www.w3.org/TeamSubmission/n3/) - [**Writing**](#writing) triples/quads to [Turtle](https://www.w3.org/TR/turtle/), [TriG](https://www.w3.org/TR/trig/), [N-Triples](https://www.w3.org/TR/n-triples/), [N-Quads](https://www.w3.org/TR/n-quads/) - and [RDF*](https://blog.liu.se/olafhartig/2019/01/10/position-statement-rdf-star-and-sparql-star/) + and [RDF-star](https://www.w3.org/2021/12/rdf-star.html) - [**Storage**](#storing) of triples/quads in memory Parsing and writing is: @@ -206,16 +206,28 @@ const writer2 = new N3.Writer({ format: 'application/trig' }); ```JavaScript const writer = new N3.Writer(process.stdout, { end: false, prefixes: { c: 'http://example.org/cartoons#' } }); -writer.addQuad( +writer.add(quad( namedNode('http://example.org/cartoons#Tom'), namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), namedNode('http://example.org/cartoons#Cat') -); -writer.addQuad(quad( +)); +writer.add(quad( namedNode('http://example.org/cartoons#Tom'), namedNode('http://example.org/cartoons#name'), literal('Tom') )); + +// Writing a quoted rdf-star triple +writer.add(quad( + quad( + namedNode('http://example.org/animals#Elephants'), + namedNode('http://example.org/skinAttribute#colour'), + namedNode('http://example.org/colours#blue'), + ), + namedNode('http://example.org/saidBy'), + namedNode('http://example.org/Jesse') +)); + writer.end(); ``` @@ -358,16 +370,14 @@ The N3.js parser and writer is fully compatible with the following W3C specifica In addition, the N3.js parser also supports [Notation3 (N3)](https://www.w3.org/TeamSubmission/n3/) (no official specification yet). -The N3.js parser and writer are also fully compatible with the RDF* variants +The N3.js parser and writer are also fully compatible with the RDF-star variants of the W3C specifications. The default mode is permissive -and allows a mixture of different syntaxes, including RDF*. +and allows a mixture of different syntaxes, including RDF-star. Pass a `format` option to the constructor with the name or MIME type of a format for strict, fault-intolerant behavior. -If a format string contains `star` or `*` -(e.g., `turtlestar` or `TriG*`), -RDF* support for that format will be enabled. +To disable RDF-star support pass `rdfStar` to `false` in the constructor. ### Interface specifications The N3.js submodules are compatible with the following [RDF.js](http://rdf.js.org) interfaces: diff --git a/package-lock.json b/package-lock.json index e3ff8bbe..c2f10e65 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,7 @@ "mocha": "^8.0.0", "nyc": "^14.1.1", "pre-commit": "^1.2.2", - "rdf-test-suite": "^1.19.2", + "rdf-test-suite": "^1.20.0", "streamify-string": "^1.0.1", "uglify-js": "^3.14.3" }, @@ -1735,9 +1735,9 @@ "optional": true }, "node_modules/@rdfjs/types": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rdfjs/types/-/types-1.0.1.tgz", - "integrity": "sha512-YxVkH0XrCNG3MWeZxfg596GFe+oorTVusmNxRP6ZHTsGczZ8AGvG3UchRNkg3Fy4MyysI7vBAA5YZbESL+VmHQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rdfjs/types/-/types-1.1.0.tgz", + "integrity": "sha512-5zm8bN2/CC634dTcn/0AhTRLaQRjXDZs3QfcAsQKNturHT7XVWcKy/8p3P5gXl+YkZTAmy7T5M/LyiT/jbkENw==", "dev": true, "dependencies": { "@types/node": "*" @@ -1753,25 +1753,15 @@ } }, "node_modules/@types/json-stable-stringify": { - "version": "1.0.32", - "resolved": "https://registry.npmjs.org/@types/json-stable-stringify/-/json-stable-stringify-1.0.32.tgz", - "integrity": "sha512-q9Q6+eUEGwQkv4Sbst3J4PNgDOvpuVuKj79Hl/qnmBMEIPzB5QoFRUtjcgcg2xNUZyYUGXBk5wYIBKHt0A+Mxw==", + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/@types/json-stable-stringify/-/json-stable-stringify-1.0.34.tgz", + "integrity": "sha512-s2cfwagOQAS8o06TcwKfr9Wx11dNGbH2E9vJz1cqV+a/LOyhWNLUNd6JSRYNzvB4d29UuJX2M0Dj9vE1T8fRXw==", "dev": true }, - "node_modules/@types/log-symbols": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/log-symbols/-/log-symbols-3.0.0.tgz", - "integrity": "sha512-uW/AGf/41aZ1c1dhZ3s063Ii2OqT8EQooZu3t4VCRyR3dqyA2Bg46BcKyZpnWTY7wzm6cayq4jzylnruu4KqSA==", - "deprecated": "This is a stub types definition. log-symbols provides its own type definitions, so you do not need this installed.", - "dev": true, - "dependencies": { - "log-symbols": "*" - } - }, "node_modules/@types/minimist": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.1.tgz", - "integrity": "sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", + "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", "dev": true }, "node_modules/@types/n3": { @@ -1785,25 +1775,31 @@ } }, "node_modules/@types/node": { - "version": "18.6.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.3.tgz", - "integrity": "sha512-6qKpDtoaYLM+5+AFChLhHermMQxc3TOEFIDzrZLPRGHPrLEwqFkkT5Kx3ju05g6X7uDPazz3jHbKPX0KzCjntg==", + "version": "18.11.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", + "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", "dev": true }, "node_modules/@types/readable-stream": { - "version": "2.3.14", - "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.14.tgz", - "integrity": "sha512-8jQ5Mp7bsDJEnW/69i6nAaQMoLwAVJVc7ZRAVTrdh/o6XueQsX38TEvKuYyoQj76/mg7WdlRfMrtl9pDLCJWsg==", + "version": "2.3.15", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.15.tgz", + "integrity": "sha512-oM5JSKQCcICF1wvGgmecmHldZ48OZamtMxcGGVICOJA8o8cahXC1zEVAif8iwoc5j8etxFaRFnf095+CDsuoFQ==", "dev": true, "dependencies": { "@types/node": "*", - "safe-buffer": "*" + "safe-buffer": "~5.1.1" } }, + "node_modules/@types/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, "node_modules/@types/sax": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.1.tgz", - "integrity": "sha512-dqYdvN7Sbw8QT/0Ci5rhjE4/iCMJEM0Y9rHpCu+gGXD9Lwbz28t6HI2yegsB6BoV1sShRMU6lAmAcgRjmFy7LA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-pSAff4IAxJjfAXUG6tFkO7dsSbTmf8CtUpfhhZ5VhkRpC4628tJhh3+V6H1E+/Gs9piSzYKT5yzHO5M4GG9jkw==", "dev": true, "dependencies": { "@types/node": "*" @@ -3999,9 +3995,9 @@ } }, "node_modules/http-link-header": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/http-link-header/-/http-link-header-1.0.5.tgz", - "integrity": "sha512-msKrMbv/xHzhdOD4sstbEr+NbGqpv8ZtZliiCeByGENJo1jK1GZ/81zHF9HpWtEH5ihovPpdqHXniwZapJCKEA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/http-link-header/-/http-link-header-1.1.0.tgz", + "integrity": "sha512-pj6N1yxOz/ANO8HHsWGg/OoIL1kmRYvQnXQ7PIRpgp+15AnEsRH8fmIJE6D1OdWG2Bov+BJHVla1fFXxg1JbbA==", "dev": true, "engines": { "node": ">=6.0.0" @@ -4466,18 +4462,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-weakref": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", @@ -4689,12 +4673,15 @@ "dev": true }, "node_modules/json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.2.tgz", + "integrity": "sha512-eunSSaEnxV12z+Z73y/j5N37/In40GK4GmsSy+tEHJMxknvqnA7/djeYtAgW0GsWHUfg+847WJjKaEylk2y09g==", "dev": true, "dependencies": { - "jsonify": "~0.0.0" + "jsonify": "^0.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/json-stable-stringify-without-jsonify": { @@ -4731,18 +4718,18 @@ } }, "node_modules/jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", + "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", "dev": true, - "engines": { - "node": "*" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/jsonld-context-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/jsonld-context-parser/-/jsonld-context-parser-2.2.0.tgz", - "integrity": "sha512-h4ykp8iUOV4Xm6MgS1zVrytyw/dNVgOeofMCcD/5mHPng3i49qAsaomLT0BOXqYas7lwITVT5c6NZIRVMdXfVQ==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/jsonld-context-parser/-/jsonld-context-parser-2.2.2.tgz", + "integrity": "sha512-3VWIg/4NCMTXP6NsI6O93spFTd4qIOucKEmD8I+Exhxk9ZUVrnkLp2G4f0toR5jVleZkiiB9YGPS+yT1wwMqnQ==", "dev": true, "dependencies": { "@types/http-link-header": "^1.0.1", @@ -4757,9 +4744,9 @@ } }, "node_modules/jsonld-streaming-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/jsonld-streaming-parser/-/jsonld-streaming-parser-3.0.0.tgz", - "integrity": "sha512-n+IW+gTIw2UeXWXdN0ZlPY4DvKANUCrV0HOagXOsDUCvkO/SiDcYOZn2hrDkBGKm7yD5sefvvG3d/FxbeepbuA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/jsonld-streaming-parser/-/jsonld-streaming-parser-3.0.1.tgz", + "integrity": "sha512-zSJlEgrKypQDk/85R+xkudeCZo6vmnvJuCPvcjk2BzHPLzv1yqiwoKQDyFzfgfgCHM0p7YCJBZl0liT9RMUZJw==", "dev": true, "dependencies": { "@rdfjs/types": "*", @@ -5616,30 +5603,16 @@ "dev": true }, "node_modules/n3": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/n3/-/n3-1.16.2.tgz", - "integrity": "sha512-5vYa2HuNEJ+a26FEs4FGgfFLgaPOODaZpJlc7FS0eUjDumc4uK0cvx216PjKXBkLzmAsSqGgQPwqztcLLvwDsw==", + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/n3/-/n3-1.16.3.tgz", + "integrity": "sha512-9caLSZuMW1kdlPxEN4ka6E4E8a5QKoZ2emxpW+zHMofI+Bo92nJhN//wNub15S5T9I4c6saEqdGEu+YXJqMZVA==", "dev": true, "dependencies": { "queue-microtask": "^1.1.2", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/n3/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "readable-stream": "^4.0.0" }, "engines": { - "node": ">= 6" + "node": ">=12.0" } }, "node_modules/nanoid": { @@ -6209,7 +6182,7 @@ "node_modules/promise-polyfill": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-1.1.6.tgz", - "integrity": "sha1-zQTv9G9clcOn0EVZHXm14+AfEtc=", + "integrity": "sha512-7rrONfyLkDEc7OJ5QBkqa4KI4EBhCd340xRuIUPGCfu13znS+vx+VDdrT9ODAJHlXm7w4lbxN3DRjyv58EuzDg==", "dev": true }, "node_modules/pseudomap": { @@ -6314,9 +6287,9 @@ } }, "node_modules/rdf-isomorphic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rdf-isomorphic/-/rdf-isomorphic-1.3.0.tgz", - "integrity": "sha512-3BRwUwCNHHR8//bqmVH+knTFVbVfkp7CWyQk7qPHHA8JriXBYxrab21OomjJx/2KF21w8bWz344mgNYEaQABYQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/rdf-isomorphic/-/rdf-isomorphic-1.3.1.tgz", + "integrity": "sha512-6uIhsXTVp2AtO6f41PdnRV5xZsa0zVZQDTBdn0br+DZuFf5M/YD+T6m8hKDUnALI6nFL/IujTMLgEs20MlNidQ==", "dev": true, "dependencies": { "@rdfjs/types": "*", @@ -6335,9 +6308,9 @@ } }, "node_modules/rdf-literal": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rdf-literal/-/rdf-literal-1.3.0.tgz", - "integrity": "sha512-5u5L4kPYNZANie5AE4gCXqwpNO/p9E/nUcDurk05XAOJT/pt9rQlDk6+BX7j3dNSee3h9GS4xlLoWxQDj7sXtg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/rdf-literal/-/rdf-literal-1.3.1.tgz", + "integrity": "sha512-+o/PGOfJchyay9Rjrvi/oveRJACnt2WFO3LhEvtPlsRD1tFmwVUCMU+s33FtQprMo+z1ohFrv/yfEQ6Eym4KgQ==", "dev": true, "dependencies": { "@rdfjs/types": "*", @@ -6345,9 +6318,9 @@ } }, "node_modules/rdf-object": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/rdf-object/-/rdf-object-1.13.1.tgz", - "integrity": "sha512-Sgq+GbsqdPsMYh+d4OZ4C9brXlzqa9MvfVHG4pkuT9p7o+AX39nqjTWE/8HVaXjjOZBIDe8T54WWTMWphu3BpA==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/rdf-object/-/rdf-object-1.13.2.tgz", + "integrity": "sha512-DVLDCbxPOkhd/k43j9wcLU7CXe/gdldBBomMV3RyZ1G9E2zPa2FFNFijzMGgRGNY1OEyGmhBxw2eiJjUC7GVNw==", "dev": true, "dependencies": { "@rdfjs/types": "*", @@ -6379,9 +6352,9 @@ } }, "node_modules/rdf-terms": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/rdf-terms/-/rdf-terms-1.9.0.tgz", - "integrity": "sha512-FGMPOIpr6vEN8gWd/dVuPpcE/7k+u4Ufqi8FvM5lczjhduT1MN9Shmrw50fWCpHFVE4n0T3lV0qti1PCaHxAfg==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/rdf-terms/-/rdf-terms-1.9.1.tgz", + "integrity": "sha512-GrE8CbQSvuVEFRCywMu6VOgV1AFE6X+nFYcAhEc5pwYKI13bUvz4voiVufQiy3V8rzQKu21Sgl+dS2qcJavy7w==", "dev": true, "dependencies": { "@rdfjs/types": "*", @@ -6390,14 +6363,13 @@ } }, "node_modules/rdf-test-suite": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/rdf-test-suite/-/rdf-test-suite-1.19.2.tgz", - "integrity": "sha512-Qvbf05SfcNcvwFzroBVSVf51zS6R74GaQmX43UwXKNxVWMoDyZlgXWLfznDtTJW2HfahnFkTsyosxrliN1zZ1Q==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/rdf-test-suite/-/rdf-test-suite-1.20.0.tgz", + "integrity": "sha512-5p26dxVT3Hxr0nV3fEmGHm/NYHr7i8R4zp1hijCNHVrwV22LhAGtYWqYUtRUe00HO0J0kUr+Hpxh3X/OejCLxA==", "dev": true, "dependencies": { "@rdfjs/types": "*", "@types/json-stable-stringify": "^1.0.32", - "@types/log-symbols": "^3.0.0", "@types/minimist": "^1.2.0", "@types/n3": "^1.10.3", "@types/sax": "^1.0.1", @@ -6428,70 +6400,12 @@ "rdf-test-suite": "bin/Runner.js" } }, - "node_modules/rdf-test-suite/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/rdf-test-suite/node_modules/arrayify-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arrayify-stream/-/arrayify-stream-2.0.0.tgz", - "integrity": "sha512-Z2NRtxpWQIz3NRA2bEZOziIungBH+fpsFFEolc5u8uVRheYitvsDNvejlfyh/hjZ9VyS9Ba62oY0zc5oa6Wu7g==", - "dev": true - }, - "node_modules/rdf-test-suite/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/rdf-test-suite/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/rdf-test-suite/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "resolved": "https://registry.npmjs.org/arrayify-stream/-/arrayify-stream-2.0.1.tgz", + "integrity": "sha512-z8fB6PtmnewQpFB53piS2d1KlUi3BPMICH2h7leCOUXpQcwvZ4GbHHSpdKoUrgLMR6b4Qan/uDe1St3Ao3yIHg==", "dev": true }, - "node_modules/rdf-test-suite/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/rdf-test-suite/node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -6504,38 +6418,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/rdf-test-suite/node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/rdf-test-suite/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/rdfxml-streaming-parser": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/rdfxml-streaming-parser/-/rdfxml-streaming-parser-2.1.0.tgz", - "integrity": "sha512-G2kYXekAy7TUE5G6PAI5/Y/5ugqwFkA+305dcqbnRqqnK+a5gq2ubLGGmxJIIIEFbcFoUZ5UfQRHvqZdsWC8xQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/rdfxml-streaming-parser/-/rdfxml-streaming-parser-2.2.1.tgz", + "integrity": "sha512-1r7aXfSRCLkBYXGcko/GpSZdHxXKvYaeUi2ulEbB7cLvACD7DNoAA/uW6dsETEhgmsEipJZI7NLqBl2whOse8Q==", "dev": true, "dependencies": { "@rdfjs/types": "*", @@ -6544,7 +6430,8 @@ "rdf-data-factory": "^1.1.0", "readable-stream": "^4.0.0", "relative-to-absolute-iri": "^1.0.0", - "saxes": "^6.0.0" + "saxes": "^6.0.0", + "validate-iri": "^1.0.0" } }, "node_modules/rdfxml-streaming-parser/node_modules/buffer": { @@ -6777,9 +6664,9 @@ } }, "node_modules/relative-to-absolute-iri": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/relative-to-absolute-iri/-/relative-to-absolute-iri-1.0.6.tgz", - "integrity": "sha512-Xw5/Zx6iWSCMJUXwXVOjySjH8Xli4hVFL9QQFvkl1qEmFBG94J+QUI9emnoctOCD3285f1jNV+QWV9eDYwIdfQ==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/relative-to-absolute-iri/-/relative-to-absolute-iri-1.0.7.tgz", + "integrity": "sha512-Xjyl4HmIzg2jzK/Un2gELqbcE8Fxy85A/aLSHE6PE/3+OGsFwmKVA1vRyGaz6vLWSqLDMHA+5rjD/xbibSQN1Q==", "dev": true }, "node_modules/release-zalgo": { @@ -7102,9 +6989,9 @@ } }, "node_modules/sparqljson-parse": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/sparqljson-parse/-/sparqljson-parse-2.1.0.tgz", - "integrity": "sha512-JKyoDNDR9xrJwR6x6N41UWfER6kfeirE9BRBHdSFSfQF3eF3pxpuUTcJ6QGwHQ4wC/JsQdG/4OGmzkuk1B+8gg==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/sparqljson-parse/-/sparqljson-parse-2.1.2.tgz", + "integrity": "sha512-RqPeyy+RYQMeqgEsKPTY+ME5ZNXcgXJzg1v0o+tROiTntS9CwUW8mAY3wsx6seSvW3LVyNDEtsqOxnAokoGXOA==", "dev": true, "dependencies": { "@rdfjs/types": "*", @@ -7140,9 +7027,9 @@ } }, "node_modules/sparqlxml-parse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/sparqlxml-parse/-/sparqlxml-parse-2.0.1.tgz", - "integrity": "sha512-7HZMm0l9a+NQW6mEHzur+KEXA2/gpLYsyiq9yMLKa7Us8yfUJG/+fbHmuBoN7yE0t41SfCXtq4EU/nDjFSGudw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/sparqlxml-parse/-/sparqlxml-parse-2.0.2.tgz", + "integrity": "sha512-Iqso0WSTCSuMUYoX2pOEJxteCq9U+7AkOqwlFcvFG1S1aM87xWrp28njQOIiyIrL7Y8CkVXBZG1ec+DhZYUNXA==", "dev": true, "dependencies": { "@rdfjs/types": "*", @@ -7868,6 +7755,12 @@ "uuid": "bin/uuid" } }, + "node_modules/validate-iri": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/validate-iri/-/validate-iri-1.0.1.tgz", + "integrity": "sha512-gLXi7351CoyVVQw8XE5sgpYawRKatxE7kj/xmCxXOZS1kMdtcqC0ILIqLuVEVnAUQSL/evOGG3eQ+8VgbdnstA==", + "dev": true + }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -9383,9 +9276,9 @@ "optional": true }, "@rdfjs/types": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rdfjs/types/-/types-1.0.1.tgz", - "integrity": "sha512-YxVkH0XrCNG3MWeZxfg596GFe+oorTVusmNxRP6ZHTsGczZ8AGvG3UchRNkg3Fy4MyysI7vBAA5YZbESL+VmHQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rdfjs/types/-/types-1.1.0.tgz", + "integrity": "sha512-5zm8bN2/CC634dTcn/0AhTRLaQRjXDZs3QfcAsQKNturHT7XVWcKy/8p3P5gXl+YkZTAmy7T5M/LyiT/jbkENw==", "dev": true, "requires": { "@types/node": "*" @@ -9401,24 +9294,15 @@ } }, "@types/json-stable-stringify": { - "version": "1.0.32", - "resolved": "https://registry.npmjs.org/@types/json-stable-stringify/-/json-stable-stringify-1.0.32.tgz", - "integrity": "sha512-q9Q6+eUEGwQkv4Sbst3J4PNgDOvpuVuKj79Hl/qnmBMEIPzB5QoFRUtjcgcg2xNUZyYUGXBk5wYIBKHt0A+Mxw==", + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/@types/json-stable-stringify/-/json-stable-stringify-1.0.34.tgz", + "integrity": "sha512-s2cfwagOQAS8o06TcwKfr9Wx11dNGbH2E9vJz1cqV+a/LOyhWNLUNd6JSRYNzvB4d29UuJX2M0Dj9vE1T8fRXw==", "dev": true }, - "@types/log-symbols": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/log-symbols/-/log-symbols-3.0.0.tgz", - "integrity": "sha512-uW/AGf/41aZ1c1dhZ3s063Ii2OqT8EQooZu3t4VCRyR3dqyA2Bg46BcKyZpnWTY7wzm6cayq4jzylnruu4KqSA==", - "dev": true, - "requires": { - "log-symbols": "*" - } - }, "@types/minimist": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.1.tgz", - "integrity": "sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", + "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", "dev": true }, "@types/n3": { @@ -9432,25 +9316,33 @@ } }, "@types/node": { - "version": "18.6.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.3.tgz", - "integrity": "sha512-6qKpDtoaYLM+5+AFChLhHermMQxc3TOEFIDzrZLPRGHPrLEwqFkkT5Kx3ju05g6X7uDPazz3jHbKPX0KzCjntg==", + "version": "18.11.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", + "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", "dev": true }, "@types/readable-stream": { - "version": "2.3.14", - "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.14.tgz", - "integrity": "sha512-8jQ5Mp7bsDJEnW/69i6nAaQMoLwAVJVc7ZRAVTrdh/o6XueQsX38TEvKuYyoQj76/mg7WdlRfMrtl9pDLCJWsg==", + "version": "2.3.15", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.15.tgz", + "integrity": "sha512-oM5JSKQCcICF1wvGgmecmHldZ48OZamtMxcGGVICOJA8o8cahXC1zEVAif8iwoc5j8etxFaRFnf095+CDsuoFQ==", "dev": true, "requires": { "@types/node": "*", - "safe-buffer": "*" + "safe-buffer": "~5.1.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } } }, "@types/sax": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.1.tgz", - "integrity": "sha512-dqYdvN7Sbw8QT/0Ci5rhjE4/iCMJEM0Y9rHpCu+gGXD9Lwbz28t6HI2yegsB6BoV1sShRMU6lAmAcgRjmFy7LA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-pSAff4IAxJjfAXUG6tFkO7dsSbTmf8CtUpfhhZ5VhkRpC4628tJhh3+V6H1E+/Gs9piSzYKT5yzHO5M4GG9jkw==", "dev": true, "requires": { "@types/node": "*" @@ -11283,9 +11175,9 @@ "dev": true }, "http-link-header": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/http-link-header/-/http-link-header-1.0.5.tgz", - "integrity": "sha512-msKrMbv/xHzhdOD4sstbEr+NbGqpv8ZtZliiCeByGENJo1jK1GZ/81zHF9HpWtEH5ihovPpdqHXniwZapJCKEA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/http-link-header/-/http-link-header-1.1.0.tgz", + "integrity": "sha512-pj6N1yxOz/ANO8HHsWGg/OoIL1kmRYvQnXQ7PIRpgp+15AnEsRH8fmIJE6D1OdWG2Bov+BJHVla1fFXxg1JbbA==", "dev": true }, "https-browserify": { @@ -11606,12 +11498,6 @@ "has-tostringtag": "^1.0.0" } }, - "is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true - }, "is-weakref": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", @@ -11779,12 +11665,12 @@ "dev": true }, "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.2.tgz", + "integrity": "sha512-eunSSaEnxV12z+Z73y/j5N37/In40GK4GmsSy+tEHJMxknvqnA7/djeYtAgW0GsWHUfg+847WJjKaEylk2y09g==", "dev": true, "requires": { - "jsonify": "~0.0.0" + "jsonify": "^0.0.1" } }, "json-stable-stringify-without-jsonify": { @@ -11813,15 +11699,15 @@ } }, "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", + "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", "dev": true }, "jsonld-context-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/jsonld-context-parser/-/jsonld-context-parser-2.2.0.tgz", - "integrity": "sha512-h4ykp8iUOV4Xm6MgS1zVrytyw/dNVgOeofMCcD/5mHPng3i49qAsaomLT0BOXqYas7lwITVT5c6NZIRVMdXfVQ==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/jsonld-context-parser/-/jsonld-context-parser-2.2.2.tgz", + "integrity": "sha512-3VWIg/4NCMTXP6NsI6O93spFTd4qIOucKEmD8I+Exhxk9ZUVrnkLp2G4f0toR5jVleZkiiB9YGPS+yT1wwMqnQ==", "dev": true, "requires": { "@types/http-link-header": "^1.0.1", @@ -11833,9 +11719,9 @@ } }, "jsonld-streaming-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/jsonld-streaming-parser/-/jsonld-streaming-parser-3.0.0.tgz", - "integrity": "sha512-n+IW+gTIw2UeXWXdN0ZlPY4DvKANUCrV0HOagXOsDUCvkO/SiDcYOZn2hrDkBGKm7yD5sefvvG3d/FxbeepbuA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/jsonld-streaming-parser/-/jsonld-streaming-parser-3.0.1.tgz", + "integrity": "sha512-zSJlEgrKypQDk/85R+xkudeCZo6vmnvJuCPvcjk2BzHPLzv1yqiwoKQDyFzfgfgCHM0p7YCJBZl0liT9RMUZJw==", "dev": true, "requires": { "@rdfjs/types": "*", @@ -12493,26 +12379,13 @@ "dev": true }, "n3": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/n3/-/n3-1.16.2.tgz", - "integrity": "sha512-5vYa2HuNEJ+a26FEs4FGgfFLgaPOODaZpJlc7FS0eUjDumc4uK0cvx216PjKXBkLzmAsSqGgQPwqztcLLvwDsw==", + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/n3/-/n3-1.16.3.tgz", + "integrity": "sha512-9caLSZuMW1kdlPxEN4ka6E4E8a5QKoZ2emxpW+zHMofI+Bo92nJhN//wNub15S5T9I4c6saEqdGEu+YXJqMZVA==", "dev": true, "requires": { "queue-microtask": "^1.1.2", - "readable-stream": "^3.6.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } + "readable-stream": "^4.0.0" } }, "nanoid": { @@ -12954,7 +12827,7 @@ "promise-polyfill": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-1.1.6.tgz", - "integrity": "sha1-zQTv9G9clcOn0EVZHXm14+AfEtc=", + "integrity": "sha512-7rrONfyLkDEc7OJ5QBkqa4KI4EBhCd340xRuIUPGCfu13znS+vx+VDdrT9ODAJHlXm7w4lbxN3DRjyv58EuzDg==", "dev": true }, "pseudomap": { @@ -13037,9 +12910,9 @@ } }, "rdf-isomorphic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rdf-isomorphic/-/rdf-isomorphic-1.3.0.tgz", - "integrity": "sha512-3BRwUwCNHHR8//bqmVH+knTFVbVfkp7CWyQk7qPHHA8JriXBYxrab21OomjJx/2KF21w8bWz344mgNYEaQABYQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/rdf-isomorphic/-/rdf-isomorphic-1.3.1.tgz", + "integrity": "sha512-6uIhsXTVp2AtO6f41PdnRV5xZsa0zVZQDTBdn0br+DZuFf5M/YD+T6m8hKDUnALI6nFL/IujTMLgEs20MlNidQ==", "dev": true, "requires": { "@rdfjs/types": "*", @@ -13058,9 +12931,9 @@ } }, "rdf-literal": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rdf-literal/-/rdf-literal-1.3.0.tgz", - "integrity": "sha512-5u5L4kPYNZANie5AE4gCXqwpNO/p9E/nUcDurk05XAOJT/pt9rQlDk6+BX7j3dNSee3h9GS4xlLoWxQDj7sXtg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/rdf-literal/-/rdf-literal-1.3.1.tgz", + "integrity": "sha512-+o/PGOfJchyay9Rjrvi/oveRJACnt2WFO3LhEvtPlsRD1tFmwVUCMU+s33FtQprMo+z1ohFrv/yfEQ6Eym4KgQ==", "dev": true, "requires": { "@rdfjs/types": "*", @@ -13068,9 +12941,9 @@ } }, "rdf-object": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/rdf-object/-/rdf-object-1.13.1.tgz", - "integrity": "sha512-Sgq+GbsqdPsMYh+d4OZ4C9brXlzqa9MvfVHG4pkuT9p7o+AX39nqjTWE/8HVaXjjOZBIDe8T54WWTMWphu3BpA==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/rdf-object/-/rdf-object-1.13.2.tgz", + "integrity": "sha512-DVLDCbxPOkhd/k43j9wcLU7CXe/gdldBBomMV3RyZ1G9E2zPa2FFNFijzMGgRGNY1OEyGmhBxw2eiJjUC7GVNw==", "dev": true, "requires": { "@rdfjs/types": "*", @@ -13102,9 +12975,9 @@ } }, "rdf-terms": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/rdf-terms/-/rdf-terms-1.9.0.tgz", - "integrity": "sha512-FGMPOIpr6vEN8gWd/dVuPpcE/7k+u4Ufqi8FvM5lczjhduT1MN9Shmrw50fWCpHFVE4n0T3lV0qti1PCaHxAfg==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/rdf-terms/-/rdf-terms-1.9.1.tgz", + "integrity": "sha512-GrE8CbQSvuVEFRCywMu6VOgV1AFE6X+nFYcAhEc5pwYKI13bUvz4voiVufQiy3V8rzQKu21Sgl+dS2qcJavy7w==", "dev": true, "requires": { "@rdfjs/types": "*", @@ -13113,14 +12986,13 @@ } }, "rdf-test-suite": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/rdf-test-suite/-/rdf-test-suite-1.19.2.tgz", - "integrity": "sha512-Qvbf05SfcNcvwFzroBVSVf51zS6R74GaQmX43UwXKNxVWMoDyZlgXWLfznDtTJW2HfahnFkTsyosxrliN1zZ1Q==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/rdf-test-suite/-/rdf-test-suite-1.20.0.tgz", + "integrity": "sha512-5p26dxVT3Hxr0nV3fEmGHm/NYHr7i8R4zp1hijCNHVrwV22LhAGtYWqYUtRUe00HO0J0kUr+Hpxh3X/OejCLxA==", "dev": true, "requires": { "@rdfjs/types": "*", "@types/json-stable-stringify": "^1.0.32", - "@types/log-symbols": "^3.0.0", "@types/minimist": "^1.2.0", "@types/n3": "^1.10.3", "@types/sax": "^1.0.1", @@ -13148,50 +13020,10 @@ "streamify-string": "^1.0.1" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, "arrayify-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arrayify-stream/-/arrayify-stream-2.0.0.tgz", - "integrity": "sha512-Z2NRtxpWQIz3NRA2bEZOziIungBH+fpsFFEolc5u8uVRheYitvsDNvejlfyh/hjZ9VyS9Ba62oY0zc5oa6Wu7g==", - "dev": true - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "resolved": "https://registry.npmjs.org/arrayify-stream/-/arrayify-stream-2.0.1.tgz", + "integrity": "sha512-z8fB6PtmnewQpFB53piS2d1KlUi3BPMICH2h7leCOUXpQcwvZ4GbHHSpdKoUrgLMR6b4Qan/uDe1St3Ao3yIHg==", "dev": true }, "is-stream": { @@ -13199,32 +13031,13 @@ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true - }, - "log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } } } }, "rdfxml-streaming-parser": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/rdfxml-streaming-parser/-/rdfxml-streaming-parser-2.1.0.tgz", - "integrity": "sha512-G2kYXekAy7TUE5G6PAI5/Y/5ugqwFkA+305dcqbnRqqnK+a5gq2ubLGGmxJIIIEFbcFoUZ5UfQRHvqZdsWC8xQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/rdfxml-streaming-parser/-/rdfxml-streaming-parser-2.2.1.tgz", + "integrity": "sha512-1r7aXfSRCLkBYXGcko/GpSZdHxXKvYaeUi2ulEbB7cLvACD7DNoAA/uW6dsETEhgmsEipJZI7NLqBl2whOse8Q==", "dev": true, "requires": { "@rdfjs/types": "*", @@ -13233,7 +13046,8 @@ "rdf-data-factory": "^1.1.0", "readable-stream": "^4.0.0", "relative-to-absolute-iri": "^1.0.0", - "saxes": "^6.0.0" + "saxes": "^6.0.0", + "validate-iri": "^1.0.0" }, "dependencies": { "buffer": { @@ -13423,9 +13237,9 @@ } }, "relative-to-absolute-iri": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/relative-to-absolute-iri/-/relative-to-absolute-iri-1.0.6.tgz", - "integrity": "sha512-Xw5/Zx6iWSCMJUXwXVOjySjH8Xli4hVFL9QQFvkl1qEmFBG94J+QUI9emnoctOCD3285f1jNV+QWV9eDYwIdfQ==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/relative-to-absolute-iri/-/relative-to-absolute-iri-1.0.7.tgz", + "integrity": "sha512-Xjyl4HmIzg2jzK/Un2gELqbcE8Fxy85A/aLSHE6PE/3+OGsFwmKVA1vRyGaz6vLWSqLDMHA+5rjD/xbibSQN1Q==", "dev": true }, "release-zalgo": { @@ -13665,9 +13479,9 @@ } }, "sparqljson-parse": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/sparqljson-parse/-/sparqljson-parse-2.1.0.tgz", - "integrity": "sha512-JKyoDNDR9xrJwR6x6N41UWfER6kfeirE9BRBHdSFSfQF3eF3pxpuUTcJ6QGwHQ4wC/JsQdG/4OGmzkuk1B+8gg==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/sparqljson-parse/-/sparqljson-parse-2.1.2.tgz", + "integrity": "sha512-RqPeyy+RYQMeqgEsKPTY+ME5ZNXcgXJzg1v0o+tROiTntS9CwUW8mAY3wsx6seSvW3LVyNDEtsqOxnAokoGXOA==", "dev": true, "requires": { "@rdfjs/types": "*", @@ -13691,9 +13505,9 @@ } }, "sparqlxml-parse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/sparqlxml-parse/-/sparqlxml-parse-2.0.1.tgz", - "integrity": "sha512-7HZMm0l9a+NQW6mEHzur+KEXA2/gpLYsyiq9yMLKa7Us8yfUJG/+fbHmuBoN7yE0t41SfCXtq4EU/nDjFSGudw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/sparqlxml-parse/-/sparqlxml-parse-2.0.2.tgz", + "integrity": "sha512-Iqso0WSTCSuMUYoX2pOEJxteCq9U+7AkOqwlFcvFG1S1aM87xWrp28njQOIiyIrL7Y8CkVXBZG1ec+DhZYUNXA==", "dev": true, "requires": { "@rdfjs/types": "*", @@ -14326,6 +14140,12 @@ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", "dev": true }, + "validate-iri": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/validate-iri/-/validate-iri-1.0.1.tgz", + "integrity": "sha512-gLXi7351CoyVVQw8XE5sgpYawRKatxE7kj/xmCxXOZS1kMdtcqC0ILIqLuVEVnAUQSL/evOGG3eQ+8VgbdnstA==", + "dev": true + }, "validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", diff --git a/package.json b/package.json index 50cb7554..efde53b7 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "mocha": "^8.0.0", "nyc": "^14.1.1", "pre-commit": "^1.2.2", - "rdf-test-suite": "^1.19.2", + "rdf-test-suite": "^1.20.0", "streamify-string": "^1.0.1", "uglify-js": "^3.14.3" }, @@ -54,7 +54,7 @@ "mocha": "mocha", "lint": "eslint src perf test spec", "prepare": "npm run build", - "spec": "npm run spec-turtle && npm run spec-ntriples && npm run spec-nquads && npm run spec-trig", + "spec": "npm run spec-turtle && npm run spec-ntriples && npm run spec-nquads && npm run spec-trig && npm run spec-rdf-star", "spec-earl": "npm run spec-earl-turtle && npm run spec-earl-ntriples && npm run spec-earl-nquads && npm run spec-earl-trig", "spec-ntriples": "rdf-test-suite spec/parser.js http://w3c.github.io/rdf-tests/ntriples/manifest.ttl -i '{ \"format\": \"n-triples\" }' -c .rdf-test-suite-cache/", "spec-nquads": "rdf-test-suite spec/parser.js http://w3c.github.io/rdf-tests/nquads/manifest.ttl -i '{ \"format\": \"n-quads\" }' -c .rdf-test-suite-cache/", @@ -64,6 +64,12 @@ "spec-earl-nquads": "rdf-test-suite spec/parser.js http://w3c.github.io/rdf-tests/nquads/manifest.ttl -i '{ \"format\": \"n-quads\" }' -c .rdf-test-suite-cache/ -o earl -p spec/earl-meta.json > spec/earl-nquads.ttl", "spec-earl-turtle": "rdf-test-suite spec/parser.js http://w3c.github.io/rdf-tests/turtle/manifest.ttl -i '{ \"format\": \"turtle\" }' -c .rdf-test-suite-cache/ -o earl -p spec/earl-meta.json > spec/earl-turtle.ttl", "spec-earl-trig": "rdf-test-suite spec/parser.js http://w3c.github.io/rdf-tests/trig/manifest.ttl -i '{ \"format\": \"trig\" }' -c .rdf-test-suite-cache/ -o earl -p spec/earl-meta.json > spec/earl-trig.ttl", + "spec-rdf-star": "npm run spec-trig-rdf-star && npm run spec-trig-eval-rdf-star && npm run spec-turtle-rdf-star && npm run spec-turtle-eval-rdf-star", + "spec-trig-rdf-star": "node ../rdf-test-suite.js/bin/Runner.js spec/parser.js https://w3c.github.io/rdf-star/tests/trig/syntax/manifest.jsonld -i '{ \"format\": \"trig-star\" }' -c .rdf-test-suite-cache/", + "spec-trig-eval-rdf-star": "node ../rdf-test-suite.js/bin/Runner.js spec/parser.js https://w3c.github.io/rdf-star/tests/trig/eval/manifest.jsonld -i '{ \"format\": \"trig-star\" }' -c .rdf-test-suite-cache/", + "spec-turtle-rdf-star": "node ../rdf-test-suite.js/bin/Runner.js spec/parser.js https://w3c.github.io/rdf-star/tests/turtle/syntax/manifest.jsonld -i '{ \"format\": \"turtle-star\" }' -c .rdf-test-suite-cache/", + "spec-turtle-eval-rdf-star": "node ../rdf-test-suite.js/bin/Runner.js spec/parser.js https://w3c.github.io/rdf-star/tests/turtle/eval/manifest.jsonld -i '{ \"format\": \"turtle-star\" }' -c .rdf-test-suite-cache/", + "spec-ntriples-rdf-star": "node ../rdf-test-suite.js/bin/Runner.js spec/parser.js https://w3c.github.io/rdf-star/tests/nt/syntax/manifest.jsonld -i '{ \"format\": \"n-quads-star\" }' -c .rdf-test-suite-cache/", "spec-clean": "rm -r .rdf-test-suite-cache/", "docs": "cd src && docco *.js -o ../docs && cd .." }, diff --git a/src/N3DataFactory.js b/src/N3DataFactory.js index dec7aaef..4c253a7c 100644 --- a/src/N3DataFactory.js +++ b/src/N3DataFactory.js @@ -10,7 +10,6 @@ let DEFAULTGRAPH; let _blankNodeCounter = 0; const escapedLiteral = /^"(.*".*)(?="[^"]*$)/; -const quadId = /^<<("(?:""|[^"])*"[^ ]*|[^ ]+) ("(?:""|[^"])*"[^ ]*|[^ ]+) ("(?:""|[^"])*"[^ ]*|[^ ]+) ?("(?:""|[^"])*"[^ ]*|[^ ]+)?>>$/; // ## DataFactory singleton const DataFactory = { @@ -188,9 +187,12 @@ export class DefaultGraph extends Term { // ## DefaultGraph singleton DEFAULTGRAPH = new DefaultGraph(); - // ### Constructs a term from the given internal string ID -export function termFromId(id, factory) { +// The third 'nested' parameter of this function is to aid +// with recursion over nested terms. It should not be used +// by consumers of this library. +// See https://github.com/rdfjs/N3.js/pull/311#discussion_r1061042725 +export function termFromId(id, factory, nested) { factory = factory || DataFactory; // Falsy value or empty string indicate the default graph @@ -215,21 +217,28 @@ export function termFromId(id, factory) { return factory.literal(id.substr(1, endPos - 1), id[endPos + 1] === '@' ? id.substr(endPos + 2) : factory.namedNode(id.substr(endPos + 3))); - case '<': - const components = quadId.exec(id); - return factory.quad( - termFromId(unescapeQuotes(components[1]), factory), - termFromId(unescapeQuotes(components[2]), factory), - termFromId(unescapeQuotes(components[3]), factory), - components[4] && termFromId(unescapeQuotes(components[4]), factory) - ); + case '[': + id = JSON.parse(id); + break; default: - return factory.namedNode(id); + if (!nested || !Array.isArray(id)) { + return factory.namedNode(id); + } } + return factory.quad( + termFromId(id[0], factory, true), + termFromId(id[1], factory, true), + termFromId(id[2], factory, true), + id[3] && termFromId(id[3], factory, true) + ); } // ### Constructs an internal string ID from the given term or ID string -export function termToId(term) { +// The third 'nested' parameter of this function is to aid +// with recursion over nested terms. It should not be used +// by consumers of this library. +// See https://github.com/rdfjs/N3.js/pull/311#discussion_r1061042725 +export function termToId(term, nested) { if (typeof term === 'string') return term; if (term instanceof Term && term.termType !== 'Quad') @@ -247,17 +256,15 @@ export function termToId(term) { term.language ? `@${term.language}` : (term.datatype && term.datatype.value !== xsd.string ? `^^${term.datatype.value}` : '')}`; case 'Quad': - // To identify RDF* quad components, we escape quotes by doubling them. - // This avoids the overhead of backslash parsing of Turtle-like syntaxes. - return `<<${ - escapeQuotes(termToId(term.subject)) - } ${ - escapeQuotes(termToId(term.predicate)) - } ${ - escapeQuotes(termToId(term.object)) - }${ - (isDefaultGraph(term.graph)) ? '' : ` ${termToId(term.graph)}` - }>>`; + const res = [ + termToId(term.subject, true), + termToId(term.predicate, true), + termToId(term.object, true), + ]; + if (!isDefaultGraph(term.graph)) { + res.push(termToId(term.graph, true)); + } + return nested ? res : JSON.stringify(res); default: throw new Error(`Unexpected termType: ${term.termType}`); } } diff --git a/src/N3Lexer.js b/src/N3Lexer.js index eeb36bdd..64080dee 100644 --- a/src/N3Lexer.js +++ b/src/N3Lexer.js @@ -53,6 +53,8 @@ export default class N3Lexer { this._endOfFile = /^(?:#[^\n\r]*)?$/; options = options || {}; + this._supportsRDFStar = options.rdfStar; + // In line mode (N-Triples or N-Quads), only simple features may be parsed if (this._lineMode = !!options.lineMode) { this._n3Mode = false; @@ -290,7 +292,16 @@ export default class N3Lexer { matchLength = 2, value = '>'; } break; - + case '{': + // We can properly evaluate this case if we are + // not in rdfStar mode or we can look ahead to + // see if there is a pipe following the { + const long = input.length !== 1; + if (long && input[1] === '|') + matchLength = 2, type = '{|'; + else if (!this._lineMode && (long || !this._supportsRDFStar)) + matchLength = 1, type = firstChar; + break; case '!': if (!this._n3Mode) break; @@ -300,14 +311,17 @@ export default class N3Lexer { case ']': case '(': case ')': - case '{': case '}': if (!this._lineMode) { matchLength = 1; type = firstChar; } break; - + case '|': + if (input.length > 1 && input[1] === '}') { + type = '|}', matchLength = 2; + break; + } default: inconclusive = true; } diff --git a/src/N3Parser.js b/src/N3Parser.js index 1a7d7449..9dcd5c4c 100644 --- a/src/N3Parser.js +++ b/src/N3Parser.js @@ -28,13 +28,13 @@ export default class N3Parser { // Support triples in other graphs this._supportsQuads = !(isTurtle || isTriG || isNTriples || isN3); // Support nesting of triples - this._supportsRDFStar = format === '' || /star|\*$/.test(format); + this._supportsRDFStar = options.rdfStar !== false; // Disable relative IRIs in N-Triples or N-Quads mode if (isLineMode) this._resolveRelativeIRI = iri => { return null; }; this._blankNodePrefix = typeof options.blankNodePrefix !== 'string' ? '' : options.blankNodePrefix.replace(/^(?!_:)/, '_:'); - this._lexer = options.lexer || new N3Lexer({ lineMode: isLineMode, n3: isN3 }); + this._lexer = options.lexer || new N3Lexer({ lineMode: isLineMode, n3: isN3, rdfStar: this._supportsRDFStar }); // Disable explicit quantifiers by default this._explicitQuantifiers = !!options.explicitQuantifiers; } @@ -197,6 +197,10 @@ export default class N3Parser { this._subject = this._blankNode(), null, null); return this._readBlankNodeHead; case '(': + // Lists are not allowed inside quoted triples + if (this._contextStack.length > 0 && this._contextStack[this._contextStack.length - 1].type === '<<') { + return this._error('Unexpected list inside quoted triple', token); + } // Start a new list this._saveContext('list', this._graph, this.RDF_NIL, null, null); this._subject = null; @@ -239,7 +243,7 @@ export default class N3Parser { break; case '<<': if (!this._supportsRDFStar) - return this._error('Unexpected RDF* syntax', token); + return this._error('Unexpected RDF-star syntax', token); this._saveContext('<<', this._graph, null, null, null); this._graph = null; return this._readSubject; @@ -315,6 +319,10 @@ export default class N3Parser { this._subject = this._blankNode()); return this._readBlankNodeHead; case '(': + // Lists are not allowed inside quoted triples + if (this._contextStack.length > 0 && this._contextStack[this._contextStack.length - 1].type === '<<') { + return this._error('Unexpected list inside quoted triple', token); + } // Start a new list this._saveContext('list', this._graph, this._subject, this._predicate, this.RDF_NIL); this._subject = null; @@ -328,7 +336,7 @@ export default class N3Parser { return this._readSubject; case '<<': if (!this._supportsRDFStar) - return this._error('Unexpected RDF* syntax', token); + return this._error('Unexpected RDF-star syntax', token); this._saveContext('<<', this._graph, this._subject, this._predicate, null); this._graph = null; return this._readSubject; @@ -363,6 +371,9 @@ export default class N3Parser { this._subject = null; return this._readBlankNodeTail(token); } + else if (this._contextStack.length > 1 && this._contextStack[this._contextStack.length - 2].type === '<<') { + return this._error('Compound blank node expressions not permitted within quoted triple', token); + } else { this._predicate = null; return this._readPredicate(token); @@ -473,6 +484,16 @@ export default class N3Parser { this._saveContext('formula', this._graph, this._subject, this._predicate, this._graph = this._blankNode()); return this._readSubject; + case '<<': + if (!this._supportsRDFStar) + return this._error('Unexpected RDF-star syntax', token); + + this._saveContext('<<', this._graph, this._subject, null, null); + return this._readSubject; + case '>>': + item = this._graph; + this._graph = null; + break; default: if ((item = this._readEntity(token)) === undefined) return; @@ -614,6 +635,18 @@ export default class N3Parser { case ',': next = this._readObject; break; + case '{|': + if (!this._supportsRDFStar) + return this._error('Unexpected RDF-star syntax', token); + + this._saveContext('{|', this._graph, this._subject, this._predicate, this._object); + + // As a convention, we set the graph term as the Default Graph in quads representing quoted triples + // see https://github.com/rdfjs/N3.js/pull/311#discussion_r1061039556 for details + this._subject = this._quad(this._subject, this._predicate, this._object, this.DEFAULTGRAPH); + this._predicate = null; + this._object = null; + return this._readPredicate; default: // An entity means this is a quad (only allowed if not already inside a graph) if (this._supportsQuads && this._graph === null && (graph = this._readEntity(token)) !== undefined) { @@ -835,29 +868,29 @@ export default class N3Parser { return this._readPath; } - // ### `_readRDFStarTailOrGraph` reads the graph of a nested RDF* quad or the end of a nested RDF* triple - _readRDFStarTailOrGraph(token) { - if (token.type !== '>>') { - // An entity means this is a quad (only allowed if not already inside a graph) - if (this._supportsQuads && this._graph === null && (this._graph = this._readEntity(token)) !== undefined) - return this._readRDFStarTail; - return this._error(`Expected >> to follow "${this._object.id}"`, token); - } - return this._readRDFStarTail(token); - } - - // ### `_readRDFStarTail` reads the end of a nested RDF* triple + // ### `_readRDFStarTail` reads the end of a nested RDF-star triple _readRDFStarTail(token) { if (token.type !== '>>') - return this._error(`Expected >> but got ${token.type}`, token); + return this._error(`Expected >> to follow "${this._object.id}" but got ${token.type}`, token); // Read the quad and restore the previous context const quad = this._quad(this._subject, this._predicate, this._object, this._graph || this.DEFAULTGRAPH); this._restoreContext('<<', token); + + // If the triple is in a list then return to reading the remaining elements + if (this._contextStack.length > 0 && this._contextStack[this._contextStack.length - 1].type === 'list') { + this._graph = quad; + return this._readListItem(token); + } + // If the triple was the subject, continue by reading the predicate. if (this._subject === null) { this._subject = quad; - return this._readPredicate; + // In N3 mode, the subject might be a path + if (this._n3Mode) + return this._getPathReader(this._readPredicateOrNamedGraph); + else + return this._readPredicate; } // If the triple was the object, read context end. else { @@ -866,6 +899,29 @@ export default class N3Parser { } } + // ### `_readRDFStarTail` reads the end of a nested RDF-star triple + _readAnnotatedTail(token) { + if (token.type === '{|') { + this._saveContext('{|', this._graph, this._subject, this._predicate, this._object); + + // As a convention, we set the graph term as the Default Graph in quads representing quoted triples + // see https://github.com/rdfjs/N3.js/pull/311#discussion_r1061039556 for details + this._subject = this._quad(this._subject, this._predicate, this._object, this.DEFAULTGRAPH); + this._predicate = null; + this._object = null; + return this._readPredicate; + } + else { + this._emit(this._subject, this._predicate, this._object, this._graph); + } + + // If the quoted triple is not finished, the next token must be a predicate + if (token.type !== '|}') + return this._readPredicate; + this._restoreContext('{|', token); + return this._getContextEndReader(); + } + // ### `_getContextEndReader` gets the next reader function at the end of a context _getContextEndReader() { const contextStack = this._contextStack; @@ -880,7 +936,9 @@ export default class N3Parser { case 'formula': return this._readFormulaTail; case '<<': - return this._readRDFStarTailOrGraph; + return this._readRDFStarTail; + case '{|': + return this._readAnnotatedTail; } } diff --git a/src/N3Writer.js b/src/N3Writer.js index abc3852f..8fc4f282 100644 --- a/src/N3Writer.js +++ b/src/N3Writer.js @@ -225,7 +225,7 @@ export default class N3Writer { } } - // ### `_encodeQuad` encodes an RDF* quad + // ### `_encodeQuad` encodes an RDF-star quad _encodeQuad({ subject, predicate, object, graph }) { return `<<${ this._encodeSubject(subject)} ${ diff --git a/test/N3Lexer-test.js b/test/N3Lexer-test.js index 03902d3f..13b6730b 100644 --- a/test/N3Lexer-test.js +++ b/test/N3Lexer-test.js @@ -855,7 +855,7 @@ describe('Lexer', () => { { type: '>>', line: 1 }, { type: 'eof', line: 1 })); - it('should tokenize an RDF* statement with IRIs', + it('should tokenize an RDF-star statement with IRIs', shouldTokenize('<< \n\t \n\t>> .', { type: '<<', line: 1 }, { type: 'IRI', value: 'http://ex.org/?bla#foo', line: 1 }, @@ -865,11 +865,57 @@ describe('Lexer', () => { { type: '.', line: 3 }, { type: 'eof', line: 3 })); - it('should not tokenize a wrongly closed RDF* statement with IRIs', + it('should not tokenize a wrongly closed RDF-star statement with IRIs', shouldNotTokenize('<< \n\t \n\t> .', 'Unexpected ">" on line 3.')); - it('should tokenize a split RDF* statement with IRIs', + it('should tokenize an RDF-star annotated statement', + shouldTokenize(' {| |}', + { type: 'IRI', value: 'a', line: 1 }, + { type: 'IRI', value: 'b', line: 1 }, + { type: 'IRI', value: 'c', line: 1 }, + { type: '{|', line: 1 }, + { type: 'IRI', value: 'd', line: 1 }, + { type: 'IRI', value: 'e', line: 1 }, + { type: '|}', line: 1 }, + { type: 'eof', line: 1 })); + + it('should tokenize an RDF-star annotated statement with multiple annotations', + shouldTokenize(' {| ; |}', + { type: 'IRI', value: 'a', line: 1 }, + { type: 'IRI', value: 'b', line: 1 }, + { type: 'IRI', value: 'c', line: 1 }, + { type: '{|', line: 1 }, + { type: 'IRI', value: 'd', line: 1 }, + { type: 'IRI', value: 'e', line: 1 }, + { type: ';', line: 1 }, + { type: 'IRI', value: 'f', line: 1 }, + { type: 'IRI', value: 'g', line: 1 }, + { type: '|}', line: 1 }, + { type: 'eof', line: 1 })); + + it('should tokenize an RDF-star annotated statement with multiple annotations, one containing a blank node', + shouldTokenize(' {| [ "f" ]; |}', + { type: 'IRI', value: 'a', line: 1 }, + { type: 'IRI', value: 'b', line: 1 }, + { type: 'IRI', value: 'c', line: 1 }, + { type: '{|', line: 1 }, + { type: 'IRI', value: 'd', line: 1 }, + { type: '[', value: '', line: 1 }, + { type: 'IRI', value: 'e', line: 1 }, + { type: 'literal', value: 'f', line: 1 }, + { type: ']', value: '', line: 1 }, + { type: ';', line: 1 }, + { type: 'IRI', value: 'f', line: 1 }, + { type: 'IRI', value: 'g', line: 1 }, + { type: '|}', line: 1 }, + { type: 'eof', line: 1 })); + + it('should not tokenize an annotated statement that is not closed', + shouldNotTokenize(' {| [ "f" ]; |', + 'Unexpected "|" on line 1.')); + + it('should tokenize a split RDF-star statement with IRIs', shouldTokenize(streamOf('<', '< \n\t \n\t>> .'), { type: '<<', line: 1 }, { type: 'IRI', value: 'http://ex.org/?bla#foo', line: 1 }, @@ -879,7 +925,7 @@ describe('Lexer', () => { { type: '.', line: 3 }, { type: 'eof', line: 3 })); - it('should tokenize an RDF* statement with string literals', + it('should tokenize an RDF-star statement with string literals', shouldTokenize('<<"string"@en "string"@nl-be "string"@EN>> .', { type: '<<', line: 1 }, { type: 'literal', value: 'string', line: 1 }, @@ -892,7 +938,7 @@ describe('Lexer', () => { { type: '.', line: 1 }, { type: 'eof', line: 1 })); - it('should tokenize an RDF* statement with integers', + it('should tokenize an RDF-star statement with integers', shouldTokenize('<<1 2 3>>.', { type: '<<', line: 1 }, { type: 'literal', value: '1', prefix: 'http://www.w3.org/2001/XMLSchema#integer', line: 1 }, @@ -902,7 +948,7 @@ describe('Lexer', () => { { type: '.', line: 1 }, { type: 'eof', line: 1 })); - it('should tokenize an RDF* statement with decimals', + it('should tokenize an RDF-star statement with decimals', shouldTokenize('<<1.2 3.4 5.6>>.', { type: '<<', line: 1 }, { type: 'literal', value: '1.2', prefix: 'http://www.w3.org/2001/XMLSchema#decimal', line: 1 }, @@ -912,7 +958,7 @@ describe('Lexer', () => { { type: '.', line: 1 }, { type: 'eof', line: 1 })); - it('should tokenize an RDF* statement with booleans', + it('should tokenize an RDF-star statement with booleans', shouldTokenize('<>.', { type: '<<', line: 1 }, { type: 'literal', value: 'true', prefix: 'http://www.w3.org/2001/XMLSchema#boolean', line: 1 }, @@ -929,7 +975,7 @@ describe('Lexer', () => { { type: '.', line: 1 }, { type: 'eof', line: 1 })); - it('should tokenize an RDF* statement with prefixed names', + it('should tokenize an RDF-star statement with prefixed names', shouldTokenize('<> .', { type: '<<', line: 1 }, { type: 'prefixed', prefix: 'a', value: 'a', line: 1 }, @@ -939,7 +985,7 @@ describe('Lexer', () => { { type: '.', line: 1 }, { type: 'eof', line: 1 })); - it('should tokenize an RDF* statement with blank nodes', + it('should tokenize an RDF-star statement with blank nodes', shouldTokenize('<<_:a _:b _:c>> .', { type: '<<', line: 1 }, { type: 'blank', prefix: '_', value: 'a', line: 1 }, @@ -949,7 +995,7 @@ describe('Lexer', () => { { type: '.', line: 1 }, { type: 'eof', line: 1 })); - it('should tokenize an RDF* statement with variables', + it('should tokenize an RDF-star statement with variables', shouldTokenize('<> .', { type: '<<', line: 1 }, { type: 'var', value: '?a', line: 1 }, @@ -959,7 +1005,7 @@ describe('Lexer', () => { { type: '.', line: 1 }, { type: 'eof', line: 1 })); - it('should tokenize an RDF* statement with mixed types', + it('should tokenize an RDF-star statement with mixed types', shouldTokenize('<< "string"@nl-be c:c>> .', { type: '<<', line: 1 }, { type: 'IRI', value: 'http://ex.org/?bla#foo', line: 1 }, @@ -970,7 +1016,7 @@ describe('Lexer', () => { { type: '.', line: 1 }, { type: 'eof', line: 1 })); - it('should tokenize an RDF* statement with mixed types', + it('should tokenize an RDF-star statement with mixed types', shouldTokenize('<<_:a a:a "string"@EN>> .', { type: '<<', line: 1 }, { type: 'blank', prefix: '_', value: 'a', line: 1 }, @@ -981,7 +1027,7 @@ describe('Lexer', () => { { type: '.', line: 1 }, { type: 'eof', line: 1 })); - it('should tokenize an RDF* statement with mixed types', + it('should tokenize an RDF-star statement with mixed types', shouldTokenize('<<"literal"@AU _:a>> .', { type: '<<', line: 1 }, { type: 'literal', value: 'literal', line: 1 }, @@ -992,7 +1038,7 @@ describe('Lexer', () => { { type: '.', line: 1 }, { type: 'eof', line: 1 })); - it('should tokenize RDF* statements with shared subjects', + it('should tokenize RDF-star statements with shared subjects', shouldTokenize('<< ;\n >>.', { type: '<<', line: 1 }, { type: 'IRI', value: 'a', line: 1 }, @@ -1005,7 +1051,7 @@ describe('Lexer', () => { { type: '.', line: 2 }, { type: 'eof', line: 2 })); - it('should tokenize RDF* statements with shared subjects and predicates', + it('should tokenize RDF-star statements with shared subjects and predicates', shouldTokenize('<< ,\n>>.', { type: '<<', line: 1 }, { type: 'IRI', value: 'a', line: 1 }, @@ -1017,7 +1063,7 @@ describe('Lexer', () => { { type: '.', line: 2 }, { type: 'eof', line: 2 })); - it('should tokenize an RDF* statement with shared subjects and predicates and prefixed names', + it('should tokenize an RDF-star statement with shared subjects and predicates and prefixed names', shouldTokenize('<> .', { type: '<<', line: 1 }, { type: 'prefixed', prefix: 'a', value: 'a', line: 1 }, diff --git a/test/N3Parser-test.js b/test/N3Parser-test.js index 80cb2466..85c5c474 100644 --- a/test/N3Parser-test.js +++ b/test/N3Parser-test.js @@ -22,61 +22,61 @@ describe('Parser', () => { }); describe('A Parser instance', () => { - it('should parse the empty string', + describe('should parse the empty string', shouldParse('' /* no triples */)); - it('should parse a whitespace string', + describe('should parse a whitespace string', shouldParse(' \t \n ' /* no triples */)); - it('should parse a single triple', + describe('should parse a single triple', shouldParse(' .', ['a', 'b', 'c'])); - it('should parse three triples', + describe('should parse three triples', shouldParse(' .\n .\n .', ['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i'])); - it('should parse a triple with a literal', + describe('should parse a triple with a literal', shouldParse(' "string".', ['a', 'b', '"string"'])); - it('should parse a triple with a numeric literal', + describe('should parse a triple with a numeric literal', shouldParse(' 3.0.', ['a', 'b', '"3.0"^^http://www.w3.org/2001/XMLSchema#decimal'])); - it('should parse a triple with an integer literal', + describe('should parse a triple with an integer literal', shouldParse(' 3.', ['a', 'b', '"3"^^http://www.w3.org/2001/XMLSchema#integer'])); - it('should parse a triple with a floating point literal', + describe('should parse a triple with a floating point literal', shouldParse(' 1.3e2.', ['a', 'b', '"1.3e2"^^http://www.w3.org/2001/XMLSchema#double'])); - it('should parse a triple with a boolean literal', + describe('should parse a triple with a boolean literal', shouldParse(' true.', ['a', 'b', '"true"^^http://www.w3.org/2001/XMLSchema#boolean'])); - it('should parse a triple with a literal and a language code', + describe('should parse a triple with a literal and a language code', shouldParse(' "string"@en.', ['a', 'b', '"string"@en'])); - it('should normalize language codes to lowercase', + describe('should normalize language codes to lowercase', shouldParse(' "string"@EN.', ['a', 'b', '"string"@en'])); - it('should parse a triple with a literal and an IRI type', + describe('should parse a triple with a literal and an IRI type', shouldParse(' "string"^^.', ['a', 'b', '"string"^^http://example.org/type'])); - it('should parse a triple with a literal and a prefixed name type', + describe('should parse a triple with a literal and a prefixed name type', shouldParse('@prefix x: . "string"^^x:z.', ['a', 'b', '"string"^^urn:x:y#z'])); - it('should differentiate between IRI and prefixed name types', + describe('should differentiate between IRI and prefixed name types', shouldParse('@prefix : . :a :b "x"^^. :a :b "x"^^:urn:foo.', ['noturn:a', 'noturn:b', '"x"^^urn:foo'], ['noturn:a', 'noturn:b', '"x"^^noturn:urn:foo'])); @@ -103,27 +103,27 @@ describe('Parser', () => { }, })); - it('should parse a triple with the "a" shorthand predicate', + describe('should parse a triple with the "a" shorthand predicate', shouldParse(' a .', ['a', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', 't'])); - it('should parse triples with prefixes', + describe('should parse triples with prefixes', shouldParse('@prefix : <#>.\n' + '@prefix a: .\n' + ':x a:a a:b.', ['#x', 'a#a', 'a#b'])); - it('should parse triples with the prefix "prefix"', + describe('should parse triples with the prefix "prefix"', shouldParse('@prefix prefix: .' + 'prefix:a prefix:b prefix:c.', ['http://prefix.cc/a', 'http://prefix.cc/b', 'http://prefix.cc/c'])); - it('should parse triples with the prefix "base"', + describe('should parse triples with the prefix "base"', shouldParse('PREFIX base: ' + 'base:a base:b base:c.', ['http://prefix.cc/a', 'http://prefix.cc/b', 'http://prefix.cc/c'])); - it('should parse triples with the prefix "graph"', + describe('should parse triples with the prefix "graph"', shouldParse('PREFIX graph: ' + 'graph:a graph:b graph:c.', ['http://prefix.cc/a', 'http://prefix.cc/b', 'http://prefix.cc/c'])); @@ -143,7 +143,7 @@ describe('Parser', () => { line: 1, })); - it('should parse triples with prefixes and different punctuation', + describe('should parse triples with prefixes and different punctuation', shouldParse('@prefix : <#>.\n' + '@prefix a: .\n' + ':x a:a a:b;a:c a:d,a:e.', @@ -171,7 +171,7 @@ describe('Parser', () => { shouldNotParse(' "c"^^d:e ', 'Undefined prefix "d:" on line 1.')); - it('should parse triples with SPARQL prefixes', + describe('should parse triples with SPARQL prefixes', shouldParse('PREFIX : <#>\n' + 'PrEfIX a: ' + ':x a:a a:b.', @@ -189,22 +189,22 @@ describe('Parser', () => { shouldNotParse('@prefix : ;', 'Expected declaration to end with a dot on line 1.')); - it('should parse statements with shared subjects', + describe('should parse statements with shared subjects', shouldParse(' ;\n .', ['a', 'b', 'c'], ['a', 'd', 'e'])); - it('should parse statements with shared subjects and trailing semicolon', + describe('should parse statements with shared subjects and trailing semicolon', shouldParse(' ;\n ;\n.', ['a', 'b', 'c'], ['a', 'd', 'e'])); - it('should parse statements with shared subjects and multiple semicolons', + describe('should parse statements with shared subjects and multiple semicolons', shouldParse(' ;;\n .', ['a', 'b', 'c'], ['a', 'd', 'e'])); - it('should parse statements with shared subjects and predicates', + describe('should parse statements with shared subjects and predicates', shouldParse(' , .', ['a', 'b', 'c'], ['a', 'b', 'd'])); @@ -217,7 +217,7 @@ describe('Parser', () => { shouldNotParse(' . , .', 'Expected entity but got , on line 1.')); - it('should parse diamonds', + describe('should parse diamonds', shouldParse('<> <> <> <>.\n(<>) <> (<>) <>.', [BASE_IRI, BASE_IRI, BASE_IRI, BASE_IRI], ['_:b0', BASE_IRI, '_:b1', BASE_IRI], @@ -226,7 +226,7 @@ describe('Parser', () => { ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', BASE_IRI], ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); - it('should parse statements with named blank nodes', + describe('should parse statements with named blank nodes', shouldParse('_:a _:c.', ['_:b0_a', 'b', '_:b0_c'])); @@ -274,21 +274,21 @@ describe('Parser', () => { }, })); - it('should parse statements with empty blank nodes', + describe('should parse statements with empty blank nodes', shouldParse('[] [].', ['_:b0', 'b', '_:b1'])); - it('should parse statements with unnamed blank nodes in the subject', + describe('should parse statements with unnamed blank nodes in the subject', shouldParse('[ ] .', ['_:b0', 'c', 'd'], ['_:b0', 'a', 'b'])); - it('should parse statements with unnamed blank nodes in the object', + describe('should parse statements with unnamed blank nodes in the object', shouldParse(' [ ].', ['a', 'b', '_:b0'], ['_:b0', 'c', 'd'])); - it('should parse statements with unnamed blank nodes with a string object', + describe('should parse statements with unnamed blank nodes with a string object', shouldParse(' [ "x"].', ['a', 'b', '_:b0'], ['_:b0', 'c', '"x"'])); @@ -305,71 +305,71 @@ describe('Parser', () => { shouldNotParse(' ; ]', 'Unexpected ] on line 1.')); - it('should parse a blank node with a trailing semicolon', + describe('should parse a blank node with a trailing semicolon', shouldParse(' [ ; ].', ['a', 'b', '_:b0'], ['_:b0', 'u', 'v'])); - it('should parse a blank node with multiple trailing semicolons', + describe('should parse a blank node with multiple trailing semicolons', shouldParse(' [ ;;; ].', ['a', 'b', '_:b0'], ['_:b0', 'u', 'v'])); - it('should parse a multi-predicate blank node', + describe('should parse a multi-predicate blank node', shouldParse(' [ ; ].', ['a', 'b', '_:b0'], ['_:b0', 'u', 'v'], ['_:b0', 'w', 'z'])); - it('should parse a multi-predicate blank node with multiple semicolons', + describe('should parse a multi-predicate blank node with multiple semicolons', shouldParse(' [ ;;; ].', ['a', 'b', '_:b0'], ['_:b0', 'u', 'v'], ['_:b0', 'w', 'z'])); - it('should parse a multi-object blank node', + describe('should parse a multi-object blank node', shouldParse(' [ , ].', ['a', 'b', '_:b0'], ['_:b0', 'u', 'v'], ['_:b0', 'u', 'z'])); - it('should parse a multi-statement blank node ending with a literal', + describe('should parse a multi-statement blank node ending with a literal', shouldParse(' [ ; "z" ].', ['a', 'b', '_:b0'], ['_:b0', 'u', 'v'], ['_:b0', 'w', '"z"'])); - it('should parse a multi-statement blank node ending with a typed literal', + describe('should parse a multi-statement blank node ending with a typed literal', shouldParse(' [ ; "z"^^ ].', ['a', 'b', '_:b0'], ['_:b0', 'u', 'v'], ['_:b0', 'w', '"z"^^http://example.org/t'])); - it('should parse a multi-statement blank node ending with a string with language', + describe('should parse a multi-statement blank node ending with a string with language', shouldParse(' [ ; "z"^^ ].', ['a', 'b', '_:b0'], ['_:b0', 'u', 'v'], ['_:b0', 'w', '"z"^^http://example.org/t'])); - it('should parse a multi-statement blank node with trailing semicolon', + describe('should parse a multi-statement blank node with trailing semicolon', shouldParse(' [ ; ; ].', ['a', 'b', '_:b0'], ['_:b0', 'u', 'v'], ['_:b0', 'w', 'z'])); - it('should parse statements with nested blank nodes in the subject', + describe('should parse statements with nested blank nodes in the subject', shouldParse('[ [ ]] .', ['_:b0', 'c', 'd'], ['_:b0', 'a', '_:b1'], ['_:b1', 'x', 'y'])); - it('should parse statements with nested blank nodes in the object', + describe('should parse statements with nested blank nodes in the object', shouldParse(' [ [ ]].', ['a', 'b', '_:b0'], ['_:b0', 'c', '_:b1'], ['_:b1', 'd', 'e'])); - it('should reuse identifiers of blank nodes within and outside of graphs', + describe('should reuse identifiers of blank nodes within and outside of graphs', shouldParse('_:a _:c. { _:a _:c }', ['_:b0_a', 'b', '_:b0_c'], ['_:b0_a', 'b', '_:b0_c', 'g'])); @@ -378,7 +378,7 @@ describe('Parser', () => { shouldNotParse('[ .', 'Expected punctuation to follow "http://example.org/b" on line 1.')); - it('should parse a statements with only an anonymous node', + describe('should parse a statements with only an anonymous node', shouldParse('[

].', ['_:b0', 'p', 'o'])); @@ -390,45 +390,45 @@ describe('Parser', () => { shouldNotParse('[[

]].', 'Disallowed blank node as predicate on line 1.')); - it('should parse statements with an empty list in the subject', + describe('should parse statements with an empty list in the subject', shouldParse('() .', ['http://www.w3.org/1999/02/22-rdf-syntax-ns#nil', 'a', 'b'])); - it('should parse statements with an empty list in the object', + describe('should parse statements with an empty list in the object', shouldParse(' ().', ['a', 'b', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); - it('should parse statements with a single-element list in the subject', + describe('should parse statements with a single-element list in the subject', shouldParse('() .', ['_:b0', 'a', 'b'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'x'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); - it('should parse statements with a single-element list in the object', + describe('should parse statements with a single-element list in the object', shouldParse(' ().', ['a', 'b', '_:b0'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'x'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); - it('should parse a list with a literal', + describe('should parse a list with a literal', shouldParse(' ("x").', ['a', 'b', '_:b0'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', '"x"'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); - it('should parse a list with a typed literal', + describe('should parse a list with a typed literal', shouldParse(' ("x"^^).', ['a', 'b', '_:b0'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', '"x"^^http://example.org/y'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); - it('should parse a list with a language-tagged literal', + describe('should parse a list with a language-tagged literal', shouldParse(' ("x"@en-GB).', ['a', 'b', '_:b0'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', '"x"@en-gb'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); - it('should parse statements with a multi-element list in the subject', + describe('should parse statements with a multi-element list in the subject', shouldParse('( ) .', ['_:b0', 'a', 'b'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'x'], @@ -436,7 +436,7 @@ describe('Parser', () => { ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'y'], ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); - it('should parse statements with a multi-element list in the object', + describe('should parse statements with a multi-element list in the object', shouldParse(' ( ).', ['a', 'b', '_:b0'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'x'], @@ -444,7 +444,7 @@ describe('Parser', () => { ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'y'], ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); - it('should parse statements with a multi-element literal list in the object', + describe('should parse statements with a multi-element literal list in the object', shouldParse(' ("x" "y"@en-GB 1 "z"^^).', ['a', 'b', '_:b0'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', '"x"'], @@ -456,7 +456,7 @@ describe('Parser', () => { ['_:b3', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', '"z"^^http://example.org/t'], ['_:b3', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); - it('should parse statements with prefixed names in lists', + describe('should parse statements with prefixed names in lists', shouldParse('@prefix a: . (a:x a:y).', ['a', 'b', '_:b0'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'a#x'], @@ -468,7 +468,7 @@ describe('Parser', () => { shouldNotParse(' (a:x a:y).', 'Undefined prefix "a:" on line 1.')); - it('should parse statements with blank nodes in lists', + describe('should parse statements with blank nodes in lists', shouldParse(' (_:x _:y).', ['a', 'b', '_:b0'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', '_:b0_x'], @@ -476,7 +476,15 @@ describe('Parser', () => { ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', '_:b0_y'], ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); - it('should parse statements with a nested empty list', + describe('should parse a nested list', + shouldParse(' ( ( ) ).', + ['a', 'b', '_:b0'], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', '_:b1'], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'c'], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); + + describe('should parse statements with a nested empty list', shouldParse(' ( ()).', ['a', 'b', '_:b0'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'x'], @@ -484,7 +492,7 @@ describe('Parser', () => { ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'], ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); - it('should parse statements with non-empty nested lists', + describe('should parse statements with non-empty nested lists', shouldParse(' ( ()).', ['a', 'b', '_:b0'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'x'], @@ -494,13 +502,152 @@ describe('Parser', () => { ['_:b2', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'y'], ['_:b2', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); - it('should parse statements with a list containing a blank node', + describe('should parse statements with a list containing a quoted triple', + shouldParse(' ( << >> ) .', + ['a', 'b', '_:b0'], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', ['c', 'd', 'e']], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); + + describe('should parse statements with a list containing a quoted triple and iri after', + shouldParse(' ( << >> ) .', + ['a', 'b', '_:b0'], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', ['c', 'd', 'e']], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', '_:b1'], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'f'], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); + + describe('should parse statements with a list containing a quoted triple and iri before', + shouldParse(' ( << >> ) .', + ['a', 'b', '_:b0'], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'f'], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', '_:b1'], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', ['c', 'd', 'e']], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); + + describe('should parse statements with a list containing a 2 quoted triples', + shouldParse(' ( << >> << >> ) .', + ['a', 'b', '_:b0'], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', ['c', 'd', 'e']], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', '_:b1'], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', ['c1', 'd1', 'e1']], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); + + + describe('should parse statements with a list containing a 3 quoted triples', + shouldParse(' ( << >> << >> << >> ) .', + ['a', 'b', '_:b0'], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', ['c', 'd', 'e']], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', '_:b1'], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', ['c1', 'd1', 'e1']], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', '_:b2'], + ['_:b2', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', ['c2', 'd2', 'e2']], + ['_:b2', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); + + describe('should parse statements with a list containing a 1 quoted triple and 2 iris', + shouldParse(' ( << >> ) .', + ['a', 'b', '_:b0'], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', ['c', 'd', 'e']], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', '_:b1'], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'h'], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', '_:b2'], + ['_:b2', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'i'], + ['_:b2', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); + + describe('should parse statements with a list containing a 1 quoted triple between 2 iris', + shouldParse(' ( << >> ) .', + ['a', 'b', '_:b0'], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'h'], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', '_:b1'], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', ['c', 'd', 'e']], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', '_:b2'], + ['_:b2', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'i'], + ['_:b2', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); + + + describe('should parse a nested list containing 1 quoted triple', + shouldParse(' ( ( << >> ) ).', + ['a', 'b', '_:b0'], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', '_:b1'], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', ['c', 'd', 'e']], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); + + describe('should parse statements with a list containing a quoted triple with list as subject', + shouldParse('( << >> ) .', + ['_:b0', 'a', 'b'], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', ['c', 'd', 'e']], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); + + describe('should parse statements with a list containing a quoted triple and iri after with list as subject', + shouldParse('( << >> ) .', + ['_:b0', 'a', 'b'], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', ['c', 'd', 'e']], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', '_:b1'], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'f'], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); + + describe('should parse statements with a list containing a quoted triple and iri before with list as subject', + shouldParse('( << >> ) .', + ['_:b0', 'a', 'b'], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'f'], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', '_:b1'], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', ['c', 'd', 'e']], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); + + describe('should parse statements with a list containing a 2 quoted triples with list as subject', + shouldParse('( << >> << >> ) .', + ['_:b0', 'a', 'b'], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', ['c', 'd', 'e']], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', '_:b1'], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', ['c1', 'd1', 'e1']], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); + + + describe('should parse statements with a list containing a 3 quoted triples with list as subject', + shouldParse('( << >> << >> << >> ) .', + ['_:b0', 'a', 'b'], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', ['c', 'd', 'e']], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', '_:b1'], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', ['c1', 'd1', 'e1']], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', '_:b2'], + ['_:b2', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', ['c2', 'd2', 'e2']], + ['_:b2', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); + + describe('should parse statements with a list containing a 1 quoted triple and 2 iris with list as subject', + shouldParse('( << >> ) .', + ['_:b0', 'a', 'b'], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', ['c', 'd', 'e']], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', '_:b1'], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'h'], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', '_:b2'], + ['_:b2', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'i'], + ['_:b2', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); + + describe('should parse statements with a list containing a 1 quoted triple between 2 iris with list as subject', + shouldParse('( << >> ) .', + ['_:b0', 'a', 'b'], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'h'], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', '_:b1'], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', ['c', 'd', 'e']], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', '_:b2'], + ['_:b2', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'i'], + ['_:b2', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); + + describe('should parse a nested list containing 1 quoted triple with list as subject', + shouldParse('( ( << >> ) ) .', + ['_:b0', 'a', 'b'], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', '_:b1'], + ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', ['c', 'd', 'e']], + ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); + + describe('should parse statements with a list containing a blank node with list as subject', shouldParse('([]) .', ['_:b0', 'a', 'b'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', '_:b1'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); - it('should parse statements with a list containing multiple blank nodes', + describe('should parse statements with a list containing multiple blank nodes with list as subject', shouldParse('([] [ ]) .', ['_:b0', 'a', 'b'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', '_:b1'], @@ -509,7 +656,7 @@ describe('Parser', () => { ['_:b2', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'], ['_:b3', 'x', 'y'])); - it('should parse statements with a blank node containing a list', + describe('should parse statements with a blank node containing a list with list as subject', shouldParse('[ ()] .', ['_:b0', 'c', 'd'], ['_:b0', 'a', '_:b1'], @@ -520,7 +667,7 @@ describe('Parser', () => { shouldNotParse(' (]).', 'Expected entity but got ] on line 1.')); - it('should resolve IRIs against @base', + describe('should resolve IRIs against @base', shouldParse('@base .\n' + ' .\n' + '@base .\n' + @@ -532,7 +679,7 @@ describe('Parser', () => { shouldNotParse('@BASE .', 'Expected entity but got @BASE on line 1.')); - it('should resolve IRIs against SPARQL base', + describe('should resolve IRIs against SPARQL base', shouldParse('BASE \n' + ' . ' + 'BASE ' + @@ -540,7 +687,7 @@ describe('Parser', () => { ['http://ex.org/a', 'http://ex.org/b', 'http://ex.org/c'], ['http://ex.org/d/e', 'http://ex.org/d/f', 'http://ex.org/d/g'])); - it('should resolve IRIs against a @base with query string', + describe('should resolve IRIs against a @base with query string', shouldParse('@base .\n' + '<> .\n' + '@base .\n' + @@ -548,7 +695,7 @@ describe('Parser', () => { ['http://ex.org/?foo', 'http://ex.org/b', 'http://ex.org/c'], ['http://ex.org/d/?bar', 'http://ex.org/d/f', 'http://ex.org/d/g'])); - it('should resolve IRIs with query string against @base', + describe('should resolve IRIs with query string against @base', shouldParse('@base .\n' + ' .\n' + '@base .\n' + @@ -559,7 +706,7 @@ describe('Parser', () => { ['http://ex.org/d?', 'http://ex.org/d?a', 'http://ex.org/d?a=b'], ['http://ex.org/d?e', 'http://ex.org/d?a', 'http://ex.org/d?a=b'])); - it('should not resolve IRIs with colons', + describe('should not resolve IRIs with colons', shouldParse('@base .\n' + ' .\n' + ' .\n' + @@ -576,7 +723,7 @@ describe('Parser', () => { shouldNotParse('@base .', 'Expected valid IRI to follow base declaration on line 1.')); - it('should resolve datatype IRIs against @base', + describe('should resolve datatype IRIs against @base', shouldParse('@base .\n' + ' "c"^^.\n' + '@base .\n' + @@ -584,157 +731,157 @@ describe('Parser', () => { ['http://ex.org/a', 'http://ex.org/b', '"c"^^http://ex.org/d'], ['http://ex.org/d/e', 'http://ex.org/d/f', '"g"^^http://ex.org/d/h'])); - it('should resolve IRIs against a base with a fragment', + describe('should resolve IRIs against a base with a fragment', shouldParse('@base .\n' + ' <#c>.\n', ['http://ex.org/a', 'http://ex.org/b', 'http://ex.org/foo#c'])); - it('should resolve IRIs with an empty fragment', + describe('should resolve IRIs with an empty fragment', shouldParse('@base .\n' + '<#> <#c>.\n', ['http://ex.org/foo#', 'http://ex.org/b#', 'http://ex.org/foo#c'])); - it('should not resolve prefixed names', + describe('should not resolve prefixed names', shouldParse('PREFIX ex: \n' + 'ex:a ex:b ex:c .', ['http://ex.org/a/bb/ccc/../a', 'http://ex.org/a/bb/ccc/../b', 'http://ex.org/a/bb/ccc/../c'])); - it('should parse an empty default graph', + describe('should parse an empty default graph', shouldParse('{}')); - it('should parse a one-triple default graph ending without a dot', + describe('should parse a one-triple default graph ending without a dot', shouldParse('{ }', ['a', 'b', 'c'])); - it('should parse a one-triple default graph ending with a dot', + describe('should parse a one-triple default graph ending with a dot', shouldParse('{ .}', ['a', 'b', 'c'])); - it('should parse a three-triple default graph ending without a dot', + describe('should parse a three-triple default graph ending without a dot', shouldParse('{ ; ,}', ['a', 'b', 'c'], ['a', 'd', 'e'], ['a', 'd', 'f'])); - it('should parse a three-triple default graph ending with a dot', + describe('should parse a three-triple default graph ending with a dot', shouldParse('{ ; ,.}', ['a', 'b', 'c'], ['a', 'd', 'e'], ['a', 'd', 'f'])); - it('should parse a three-triple default graph ending with a semicolon', + describe('should parse a three-triple default graph ending with a semicolon', shouldParse('{ ; ,;}', ['a', 'b', 'c'], ['a', 'd', 'e'], ['a', 'd', 'f'])); - it('should parse a default graph with a blank node ending with a dot', + describe('should parse a default graph with a blank node ending with a dot', shouldParse('{ [

]. }', ['_:b0', 'p', 'o'])); - it('should parse a default graph with a blank node ending without a dot', + describe('should parse a default graph with a blank node ending without a dot', shouldParse('{ [

] }', ['_:b0', 'p', 'o'])); - it('should parse an empty named graph with an IRI', + describe('should parse an empty named graph with an IRI', shouldParse('{}')); - it('should parse a one-triple named graph with an IRI ending without a dot', + describe('should parse a one-triple named graph with an IRI ending without a dot', shouldParse(' { }', ['a', 'b', 'c', 'g'])); - it('should parse a one-triple named graph with an IRI ending with a dot', + describe('should parse a one-triple named graph with an IRI ending with a dot', shouldParse('{ .}', ['a', 'b', 'c', 'g'])); - it('should parse a three-triple named graph with an IRI ending without a dot', + describe('should parse a three-triple named graph with an IRI ending without a dot', shouldParse(' { ; ,}', ['a', 'b', 'c', 'g'], ['a', 'd', 'e', 'g'], ['a', 'd', 'f', 'g'])); - it('should parse a three-triple named graph with an IRI ending with a dot', + describe('should parse a three-triple named graph with an IRI ending with a dot', shouldParse('{ ; ,.}', ['a', 'b', 'c', 'g'], ['a', 'd', 'e', 'g'], ['a', 'd', 'f', 'g'])); - it('should parse an empty named graph with a prefixed name', + describe('should parse an empty named graph with a prefixed name', shouldParse('@prefix g: .\ng:h {}')); - it('should parse a one-triple named graph with a prefixed name ending without a dot', + describe('should parse a one-triple named graph with a prefixed name ending without a dot', shouldParse('@prefix g: .\ng:h { }', ['a', 'b', 'c', 'g#h'])); - it('should parse a one-triple named graph with a prefixed name ending with a dot', + describe('should parse a one-triple named graph with a prefixed name ending with a dot', shouldParse('@prefix g: .\ng:h{ .}', ['a', 'b', 'c', 'g#h'])); - it('should parse a three-triple named graph with a prefixed name ending without a dot', + describe('should parse a three-triple named graph with a prefixed name ending without a dot', shouldParse('@prefix g: .\ng:h { ; ,}', ['a', 'b', 'c', 'g#h'], ['a', 'd', 'e', 'g#h'], ['a', 'd', 'f', 'g#h'])); - it('should parse a three-triple named graph with a prefixed name ending with a dot', + describe('should parse a three-triple named graph with a prefixed name ending with a dot', shouldParse('@prefix g: .\ng:h{ ; ,.}', ['a', 'b', 'c', 'g#h'], ['a', 'd', 'e', 'g#h'], ['a', 'd', 'f', 'g#h'])); - it('should parse a named graph with a blank node ending with a dot', + describe('should parse a named graph with a blank node ending with a dot', shouldParse(' { [

]. }', ['_:b0', 'p', 'o', 'g'])); - it('should parse a named graph with a blank node ending without a dot', + describe('should parse a named graph with a blank node ending without a dot', shouldParse(' { [

] }', ['_:b0', 'p', 'o', 'g'])); - it('should parse an empty anonymous graph', + describe('should parse an empty anonymous graph', shouldParse('[] {}')); - it('should parse a one-triple anonymous graph ending without a dot', + describe('should parse a one-triple anonymous graph ending without a dot', shouldParse('[] { }', ['a', 'b', 'c', '_:b0'])); - it('should parse a one-triple anonymous graph ending with a dot', + describe('should parse a one-triple anonymous graph ending with a dot', shouldParse('[]{ .}', ['a', 'b', 'c', '_:b0'])); - it('should parse a three-triple anonymous graph ending without a dot', + describe('should parse a three-triple anonymous graph ending without a dot', shouldParse('[] { ; ,}', ['a', 'b', 'c', '_:b0'], ['a', 'd', 'e', '_:b0'], ['a', 'd', 'f', '_:b0'])); - it('should parse a three-triple anonymous graph ending with a dot', + describe('should parse a three-triple anonymous graph ending with a dot', shouldParse('[]{ ; ,.}', ['a', 'b', 'c', '_:b0'], ['a', 'd', 'e', '_:b0'], ['a', 'd', 'f', '_:b0'])); - it('should parse an empty named graph with an IRI and the GRAPH keyword', + describe('should parse an empty named graph with an IRI and the GRAPH keyword', shouldParse('GRAPH {}')); - it('should parse an empty named graph with a prefixed name and the GRAPH keyword', + describe('should parse an empty named graph with a prefixed name and the GRAPH keyword', shouldParse('@prefix g: .\nGRAPH g:h {}')); - it('should parse an empty anonymous graph and the GRAPH keyword', + describe('should parse an empty anonymous graph and the GRAPH keyword', shouldParse('GRAPH [] {}')); - it('should parse a one-triple named graph with an IRI and the GRAPH keyword', + describe('should parse a one-triple named graph with an IRI and the GRAPH keyword', shouldParse('GRAPH { }', ['a', 'b', 'c', 'g'])); - it('should parse a one-triple named graph with a prefixed name and the GRAPH keyword', + describe('should parse a one-triple named graph with a prefixed name and the GRAPH keyword', shouldParse('@prefix g: .\nGRAPH g:h { }', ['a', 'b', 'c', 'g#h'])); - it('should parse a one-triple anonymous graph and the GRAPH keyword', + describe('should parse a one-triple anonymous graph and the GRAPH keyword', shouldParse('GRAPH [] { }', ['a', 'b', 'c', '_:b0'])); - it('should parse a graph with 8-bit unicode escape sequences', + describe('should parse a graph with 8-bit unicode escape sequences', shouldParse('<\\U0001d400> {\n<\\U0001d400> <\\U0001d400> "\\U0001d400"^^<\\U0001d400>\n}\n', ['\ud835\udC00', '\ud835\udc00', '"\ud835\udc00"^^http://example.org/\ud835\udc00', '\ud835\udc00'])); @@ -744,7 +891,7 @@ describe('Parser', () => { it('should not parse a single opening brace', shouldNotParse('{', - 'Expected entity but got eof on line 1.')); + 'Unexpected "{" on line 1.')); it('should not parse a superfluous closing brace ', shouldNotParse('{}}', @@ -782,11 +929,15 @@ describe('Parser', () => { shouldNotParse('GRAPH GRAPH {}', 'Invalid graph label on line 1.')); - it('should parse a quad with 4 IRIs', + describe('should parse a quad with 4 IRIs', shouldParse(' .', ['a', 'b', 'c', 'g'])); - it('should parse a quad with 4 prefixed names', + it('should not parse a quad in a quoted triple', + shouldNotParse('<< >> .', + 'Expected >> to follow "http://example.org/c" but got IRI on line 1.')); + + describe('should parse a quad with 4 prefixed names', shouldParse('@prefix p: .\np:a p:b p:c p:g.', ['p#a', 'p#b', 'p#c', 'p#g'])); @@ -794,11 +945,11 @@ describe('Parser', () => { shouldNotParse(' p:g.', 'Undefined prefix "p:" on line 1.')); - it('should parse a quad with 3 IRIs and a literal', + describe('should parse a quad with 3 IRIs and a literal', shouldParse(' "c"^^ .', ['a', 'b', '"c"^^http://example.org/d', 'g'])); - it('should parse a quad with 2 blank nodes and a literal', + describe('should parse a quad with 2 blank nodes and a literal', shouldParse('_:a "c"^^ _:g.', ['_:b0_a', 'b', '"c"^^http://example.org/d', '_:b0_g'])); @@ -915,7 +1066,7 @@ describe('Parser', () => { } }); - it('should parse a string synchronously if no callback is given', () => { + describe('should parse a string synchronously if no callback is given', () => { const triples = new Parser().parse('@prefix a: . a:a a:b a:c.'); triples.should.deep.equal([ new Quad(termFromId('urn:a:a'), termFromId('urn:a:b'), @@ -933,84 +1084,129 @@ describe('Parser', () => { .should.throw('Expected entity but got eof on line 1'); }); - it('should parse an RDF* triple with a triple with iris as subject correctly', () => { + describe('should parse an RDF-star triple with a triple with iris as subject correctly', () => { shouldParse('<< >> .', [['a', 'b', 'c'], 'b', 'c']); }); - it('should not parse an RDF* triple with a triple as predicate', + it('should not parse an RDF-star triple with a triple as predicate', shouldNotParse(' << >> ', 'Expected entity but got << on line 1.')); - it('should parse an RDF* triple with a triple with blanknodes as subject correctly', + describe('should parse an RDF-star triple with a triple with blanknodes as subject correctly', shouldParse('<<_:a _:c>> .', [['_:b0_a', 'b', '_:b0_c'], 'b', 'c'])); - it('should parse an RDF* triple with a triple with blanknodes and literals as subject correctly', + describe('should parse an RDF-star triple with a triple with blanknodes and literals as subject correctly', shouldParse('<<_:a "c"^^>> .', [['_:b0_a', 'b', '"c"^^http://example.org/d'], 'b', 'c'])); - it('should parse an RDF* triple with a triple as object correctly', + describe('should parse an RDF-star triple with a triple as object correctly', shouldParse(' << >>.', ['a', 'b', ['a', 'b', 'c']])); - it('should parse an RDF* triple with a triple as object correctly', + describe('should parse an RDF-star triple with a triple as object correctly', shouldParse(' <<_:a _:c>>.', ['a', 'b', ['_:b0_a', 'b', '_:b0_c']])); - it('should parse an RDF* triple with a triple as object correctly', + describe('should parse an RDF-star triple with a triple as object correctly', shouldParse(' <<_:a "c"^^>>.', ['a', 'b', ['_:b0_a', 'b', '"c"^^http://example.org/d']])); - it('should parse nested triples correctly', + describe('should parse nested triples correctly', shouldParse('<<<< >> >> .', [[['a', 'b', 'c'], 'f', 'g'], 'd', 'e'])); - it('should parse nested triples correctly', + describe('should parse nested triples correctly', shouldParse(' << << >>>>.', ['d', 'e', ['f', 'g', ['a', 'b', 'c']]])); - it('should parse nested triples correctly', + describe('should parse nested triples correctly', shouldParse('<< << >>>> .', [['f', 'g', ['a', 'b', 'c']], 'd', 'e'])); - it('should parse nested triples correctly', + describe('should parse nested triples correctly', shouldParse(' <<<< >> >>.', ['d', 'e', [['a', 'b', 'c'], 'f', 'g']])); - it('should not parse nested RDF* statements that are partially closed', + it('should not parse compound blank node inside quoted triple subject', + shouldNotParse('<< [ ] >> .', + 'Compound blank node expressions not permitted within quoted triple on line 1.' + )); + + it('should not parse compound blank node inside quoted triple predicate', + shouldNotParse('<< [ ] >> .', + 'Disallowed blank node as predicate on line 1.' + )); + + it('should not parse compound blank node inside quoted triple object', + shouldNotParse('<< [ ] >> .', + 'Compound blank node expressions not permitted within quoted triple on line 1.' + )); + + it('should not parse empty list inside quoted triple subject', + shouldNotParse('<< () >> .', + 'Unexpected list inside quoted triple on line 1.' + )); + + it('should not parse non-empty list inside quoted triple subject', + shouldNotParse('<< ( ) >> .', + 'Unexpected list inside quoted triple on line 1.' + )); + + it('should not parse empty list inside quoted triple predicate', + shouldNotParse('<< () >> .', + 'Expected entity but got ( on line 1.' + )); + + it('should not parse non-empty list inside quoted triple predicate', + shouldNotParse('<< ( ) >> .', + 'Expected entity but got ( on line 1.' + )); + + it('should not parse empty list inside quoted triple object', + shouldNotParse('<< () >> .', + 'Unexpected list inside quoted triple on line 1.' + )); + + it('should not parse non-empty list inside quoted triple object', + shouldNotParse('<< ( ) >> .', + 'Unexpected list inside quoted triple on line 1.' + )); + + it('should not parse nested RDF-star statements that are partially closed', shouldNotParse(' <<<< >> .', - 'Expected entity but got . on line 1.' + 'Expected >> to follow "http://example.org/g" but got . on line 1.' )); - it('should not parse partially closed nested RDF* statements', + it('should not parse partially closed nested RDF-star statements', shouldNotParse(' <<<< >>.', - 'Expected >> but got IRI on line 1.' + 'Expected >> to follow "http://example.org/c" but got IRI on line 1.' )); - it('should not parse nested RDF* statements with too many closing tags', + it('should not parse nested RDF-star statements with too many closing tags', shouldNotParse(' <<<< >>>> >>.', 'Expected entity but got >> on line 1.' )); - it('should not parse nested RDF* statements with too many closing tags', + it('should not parse nested RDF-star statements with too many closing tags', shouldNotParse(' <<<< >> >>>>.', 'Expected entity but got >> on line 1.' )); - it('should not parse RDF* statements with too many closing tags', + it('should not parse RDF-star statements with too many closing tags', shouldNotParse(' >>.', 'Expected entity but got >> on line 1.' )); - it('should not parse incomplete RDF* statements', + it('should not parse incomplete RDF-star statements', shouldNotParse(' << >>.', 'Expected entity but got >> on line 1.' )); - it('should not parse incomplete RDF* statements', + it('should not parse incomplete RDF-star statements', shouldNotParse('<< >> .', 'Expected entity but got >> on line 1.' )); - it('should not parse incorrectly nested RDF* statements', + it('should not parse incorrectly nested RDF-star statements', shouldNotParse('>> <<', 'Expected entity but got >> on line 1.' )); @@ -1020,34 +1216,136 @@ describe('Parser', () => { 'Unexpected . on line 1.' )); - it('should parse an RDF* quad', - shouldParse('<< >> .', - [['a', 'b', 'c', 'd'], 'a', 'b'])); - - it('should not parse a malformed RDF* quad', + it('should not parse a malformed RDF-star quad', shouldNotParse('<< >> .', - 'Expected >> but got IRI on line 1.')); + 'Expected >> to follow "http://example.org/c" but got IRI on line 1.')); - it('should parse statements with a shared RDF* subject', + describe('should parse statements with a shared RDF-star subject', shouldParse('<< >> ;\n .', [['a', 'b', 'c'], 'b', 'c'], [['a', 'b', 'c'], 'd', 'c'])); - it('should parse statements with a shared RDF* subject', + // it('should parse no chunks (i.e. onEnd called immediately)', + // shouldParseChunks([])); + + it('should parse statements with a shared RDF-star subject that is chunked at double quotes', + shouldParseChunks(['<', '< >> ;\n .'], + [['a', 'b', 'c'], 'b', 'c'], + [['a', 'b', 'c'], 'd', 'c'])); + + it('should parse statements with a shared RDF-star subject that is chunked at every character', + shouldParseChunks('<< >> ;\n .'.split(''), + [['a', 'b', 'c'], 'b', 'c'], + [['a', 'b', 'c'], 'd', 'c'])); + + describe('should parse statements with a shared RDF-star subject', shouldParse('<< >> ;\n << >>.', [['a', 'b', 'c'], 'b', 'c'], [['a', 'b', 'c'], 'd', ['a', 'b', 'c']])); - it('should put nested triples in the default graph', + describe('should put nested triples in the default graph', shouldParse(' .\n<< >> .', ['a', 'b', 'c', 'g'], [['a', 'b', 'c'], 'd', 'e'])); + + describe('should parse an explicit triple with reified annotation', + shouldParse(' {| |} .', + ['a', 'b', 'c'], + [['a', 'b', 'c'], 'd', 'e'])); + + it('should not parse }|', + shouldNotParse(' }| |} .', 'Unexpected graph closing on line 1.')); + + it('should not parse |{', + shouldNotParse(' {| |{ .', 'Unexpected "|{" on line 1.')); + + it('should parse an explicit triple with reified annotation that is chunked at the pipe', + shouldParseChunks([' {| |', '} .'], + ['a', 'b', 'c'], + [['a', 'b', 'c'], 'd', 'e'])); + + it('should parse an explicit triple with reified annotation that is chunked at the pipe and each character after', + shouldParseChunks([' {| |', '}', ' ', '.', ''], + ['a', 'b', 'c'], + [['a', 'b', 'c'], 'd', 'e'])); + + it('should parse an explicit triple with reified annotation that is chunked at each annotation', + shouldParseChunks([' {', '| |', '} .'], + ['a', 'b', 'c'], + [['a', 'b', 'c'], 'd', 'e'])); + + it('should parse an quoted triple that is chunked on first quote', + shouldParseChunks(['<', '< >> .'], + [['a', 'b', 'c'], 'd', 'e'])); + + it('should parse an quoted triple that is chunked on ending quote', + shouldParseChunks(['<< >', '> .'], + [['a', 'b', 'c'], 'd', 'e'])); + + it('should parse an explicit triple with reified annotation that is chunked before annotation', + shouldParseChunks([' ', '{| |} .'], + ['a', 'b', 'c'], + [['a', 'b', 'c'], 'd', 'e'])); + + describe('should parse an explicit triple with nested reified annotation', + shouldParse(' {| {| |} |} .', + ['a', 'b', 'c'], + [['a', 'b', 'c'], 'd', 'e'], + [[['a', 'b', 'c'], 'd', 'e'], 'f', 'g'])); + + const q = ['http://example.com/ns#s', 'http://example.com/ns#p', + ['http://example.com/ns#a', 'http://example.com/ns#b', 'http://example.com/ns#c']]; + + describe('should parse an explicit triple with reified annotation containing prefixed iris', + shouldParse('PREFIX : \n :s :p <<:a :b :c>> {| :q :z |} .', + q, [q, 'http://example.com/ns#q', 'http://example.com/ns#z'])); + + describe('should parse an explicit triple with 2 reified annotations', + shouldParse(' {| ; |} .', + ['a', 'b', 'c'], + [['a', 'b', 'c'], 'd', 'e'], + [['a', 'b', 'c'], 'f', 'g'])); + + describe('should parse an explicit triple with reified annotation in a named graph', + shouldParse(' { {| |} . }', + ['a', 'b', 'c', 'G'], + [['a', 'b', 'c'], 'd', 'e', 'G'])); + + describe('should parse an explicit triple with 2 reified annotations in a named graph', + shouldParse(' { {| ; |} . }', + ['a', 'b', 'c', 'G'], + [['a', 'b', 'c'], 'd', 'e', 'G'], + [['a', 'b', 'c'], 'f', 'g', 'G'])); + + it('should not parse an annotated object in list', + shouldNotParse(' ( {| |} )', + 'Expected entity but got {| on line 1.')); + + it('should not parse an annotated statement in list', + shouldNotParse(' ( {| |} )', + 'Expected entity but got {| on line 1.')); + + it('should not parse fourth term in quoted triple', + shouldNotParse('<< >>

', + 'Expected >> to follow "http://example.org/c" but got IRI on line 1.')); + + it('should not parse fourth term in quoted triple object', + shouldNotParse('

<< >>', + 'Expected >> to follow "http://example.org/c" but got IRI on line 1.')); + + it('should not parse quoted triple as predicate', + shouldNotParse('

<< >> ', + 'Expected entity but got << on line 1.')); + + it('should not parse quoted quad as predicate', + shouldNotParse('

<< >> ', + 'Expected entity but got << on line 1.')); }); describe('An Parser instance without document IRI', () => { function parser() { return new Parser(); } - it('should keep relative IRIs', + describe('should keep relative IRIs', shouldParse(parser, '@prefix : <#>.\n' + ' .\n' + @@ -1055,7 +1353,7 @@ describe('Parser', () => { [termFromId('a'), termFromId('b'), termFromId('c'), termFromId('g')], [termFromId('#d'), termFromId('#e'), termFromId('#f'), termFromId('#g')])); - it('should keep empty IRIs', + describe('should keep empty IRIs', shouldParse(parser, '@prefix : <>.\n' + '<> <> <> <>.\n' + @@ -1067,7 +1365,7 @@ describe('Parser', () => { describe('An Parser instance with a document IRI', () => { function parser() { return new Parser({ baseIRI: 'http://ex.org/x/yy/zzz/f.ttl' }); } - it('should resolve IRIs against the document IRI', + describe('should resolve IRIs against the document IRI', shouldParse(parser, '@prefix : <#>.\n' + ' .\n' + @@ -1075,47 +1373,47 @@ describe('Parser', () => { ['http://ex.org/x/yy/zzz/a', 'http://ex.org/x/yy/zzz/b', 'http://ex.org/x/yy/zzz/c', 'http://ex.org/x/yy/zzz/g'], ['http://ex.org/x/yy/zzz/f.ttl#d', 'http://ex.org/x/yy/zzz/f.ttl#e', 'http://ex.org/x/yy/zzz/f.ttl#f', 'http://ex.org/x/yy/zzz/f.ttl#g'])); - it('should resolve IRIs with a trailing slash against the document IRI', + describe('should resolve IRIs with a trailing slash against the document IRI', shouldParse(parser, ' .\n', ['http://ex.org/a', 'http://ex.org/a/b', 'http://ex.org/a/b/c'])); - it('should resolve IRIs starting with ./ against the document IRI', + describe('should resolve IRIs starting with ./ against the document IRI', shouldParse(parser, '<./a> <./a/b> <./a/b/c>.\n', ['http://ex.org/x/yy/zzz/a', 'http://ex.org/x/yy/zzz/a/b', 'http://ex.org/x/yy/zzz/a/b/c'])); - it('should resolve IRIs starting with multiple ./ sequences against the document IRI', + describe('should resolve IRIs starting with multiple ./ sequences against the document IRI', shouldParse(parser, '<./././a> <./././././a/b> <././././././a/b/c>.\n', ['http://ex.org/x/yy/zzz/a', 'http://ex.org/x/yy/zzz/a/b', 'http://ex.org/x/yy/zzz/a/b/c'])); - it('should resolve IRIs starting with ../ against the document IRI', + describe('should resolve IRIs starting with ../ against the document IRI', shouldParse(parser, '<../a> <../a/b> <../a/b/c>.\n', ['http://ex.org/x/yy/a', 'http://ex.org/x/yy/a/b', 'http://ex.org/x/yy/a/b/c'])); - it('should resolve IRIs starting multiple ../ sequences against the document IRI', + describe('should resolve IRIs starting multiple ../ sequences against the document IRI', shouldParse(parser, '<../../a> <../../../a/b> <../../../../../../../../a/b/c>.\n', ['http://ex.org/x/a', 'http://ex.org/a/b', 'http://ex.org/a/b/c'])); - it('should resolve IRIs starting with mixes of ./ and ../ sequences against the document IRI', + describe('should resolve IRIs starting with mixes of ./ and ../ sequences against the document IRI', shouldParse(parser, '<.././a> <./.././a/b> <./.././.././a/b/c>.\n', ['http://ex.org/x/yy/a', 'http://ex.org/x/yy/a/b', 'http://ex.org/x/a/b/c'])); - it('should resolve IRIs starting with .x, ..x, or .../ against the document IRI', + describe('should resolve IRIs starting with .x, ..x, or .../ against the document IRI', shouldParse(parser, '<.x/a> <..x/a/b> <.../a/b/c>.\n', ['http://ex.org/x/yy/zzz/.x/a', 'http://ex.org/x/yy/zzz/..x/a/b', 'http://ex.org/x/yy/zzz/.../a/b/c'])); - it('should resolve datatype IRIs against the document IRI', + describe('should resolve datatype IRIs against the document IRI', shouldParse(parser, ' "c"^^.', ['http://ex.org/x/yy/zzz/a', 'http://ex.org/x/yy/zzz/b', '"c"^^http://ex.org/x/yy/zzz/d'])); - it('should resolve IRIs in lists against the document IRI', + describe('should resolve IRIs in lists against the document IRI', shouldParse(parser, '( )

( ).', ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'http://ex.org/x/yy/zzz/a'], @@ -1128,7 +1426,7 @@ describe('Parser', () => { ['_:b3', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'http://ex.org/x/yy/zzz/d'], ['_:b3', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'])); - it('should respect @base statements', + describe('should respect @base statements', shouldParse(parser, ' .\n' + '@base .\n' + @@ -1146,7 +1444,7 @@ describe('Parser', () => { describe('A Parser instance with a blank node prefix', () => { function parser() { return new Parser({ baseIRI: BASE_IRI, blankNodePrefix: '_:blank' }); } - it('should use the given prefix for blank nodes', + describe('should use the given prefix for blank nodes', shouldParse(parser, '_:a _:c.\n', ['_:blanka', 'b', '_:blankc'])); @@ -1155,7 +1453,7 @@ describe('Parser', () => { describe('A Parser instance with an empty blank node prefix', () => { function parser() { return new Parser({ baseIRI: BASE_IRI, blankNodePrefix: '' }); } - it('should not use a prefix for blank nodes', + describe('should not use a prefix for blank nodes', shouldParse(parser, '_:a _:c.\n', ['_:a', 'b', '_:c'])); @@ -1164,17 +1462,17 @@ describe('Parser', () => { describe('A Parser instance with a non-string format', () => { function parser() { return new Parser({ baseIRI: BASE_IRI, format: 1 }); } - it('should parse a single triple', + describe('should parse a single triple', shouldParse(parser, ' .', ['a', 'b', 'c'])); - it('should parse a graph', + describe('should parse a graph', shouldParse(parser, '{ }', ['a', 'b', 'c'])); }); describe('A Parser instance for the Turtle format', () => { - function parser() { return new Parser({ baseIRI: BASE_IRI, format: 'Turtle' }); } + function parser() { return new Parser({ baseIRI: BASE_IRI, format: 'Turtle', rdfStar: false }); } - it('should parse a single triple', + describe('should parse a single triple', shouldParse(parser, ' .', ['a', 'b', 'c'])); it('should not parse a default graph', @@ -1218,41 +1516,59 @@ describe('Parser', () => { shouldNotParse(parser, '1 .', 'Unexpected literal on line 1.')); - it('should not parse RDF* in the subject position', + it('should not parse RDF-star in the subject position', shouldNotParse(parser, '<< >> .', - 'Unexpected RDF* syntax on line 1.')); + 'Unexpected RDF-star syntax on line 1.')); + + it('should not parse annotated statement', + shouldNotParse(parser, ' {| |} .', + 'Unexpected RDF-star syntax on line 1.')); - it('should not parse RDF* in the object position', + it('should not parse RDF-star in the object position', shouldNotParse(parser, ' < >>.', - 'Unexpected RDF* syntax on line 1.')); + 'Unexpected RDF-star syntax on line 1.')); + + it('should not parse RDF-star in the object list', + shouldNotParse(parser, ' ( < >> ).', + 'Unexpected RDF-star syntax on line 1.')); + + it('should not parse RDF-star in the subject list', + shouldNotParse(parser, '( < >> ) .', + 'Unexpected RDF-star syntax on line 1.')); }); describe('A Parser instance for the TurtleStar format', () => { function parser() { return new Parser({ baseIRI: BASE_IRI, format: 'TurtleStar' }); } - it('should parse RDF*', + describe('should parse RDF-star', shouldParse(parser, '<< >> .', [['a', 'b', 'c'], 'b', 'c'])); it('should not parse nested quads', shouldNotParse(parser, '<<_:a _:b >> "c" .', - 'Expected >> to follow "_:b0_b" on line 1.')); + 'Expected >> to follow "_:b0_b" but got IRI on line 1.')); }); - describe('A Parser instance for the TriG format', () => { - function parser() { return new Parser({ baseIRI: BASE_IRI, format: 'TriG' }); } + describe('A Parser instance for the TriG format with rdfStar support disabled', () => { + function parser() { return new Parser({ baseIRI: BASE_IRI, format: 'TriG', rdfStar: false }); } + + it('should parse a single triple chunked before a closing bracket', + shouldParseChunks(parser, [' .'], ['a', 'b', 'c'])); + + it('should parse a single triple chunked after an opening bracket', + shouldParseChunks(parser, [' <', 'b> .'], ['a', 'b', 'c'])); - it('should parse a single triple', + describe('should parse a single triple', shouldParse(parser, ' .', ['a', 'b', 'c'])); - it('should parse a default graph', + describe('should parse a default graph', shouldParse(parser, '{}')); - it('should parse a named graph', + describe('should parse a named graph', shouldParse(parser, ' {}')); - it('should parse a named graph with the GRAPH keyword', + describe('should parse a named graph with the GRAPH keyword', shouldParse(parser, 'GRAPH {}')); it('should not parse a quad', @@ -1279,35 +1595,35 @@ describe('Parser', () => { it('should not parse @forAll', shouldNotParse(parser, '@forAll .', 'Unexpected "@forAll" on line 1.')); - it('should not parse RDF* in the subject position', + it('should not parse RDF-star in the subject position', shouldNotParse(parser, '<< >> .', - 'Unexpected RDF* syntax on line 1.')); + 'Unexpected RDF-star syntax on line 1.')); - it('should not parse RDF* in the object position', + it('should not parse RDF-star in the object position', shouldNotParse(parser, ' << >>.', - 'Unexpected RDF* syntax on line 1.')); + 'Unexpected RDF-star syntax on line 1.')); }); - describe('A Parser instance for the TriGStar format', () => { - function parser() { return new Parser({ baseIRI: BASE_IRI, format: 'TriGStar' }); } + describe('A Parser instance for the TriGS format testing rdfStar support', () => { + function parser() { return new Parser({ baseIRI: BASE_IRI, format: 'TriG' }); } - it('should parse RDF*', + describe('should parse RDF-star', shouldParse(parser, '<< >> .', [['a', 'b', 'c'], 'a', 'b'])); it('should not parse nested quads', shouldNotParse(parser, '<<_:a _:b >> "c" .', - 'Expected >> to follow "_:b0_b" on line 1.')); + 'Expected >> to follow "_:b0_b" but got IRI on line 1.')); }); - describe('A Parser instance for the N-Triples format', () => { - function parser() { return new Parser({ baseIRI: BASE_IRI, format: 'N-Triples' }); } + describe('A Parser instance for the N-Triples format with rdfStar support disabled', () => { + function parser() { return new Parser({ baseIRI: BASE_IRI, format: 'N-Triples', rdfStar: false }); } - it('should parse a single triple', + describe('should parse a single triple', shouldParse(parser, '_:a "c".', ['_:b0_a', 'http://ex.org/b', '"c"'])); - it('should parse a single triple starting with Bom', + describe('should parse a single triple starting with Bom', shouldParse(parser, '\ufeff_:a "c".', ['_:b0_a', 'http://ex.org/b', '"c"'])); @@ -1354,35 +1670,38 @@ describe('Parser', () => { it('should not parse @forAll', shouldNotParse(parser, '@forAll .', 'Unexpected "@forAll" on line 1.')); - it('should not parse RDF* in the subject position', + it('should not parse an object list', + shouldNotParse(parser, ' , .', 'Invalid IRI on line 1.')); + + it('should not parse RDF-star in the subject position', shouldNotParse(parser, '<< >> .', - 'Unexpected RDF* syntax on line 1.')); + 'Unexpected RDF-star syntax on line 1.')); - it('should not parse RDF* in the object position', + it('should not parse RDF-star in the object position', shouldNotParse(parser, ' << >>.', - 'Unexpected RDF* syntax on line 1.')); + 'Unexpected RDF-star syntax on line 1.')); }); - describe('A Parser instance for the N-TriplesStar format', () => { - function parser() { return new Parser({ baseIRI: BASE_IRI, format: 'N-TriplesStar' }); } + describe('A Parser instance for the N-Triples format to test rdfStar support', () => { + function parser() { return new Parser({ baseIRI: BASE_IRI, format: 'N-Triples' }); } - it('should parse RDF*', + describe('should parse RDF-star', shouldParse(parser, '<<_:a _:c>> _:b .', [['_:b0_a', 'b', '_:b0_c'], 'a', '_:b0_b'])); it('should not parse nested quads', shouldNotParse(parser, '<<_:a _:b >> "c" .', - 'Expected >> to follow "_:b0_b" on line 1.')); + 'Expected >> to follow "_:b0_b" but got IRI on line 1.')); }); - describe('A Parser instance for the N-Quads format', () => { - function parser() { return new Parser({ baseIRI: BASE_IRI, format: 'N-Quads' }); } + describe('A Parser instance for the N-Quads format with rdfStar support disabled', () => { + function parser() { return new Parser({ baseIRI: BASE_IRI, format: 'N-Quads', rdfStar: false }); } - it('should parse a single triple', + describe('should parse a single triple', shouldParse(parser, '_:a "c".', ['_:b0_a', 'http://ex.org/b', '"c"'])); - it('should parse a single quad', + describe('should parse a single quad', shouldParse(parser, '_:a "c" .', ['_:b0_a', 'http://ex.org/b', '"c"', 'http://ex.org/g'])); @@ -1413,27 +1732,27 @@ describe('Parser', () => { it('should not parse @forAll', shouldNotParse(parser, '@forAll .', 'Unexpected "@forAll" on line 1.')); - it('should not parse RDF* in the subject position', + it('should not parse RDF-star in the subject position', shouldNotParse(parser, '<< >> .', - 'Unexpected RDF* syntax on line 1.')); + 'Unexpected RDF-star syntax on line 1.')); - it('should not parse RDF* in the object position', + it('should not parse RDF-star in the object position', shouldNotParse(parser, '_:a << >>.', - 'Unexpected RDF* syntax on line 1.')); + 'Unexpected RDF-star syntax on line 1.')); }); describe('A Parser instance for the N-QuadsStar format', () => { function parser() { return new Parser({ baseIRI: BASE_IRI, format: 'N-QuadsStar' }); } - it('should parse RDF*', + describe('should parse RDF-star', shouldParse(parser, '<<_:a _:c>> _:c .', [['_:b0_a', 'b', '_:b0_c'], 'a', '_:b0_c'])); }); - describe('A Parser instance for the N3 format', () => { - function parser() { return new Parser({ baseIRI: BASE_IRI, format: 'N3' }); } + describe('A Parser instance for the N3 format with rdfStar support disabled', () => { + function parser() { return new Parser({ baseIRI: BASE_IRI, format: 'N3', rdfStar: false }); } - it('should parse a single triple', + describe('should parse a single triple', shouldParse(parser, ' .', ['a', 'b', 'c'])); it('should not parse a default graph', @@ -1448,39 +1767,45 @@ describe('Parser', () => { it('should not parse a quad', shouldNotParse(parser, ' .', 'Expected punctuation to follow "http://example.org/c" on line 1.')); - it('allows a blank node in predicate position', + describe('allows a blank node in predicate position', shouldParse(parser, ' [] .', ['a', '_:b0', 'c'])); - it('allows a blank node label in predicate position', + describe('allows a blank node label in predicate position', shouldParse(parser, ' _:b .', ['a', '_:b0_b', 'c'])); - it('allows a blank node with properties in predicate position', + describe('allows a blank node with properties in predicate position', shouldParse(parser, ' [

] .', ['a', '_:b0', 'c'], ['_:b0', 'p', 'o'])); - it('should parse a variable', + describe('should parse a variable', shouldParse(parser, '?a ?b ?c.', ['?a', '?b', '?c'])); - it('should parse a simple equality', + describe('should parse a simple equality', shouldParse(parser, ' = .', ['a', 'http://www.w3.org/2002/07/owl#sameAs', 'b'])); - it('should parse a simple right implication', + describe('should parse a simple right implication', shouldParse(parser, ' => .', ['a', 'http://www.w3.org/2000/10/swap/log#implies', 'b'])); - it('should parse a simple left implication', + describe('should parse a simple left implication', shouldParse(parser, ' <= .', ['b', 'http://www.w3.org/2000/10/swap/log#implies', 'a'])); - it('should parse a right implication between one-triple graphs', + describe('should parse a right implication between one-triple graphs', shouldParse(parser, '{ ?a ?b . } => { ?a }.', ['_:b0', 'http://www.w3.org/2000/10/swap/log#implies', '_:b1'], ['?a', '?b', 'c', '_:b0'], ['d', 'e', '?a', '_:b1'])); - it('should parse a right implication between two-triple graphs', + it('should parse a right implication between one-triple graphs with chunk at first bracket', + shouldParseChunks(parser, ['{', ' ?a ?b . } => { ?a }.'], + ['_:b0', 'http://www.w3.org/2000/10/swap/log#implies', '_:b1'], + ['?a', '?b', 'c', '_:b0'], + ['d', 'e', '?a', '_:b1'])); + + describe('should parse a right implication between two-triple graphs', shouldParse(parser, '{ ?a ?b . . } => { ?a, }.', ['_:b0', 'http://www.w3.org/2000/10/swap/log#implies', '_:b1'], ['?a', '?b', 'c', '_:b0'], @@ -1488,13 +1813,13 @@ describe('Parser', () => { ['d', 'e', '?a', '_:b1'], ['d', 'e', 'f', '_:b1'])); - it('should parse a left implication between one-triple graphs', + describe('should parse a left implication between one-triple graphs', shouldParse(parser, '{ ?a ?b . } <= { ?a }.', ['_:b1', 'http://www.w3.org/2000/10/swap/log#implies', '_:b0'], ['?a', '?b', 'c', '_:b0'], ['d', 'e', '?a', '_:b1'])); - it('should parse a left implication between two-triple graphs', + describe('should parse a left implication between two-triple graphs', shouldParse(parser, '{ ?a ?b . . } <= { ?a, }.', ['_:b1', 'http://www.w3.org/2000/10/swap/log#implies', '_:b0'], ['?a', '?b', 'c', '_:b0'], @@ -1502,13 +1827,13 @@ describe('Parser', () => { ['d', 'e', '?a', '_:b1'], ['d', 'e', 'f', '_:b1'])); - it('should parse an equality of one-triple graphs', + describe('should parse an equality of one-triple graphs', shouldParse(parser, '{ ?a ?b . } = { ?a }.', ['_:b0', 'http://www.w3.org/2002/07/owl#sameAs', '_:b1'], ['?a', '?b', 'c', '_:b0'], ['d', 'e', '?a', '_:b1'])); - it('should parse an equality of two-triple graphs', + describe('should parse an equality of two-triple graphs', shouldParse(parser, '{ ?a ?b . . } = { ?a, }.', ['_:b0', 'http://www.w3.org/2002/07/owl#sameAs', '_:b1'], ['?a', '?b', 'c', '_:b0'], @@ -1516,7 +1841,7 @@ describe('Parser', () => { ['d', 'e', '?a', '_:b1'], ['d', 'e', 'f', '_:b1'])); - it('should parse nested implication graphs', + describe('should parse nested implication graphs', shouldParse(parser, '{ { ?a ?b ?c }<={ ?d ?e ?f }. } <= { { ?g ?h ?i } => { ?j ?k ?l } }.', ['_:b3', 'http://www.w3.org/2000/10/swap/log#implies', '_:b0'], ['_:b2', 'http://www.w3.org/2000/10/swap/log#implies', '_:b1', '_:b0'], @@ -1535,11 +1860,11 @@ describe('Parser', () => { ['_:b2.a', '_:b2.b', '_:b2.c', '_:b2'], ['_:b3.a', '_:b3.b', '_:b3.c', '_:b3'])); - it('should parse a @forSome statement', + describe('should parse a @forSome statement', shouldParse(parser, '@forSome . .', ['_:b0', '_:b0', '_:b0'])); - it('should parse a @forSome statement with multiple entities', + describe('should parse a @forSome statement with multiple entities', shouldParse(parser, '@prefix a: . @base . @forSome a:x, , a:z. a:x a:z.', ['_:b0', '_:b1', '_:b2'])); @@ -1555,17 +1880,17 @@ describe('Parser', () => { shouldNotParse(parser, '@forSome ?a.', 'Unexpected var on line 1.')); - it('should correctly scope @forSome statements', + describe('should correctly scope @forSome statements', shouldParse(parser, '@forSome . { @forSome . . }. .', ['_:b0', '_:b0', '_:b1'], ['_:b2', '_:b2', '_:b2', '_:b1'], ['_:b0', '_:b0', '_:b0'])); - it('should parse a @forAll statement', + describe('should parse a @forAll statement', shouldParse(parser, '@forAll . .', ['?b0', '?b0', '?b0'])); - it('should parse a @forAll statement with multiple entities', + describe('should parse a @forAll statement with multiple entities', shouldParse(parser, '@prefix a: . @base . @forAll a:x, , a:z. a:x a:z.', ['?b0', '?b1', '?b2'])); @@ -1581,19 +1906,19 @@ describe('Parser', () => { shouldNotParse(parser, '@forAll ?a.', 'Unexpected var on line 1.')); - it('should correctly scope @forAll statements', + describe('should correctly scope @forAll statements', shouldParse(parser, '@forAll . { @forAll . . }. .', ['?b0', '?b0', '_:b1'], ['?b2', '?b2', '?b2', '_:b1'], ['?b0', '?b0', '?b0'])); - it('should parse a ! path of length 2 as subject', + describe('should parse a ! path of length 2 as subject', shouldParse(parser, '@prefix : . @prefix fam: .' + ':joe!fam:mother a fam:Person.', ['ex:joe', 'f:mother', '_:b0'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', 'f:Person'])); - it('should parse a ! path of length 4 as subject', + describe('should parse a ! path of length 4 as subject', shouldParse(parser, '@prefix : . @prefix fam: . @prefix loc: .' + ':joe!fam:mother!loc:office!loc:zip loc:code 1234.', ['ex:joe', 'f:mother', '_:b0'], @@ -1601,13 +1926,13 @@ describe('Parser', () => { ['_:b1', 'l:zip', '_:b2'], ['_:b2', 'l:code', '"1234"^^http://www.w3.org/2001/XMLSchema#integer'])); - it('should parse a ! path of length 2 as object', + describe('should parse a ! path of length 2 as object', shouldParse(parser, '@prefix : . @prefix fam: .' + ' :joe!fam:mother.', ['x', 'is', '_:b0'], ['ex:joe', 'f:mother', '_:b0'])); - it('should parse a ! path of length 4 as object', + describe('should parse a ! path of length 4 as object', shouldParse(parser, '@prefix : . @prefix fam: . @prefix loc: .' + ' :joe!fam:mother!loc:office!loc:zip.', ['x', 'is', '_:b2'], @@ -1615,13 +1940,13 @@ describe('Parser', () => { ['_:b0', 'l:office', '_:b1'], ['_:b1', 'l:zip', '_:b2'])); - it('should parse a ^ path of length 2 as subject', + describe('should parse a ^ path of length 2 as subject', shouldParse(parser, '@prefix : . @prefix fam: .' + ':joe^fam:son a fam:Person.', ['_:b0', 'f:son', 'ex:joe'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', 'f:Person'])); - it('should parse a ^ path of length 4 as subject', + describe('should parse a ^ path of length 4 as subject', shouldParse(parser, '@prefix : . @prefix fam: .' + ':joe^fam:son^fam:sister^fam:mother a fam:Person.', ['_:b0', 'f:son', 'ex:joe'], @@ -1629,13 +1954,13 @@ describe('Parser', () => { ['_:b2', 'f:mother', '_:b1'], ['_:b2', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', 'f:Person'])); - it('should parse a ^ path of length 2 as object', + describe('should parse a ^ path of length 2 as object', shouldParse(parser, '@prefix : . @prefix fam: .' + ' :joe^fam:son.', ['x', 'is', '_:b0'], ['_:b0', 'f:son', 'ex:joe'])); - it('should parse a ^ path of length 4 as object', + describe('should parse a ^ path of length 4 as object', shouldParse(parser, '@prefix : . @prefix fam: .' + ' :joe^fam:son^fam:sister^fam:mother.', ['x', 'is', '_:b2'], @@ -1643,49 +1968,49 @@ describe('Parser', () => { ['_:b1', 'f:sister', '_:b0'], ['_:b2', 'f:mother', '_:b1'])); - it('should parse mixed !/^ paths as subject', + describe('should parse mixed !/^ paths as subject', shouldParse(parser, '@prefix : . @prefix fam: .' + ':joe!fam:mother^fam:mother a fam:Person.', ['ex:joe', 'f:mother', '_:b0'], ['_:b1', 'f:mother', '_:b0'], ['_:b1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', 'f:Person'])); - it('should parse mixed !/^ paths as object', + describe('should parse mixed !/^ paths as object', shouldParse(parser, '@prefix : . @prefix fam: .' + ' :joe!fam:mother^fam:mother.', ['x', 'is', '_:b1'], ['ex:joe', 'f:mother', '_:b0'], ['_:b1', 'f:mother', '_:b0'])); - it('should parse a ! path in a blank node as subject', + describe('should parse a ! path in a blank node as subject', shouldParse(parser, '@prefix : . @prefix fam: .' + '[fam:knows :joe!fam:mother] a fam:Person.', ['_:b0', 'f:knows', '_:b1'], ['ex:joe', 'f:mother', '_:b1'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', 'f:Person'])); - it('should parse a ! path in a blank node as object', + describe('should parse a ! path in a blank node as object', shouldParse(parser, '@prefix : . @prefix fam: .' + ' [fam:knows :joe!fam:mother].', ['x', 'is', '_:b0'], ['_:b0', 'f:knows', '_:b1'], ['ex:joe', 'f:mother', '_:b1'])); - it('should parse a ^ path in a blank node as subject', + describe('should parse a ^ path in a blank node as subject', shouldParse(parser, '@prefix : . @prefix fam: .' + '[fam:knows :joe^fam:son] a fam:Person.', ['_:b0', 'f:knows', '_:b1'], ['_:b1', 'f:son', 'ex:joe'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', 'f:Person'])); - it('should parse a ^ path in a blank node as object', + describe('should parse a ^ path in a blank node as object', shouldParse(parser, '@prefix : . @prefix fam: .' + ' [fam:knows :joe^fam:son].', ['x', 'is', '_:b0'], ['_:b0', 'f:knows', '_:b1'], ['_:b1', 'f:son', 'ex:joe'])); - it('should parse a ! path in a list as subject', + describe('should parse a ! path in a list as subject', shouldParse(parser, '@prefix : . @prefix fam: .' + '( :joe!fam:mother ) a :List.', ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', 'ex:List'], @@ -1697,7 +2022,7 @@ describe('Parser', () => { ['_:b3', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'], ['ex:joe', 'f:mother', '_:b2'])); - it('should parse a ! path in a list as object', + describe('should parse a ! path in a list as object', shouldParse(parser, '@prefix : . @prefix fam: .' + ' ( :joe!fam:mother ).', ['l', 'is', '_:b0'], @@ -1709,7 +2034,7 @@ describe('Parser', () => { ['_:b3', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'], ['ex:joe', 'f:mother', '_:b2'])); - it('should parse a ^ path in a list as subject', + describe('should parse a ^ path in a list as subject', shouldParse(parser, '@prefix : . @prefix fam: .' + '( :joe^fam:son ) a :List.', ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', 'ex:List'], @@ -1721,7 +2046,7 @@ describe('Parser', () => { ['_:b3', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'], ['_:b2', 'f:son', 'ex:joe'])); - it('should parse a ^ path in a list as object', + describe('should parse a ^ path in a list as object', shouldParse(parser, '@prefix : . @prefix fam: .' + ' ( :joe^fam:son ).', ['l', 'is', '_:b0'], @@ -1733,7 +2058,7 @@ describe('Parser', () => { ['_:b3', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'], ['_:b2', 'f:son', 'ex:joe'])); - it('should parse a formula as list item', + describe('should parse a formula as list item', shouldParse(parser, ' ( { a . } ).', ['a', 'findAll', '_:b0'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'b'], @@ -1750,56 +2075,64 @@ describe('Parser', () => { it('should not parse an invalid ^ path', shouldNotParse(parser, '^"invalid" ', 'Expected entity but got literal on line 1.')); - it('should parse literal as subject', + describe('should parse literal as subject', shouldParse(parser, ' {1 0}.', ['a', 'b', '_:b0'], ['"1"^^http://www.w3.org/2001/XMLSchema#integer', 'greaterThan', '"0"^^http://www.w3.org/2001/XMLSchema#integer', '_:b0'] )); - it('should parse literals with datatype as subject', + describe('should parse literals with datatype as subject', shouldParse(parser, ' {"a"^^ "b"^^}.', ['a', 'b', '_:b0'], ['"a"^^http://example.org/c', 'greaterThan', '"b"^^http://example.org/c', '_:b0'] )); - it('should parse literals with language as subject', + describe('should parse literals with language as subject', shouldParse(parser, ' {"bonjour"@fr "hello"@en}.', ['a', 'b', '_:b0'], ['"bonjour"@fr', 'sameAs', '"hello"@en', '_:b0'] )); - it('should not parse RDF* in the subject position', + it('should not parse RDF-star in the subject position', shouldNotParse(parser, '<< >> .', - 'Unexpected RDF* syntax on line 1.')); + 'Unexpected RDF-star syntax on line 1.')); - it('should not parse RDF* in the object position', + it('should not parse RDF-star in the object position', shouldNotParse(parser, ' << >>.', - 'Unexpected RDF* syntax on line 1.')); + 'Unexpected RDF-star syntax on line 1.')); }); - describe('A Parser instance for the N3Star format', () => { - function parser() { return new Parser({ baseIRI: BASE_IRI, format: 'N3Star' }); } + describe('A Parser instance for the N3 format testing rdfStar support', () => { + function parser() { return new Parser({ baseIRI: BASE_IRI, format: 'N3' }); } + + describe('should parse RDF-star path', + shouldParse(parser, '<< >>! .', + [['a', 'b', 'c'], 'p1', '_:b0'], ['_:b0', 'p2', 'o'])); + + describe('should parse RDF-star path', + shouldParse(parser, '<< >>!^ .', + [['a', 'b', 'c'], 'p1', '_:b0'], ['_:b1', 'p2', '_:b0'], ['_:b1', 'p3', 'o'])); - it('should parse RDF*', + describe('should parse RDF-star', shouldParse(parser, '<< >> .', [['a', 'b', 'c'], 'a', 'b'])); it('should not parse nested quads', shouldNotParse(parser, '<<_:a _:b >> "c" .', - 'Expected >> to follow "_:.b" on line 1.')); + 'Expected >> to follow "_:.b" but got IRI on line 1.')); }); describe('A Parser instance for the N3 format with the explicitQuantifiers option', () => { function parser() { return new Parser({ baseIRI: BASE_IRI, format: 'N3', explicitQuantifiers: true }); } - it('should parse a @forSome statement', + describe('should parse a @forSome statement', shouldParse(parser, '@forSome . .', ['', 'http://www.w3.org/2000/10/swap/reify#forSome', '_:b0', 'urn:n3:quantifiers'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'x', 'urn:n3:quantifiers'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil', 'urn:n3:quantifiers'], ['x', 'x', 'x'])); - it('should parse a @forSome statement with multiple entities', + describe('should parse a @forSome statement with multiple entities', shouldParse(parser, '@prefix a: . @base . @forSome a:x, , a:z. a:x a:z.', ['', 'http://www.w3.org/2000/10/swap/reify#forSome', '_:b0', 'urn:n3:quantifiers'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'a:x', 'urn:n3:quantifiers'], @@ -1810,7 +2143,7 @@ describe('Parser', () => { ['_:b2', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil', 'urn:n3:quantifiers'], ['a:x', 'b:y', 'a:z'])); - it('should correctly scope @forSome statements', + describe('should correctly scope @forSome statements', shouldParse(parser, '@forSome . { @forSome . . }. .', ['', 'http://www.w3.org/2000/10/swap/reify#forSome', '_:b0', 'urn:n3:quantifiers'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'x', 'urn:n3:quantifiers'], @@ -1822,14 +2155,14 @@ describe('Parser', () => { ['x', 'x', 'x', '_:b1'], ['x', 'x', 'x'])); - it('should parse a @forAll statement', + describe('should parse a @forAll statement', shouldParse(parser, '@forAll . .', ['', 'http://www.w3.org/2000/10/swap/reify#forAll', '_:b0', 'urn:n3:quantifiers'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'x', 'urn:n3:quantifiers'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil', 'urn:n3:quantifiers'], ['x', 'x', 'x'])); - it('should parse a @forAll statement with multiple entities', + describe('should parse a @forAll statement with multiple entities', shouldParse(parser, '@prefix a: . @base . @forAll a:x, , a:z. a:x a:z.', ['', 'http://www.w3.org/2000/10/swap/reify#forAll', '_:b0', 'urn:n3:quantifiers'], ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', 'a:x', 'urn:n3:quantifiers'], @@ -2301,7 +2634,31 @@ describe('Parser', () => { }); }); -function shouldParse(parser, input) { +// Split string into all combinations possible +function splitAllWays(result, left, right, chunkSize) { + // Push current left + right to the result list + result.push(left.concat(right)); + // document.write(left.concat(right) + '
'); + + // If we still have chars to work with in the right side then keep splitting + if (right.length > 1) { + // For each combination left/right split call splitAllWays() + for (let i = chunkSize; i < right.length; i += chunkSize) { + splitAllWays(result, left.concat(right.substring(0, i)), right.substring(i), chunkSize); + } + } + + // Return result + return result; +} + +// Return a large number of combinations for splitting the string to test chunking - anything with 5 or fewer +// characters will test every permutation of splits possible on the string +function getSplits(str) { + return splitAllWays([], [], str, Math.max(Math.floor(str.length / 6), 1)); +} + +function shouldParseChunks(parser, input) { const expected = Array.prototype.slice.call(arguments, 1); // Shift parameters as necessary if (parser.call) @@ -2309,15 +2666,77 @@ function shouldParse(parser, input) { else input = parser, parser = Parser; + const items = expected.map(mapToQuad); + + return _shouldParseChunks(parser, input, items); +} + +function _shouldParseChunks(parser, input, items) { return function (done) { - const results = []; + const results2 = []; + + let onData, onEnd; + new parser({ baseIRI: BASE_IRI }).parse({ + baseIRI: BASE_IRI, + on: (event, callback) => { + switch (event) { + case 'data': onData = callback; break; + case 'end': onEnd = callback; break; + } + }, + }, + (error, triple) => { + expect(error).not.to.exist; + if (triple) + results2.push(triple); + else + toSortedJSON(results2).should.equal(toSortedJSON(items)), done(); + } + ); + + for (const chunk of input) { + onData(chunk); + } + + onEnd(); + }; +} + +function shouldParse(parser, input) { + return () => { + const expected = Array.prototype.slice.call(arguments, 1); + // Shift parameters as necessary + if (parser.call) + expected.shift(); + else + input = parser, parser = Parser; + const items = expected.map(mapToQuad); - new parser({ baseIRI: BASE_IRI }).parse(input, (error, triple) => { - expect(error).not.to.exist; - if (triple) - results.push(triple); - else + + for (const chunk of [ + // Split at every character + input.split(''), + // Random splits + ...getSplits(input), + // Exactly one split in each position + ...input.split('').map((_, i) => [input.slice(0, i), input.slice(i)]), + ] + // Ignore degenerate cases (for now) + .filter(arr => arr.length > 0 && (arr.length !== 1 || arr[0] !== '')) + ) { + it(`should run on chunking ${JSON.stringify(chunk)}`, _shouldParseChunks(parser, chunk, items)); + } + + it('should run on full string', done => { + // Test parsing of whole string + const results = []; + new parser({ baseIRI: BASE_IRI }).parse(input, (error, triple) => { + expect(error).not.to.exist; + if (triple) + results.push(triple); + else toSortedJSON(results).should.equal(toSortedJSON(items)), done(); + }); }); }; } @@ -2339,7 +2758,7 @@ function mapToQuad(item) { function toSortedJSON(triples) { triples = triples.map(t => { return JSON.stringify([ - t.subject.toJSON(), t.predicate.toJSON(), t.object.toJSON(), t.graph.toJSON(), + t.subject && t.subject.toJSON(), t.predicate && t.predicate.toJSON(), t.object && t.object.toJSON(), t.graph && t.graph.toJSON(), ]); }); triples.sort(); diff --git a/test/N3Store-test.js b/test/N3Store-test.js index b7ca2dd9..424880e2 100644 --- a/test/N3Store-test.js +++ b/test/N3Store-test.js @@ -275,7 +275,7 @@ describe('Store', () => { }); }); - describe('removing matching quads for RDF*', () => { + describe('removing matching quads for RDF-star', () => { let store; beforeEach(() => { store = new Store([ @@ -295,7 +295,7 @@ describe('Store', () => { store.size.should.eql(5); }); - it('should match RDF* and normal quads at the same time', done => { + it('should match RDF-star and normal quads at the same time', done => { const stream = store.removeMatches(null, 'p1', 'o2'); stream.on('end', () => { store.size.should.eql(3); @@ -1653,6 +1653,32 @@ describe('Store', () => { [...store.match(null, null, null, null)].should.have.length(3); }); + it('should include added elements in match if iteration has not yet started (deeply nested)', () => { + const m = store.match(null, null, null, null); + store.add(new Quad( + new NamedNode('s1'), + new NamedNode('p1'), + new Quad(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o3')) + ) + ); + store.add(new Quad( + new NamedNode('s1'), + new NamedNode('p1'), + new Quad( + new NamedNode('s1'), + new NamedNode('p1'), + new Quad( + new NamedNode('s1'), + new NamedNode('p1'), + new NamedNode('o3') + ) + ) + ) + ); + [...m].should.have.length(4); + [...store.match(null, null, null, null)].should.have.length(4); + }); + it('should still include results of original match after iterating while adding new data', () => { const m = store.match(null, null, null, null)[Symbol.iterator](); m.next().value.should.deep.equal(new Quad(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o1'))); diff --git a/test/Term-test.js b/test/Term-test.js index d052216d..750bc3e5 100644 --- a/test/Term-test.js +++ b/test/Term-test.js @@ -15,6 +15,54 @@ import { unescapeQuotes, } from '../src/N3DataFactory'; + +const DEEP_TRIPLE = new Quad( + new Quad( + new Quad( + new Quad( + new BlankNode('n3-000'), + new Variable('var-b'), + new Literal('"abc"@en-us'), + new NamedNode('http://ex.org/d') + ), + new Variable('var-b'), + new Quad( + new BlankNode('n3-000'), + new Variable('var-b'), + new Literal('"abc"@en-us'), + new NamedNode('http://ex.org/d') + ), + new NamedNode('http://ex.org/d') + ), + new Variable('var-b'), + new Quad( + new BlankNode('n3-000'), + new Variable('var-b'), + new Literal('"abc"@en-us'), + new NamedNode('http://ex.org/d') + ), + new NamedNode('http://ex.org/d') + ), + new NamedNode('http://ex.org/b'), + new Quad( + new Quad( + new BlankNode('n3-000'), + new Variable('var-b'), + new Literal('"abc"@en-us'), + new NamedNode('http://ex.org/d') + ), + new Variable('var-b'), + new Quad( + new BlankNode('n3-000'), + new Variable('var-b'), + new Literal('"abc"@en-us'), + new NamedNode('http://ex.org/d') + ), + new NamedNode('http://ex.org/d') + ), + new NamedNode('http://ex.org/d') +); + describe('Term', () => { describe('The Term module', () => { it('should be a function', () => { @@ -81,16 +129,17 @@ describe('Term', () => { }); it('should create a Quad with the default graph if the id doesnt specify the graph', () => { - termFromId('<>').should.deep.equal(new Quad( + const q = new Quad( new NamedNode('http://ex.org/a'), new NamedNode('http://ex.org/b'), new Literal('"abc"@en-us'), new DefaultGraph() - )); + ); + expect(q.equals(termFromId(termToId(q)))).equals(true); }); it('should create a Quad with the correct graph if the id specifies a graph', () => { - const id = '<>'; + const id = '["http://ex.org/a", "http://ex.org/b", "\\"abc\\"@en-us", "http://ex.org/d"]'; termFromId(id).should.deep.equal(new Quad( new NamedNode('http://ex.org/a'), new NamedNode('http://ex.org/b'), @@ -100,7 +149,7 @@ describe('Term', () => { }); it('should create a Quad correctly', () => { - const id = '<>'; + const id = '["http://ex.org/a", "http://ex.org/b", "http://ex.org/c"]'; termFromId(id).should.deep.equal(new Quad( new NamedNode('http://ex.org/a'), new NamedNode('http://ex.org/b'), @@ -110,7 +159,7 @@ describe('Term', () => { }); it('should create a Quad correctly', () => { - const id = '<<_:n3-123 ?var-a ?var-b _:n3-000>>'; + const id = '["_:n3-123", "?var-a", "?var-b", "_:n3-000"]'; termFromId(id).should.deep.equal(new Quad( new BlankNode('n3-123'), new Variable('var-a'), @@ -120,7 +169,7 @@ describe('Term', () => { }); it('should create a Quad correctly', () => { - const id = '<>'; + const id = '["?var-a", "?var-b", "\\"abc\\"@en-us", "?var-d"]'; termFromId(id).should.deep.equal(new Quad( new Variable('var-a'), new Variable('var-b'), @@ -130,7 +179,7 @@ describe('Term', () => { }); it('should create a Quad correctly', () => { - const id = '<<_:n3-000 ?var-b _:n3-123 http://ex.org/d>>'; + const id = '["_:n3-000", "?var-b", "_:n3-123", "http://ex.org/d"]'; termFromId(id).should.deep.equal(new Quad( new BlankNode('n3-000'), new Variable('var-b'), @@ -140,7 +189,7 @@ describe('Term', () => { }); it('should create a Quad correctly from literal containing escaped quotes', () => { - const id = '<<_:n3-000 ?var-b "Hello ""W""orl""d!"@en-us http://ex.org/d>>'; + const id = '["_:n3-000", "?var-b", "\\"Hello \\"W\\"orl\\"d!\\"@en-us", "http://ex.org/d"]'; termFromId(id).should.deep.equal(new Quad( new BlankNode('n3-000'), new Variable('var-b'), @@ -150,13 +199,19 @@ describe('Term', () => { }); it('should create a Quad correctly from literal containing escaped quotes', () => { - const id = '<<"Hello ""W""orl""d!"@en-us http://ex.org/b http://ex.org/c>>'; - termFromId(id).should.deep.equal(new Quad( + const q = new Quad( new Literal('"Hello "W"orl"d!"@en-us'), new NamedNode('http://ex.org/b'), new NamedNode('http://ex.org/c'), new DefaultGraph() - )); + ); + + termFromId(termToId(q)).should.deep.equal(q); + }); + + it('should correctly handle deeply nested quads', () => { + DEEP_TRIPLE.equals(termFromId(termToId(DEEP_TRIPLE))).should.equal(true); + termFromId(termToId(DEEP_TRIPLE)).equals(DEEP_TRIPLE).should.equal(true); }); describe('with a custom factory', () => { @@ -283,7 +338,7 @@ describe('Term', () => { new NamedNode('http://ex.org/b'), new Literal('"abc"@en-us'), new DefaultGraph() - )).should.equal('<>'); + )).should.equal('["http://ex.org/a","http://ex.org/b","\\"abc\\"@en-us"]'); }); it('should create an id from a Quad', () => { @@ -292,7 +347,7 @@ describe('Term', () => { new NamedNode('http://ex.org/b'), new Literal('"abc"@en-us'), new NamedNode('http://ex.org/d') - )).should.equal('<>'); + )).should.equal('["http://ex.org/a","http://ex.org/b","\\"abc\\"@en-us","http://ex.org/d"]'); }); it('should create an id from a manually created Quad', () => { @@ -303,7 +358,7 @@ describe('Term', () => { graph: new NamedNode('http://ex.org/d'), termType: 'Quad', value: '', - }).should.equal('<>'); + }).should.equal('["http://ex.org/a","http://ex.org/b","\\"abc\\"@en-us","http://ex.org/d"]'); }); it('should create an id with escaped literals from a Quad', () => { @@ -312,7 +367,7 @@ describe('Term', () => { new Variable('var-b'), new Literal('"Hello "W"orl"d!"@en-us'), new NamedNode('http://ex.org/d') - )).should.equal('<<_:n3-000 ?var-b "Hello ""W""orl""d!"@en-us http://ex.org/d>>'); + )).should.equal('["_:n3-000","?var-b","\\"Hello \\"W\\"orl\\"d!\\"@en-us","http://ex.org/d"]'); }); it('should create an id without graph from a Quad with default graph and Quad as subject', () => { @@ -326,7 +381,7 @@ describe('Term', () => { new NamedNode('http://ex.org/b'), new Literal('"abc"@en-us'), new DefaultGraph() - )).should.equal('<<<<_:n3-000 ?var-b "abc"@en-us http://ex.org/d>> http://ex.org/b "abc"@en-us>>'); + )).should.equal('[["_:n3-000","?var-b","\\"abc\\"@en-us","http://ex.org/d"],"http://ex.org/b","\\"abc\\"@en-us"]'); }); it('should create an id without graph from a Quad with default graph and Quad as object', () => { @@ -340,7 +395,7 @@ describe('Term', () => { new NamedNode('http://ex.org/d') ), new DefaultGraph() - )).should.equal('<<"abc"@en-us http://ex.org/b <<_:n3-000 ?var-b "abc"@en-us http://ex.org/d>>>>'); + )).should.equal('["\\"abc\\"@en-us","http://ex.org/b",["_:n3-000","?var-b","\\"abc\\"@en-us","http://ex.org/d"]]'); }); it('should create an id without graph from a Quad with default graph and Quad as subject and object', () => { @@ -359,7 +414,7 @@ describe('Term', () => { new NamedNode('http://ex.org/d') ), new DefaultGraph() - )).should.equal('<<<<_:n3-000 ?var-b "abc"@en-us http://ex.org/d>> http://ex.org/b <<_:n3-000 ?var-b "abc"@en-us http://ex.org/d>>>>'); + )).should.equal('[["_:n3-000","?var-b","\\"abc\\"@en-us","http://ex.org/d"],"http://ex.org/b",["_:n3-000","?var-b","\\"abc\\"@en-us","http://ex.org/d"]]'); }); it('should create an id without graph from a Quad with Quad as subject', () => { @@ -373,7 +428,7 @@ describe('Term', () => { new NamedNode('http://ex.org/b'), new Literal('"abc"@en-us'), new NamedNode('http://ex.org/d') - )).should.equal('<<<<_:n3-000 ?var-b "abc"@en-us http://ex.org/d>> http://ex.org/b "abc"@en-us http://ex.org/d>>'); + )).should.equal('[["_:n3-000","?var-b","\\"abc\\"@en-us","http://ex.org/d"],"http://ex.org/b","\\"abc\\"@en-us","http://ex.org/d"]'); }); it('should create an id without graph from a Quad with Quad as object', () => { @@ -387,7 +442,7 @@ describe('Term', () => { new NamedNode('http://ex.org/d') ), new NamedNode('http://ex.org/d') - )).should.equal('<<"abc"@en-us http://ex.org/b <<_:n3-000 ?var-b "abc"@en-us http://ex.org/d>> http://ex.org/d>>'); + )).should.equal('["\\"abc\\"@en-us","http://ex.org/b",["_:n3-000","?var-b","\\"abc\\"@en-us","http://ex.org/d"],"http://ex.org/d"]'); }); it('should create an id from a Quad with Quad as subject and object', () => { @@ -406,7 +461,7 @@ describe('Term', () => { new NamedNode('http://ex.org/d') ), new NamedNode('http://ex.org/d') - )).should.equal('<<<<_:n3-000 ?var-b "abc"@en-us http://ex.org/d>> http://ex.org/b <<_:n3-000 ?var-b "abc"@en-us http://ex.org/d>> http://ex.org/d>>'); + )).should.equal('[["_:n3-000","?var-b","\\"abc\\"@en-us","http://ex.org/d"],"http://ex.org/b",["_:n3-000","?var-b","\\"abc\\"@en-us","http://ex.org/d"],"http://ex.org/d"]'); }); it('should escape literals in nested Quads', () => { @@ -425,11 +480,46 @@ describe('Term', () => { new NamedNode('http://ex.org/d') ), new DefaultGraph() - )).should.equal('<<<<_:n3-000 ?var-b "Hello ""W""orl""d!"@en-us http://ex.org/d>> http://ex.org/b <<_:n3-000 ?var-b "Hello ""W""orl""d!"@en-us http://ex.org/d>>>>'); + )).should.equal('[["_:n3-000","?var-b","\\"Hello \\"W\\"orl\\"d!\\"@en-us","http://ex.org/d"],"http://ex.org/b",["_:n3-000","?var-b","\\"Hello \\"W\\"orl\\"d!\\"@en-us","http://ex.org/d"]]'); + }); + + + it('should termToId <-> termFromId should roundtrip on deeply nested quad', () => { + const q = new Quad( + new Quad( + new NamedNode('http://example.org/s1'), + new NamedNode('http://example.org/p1'), + new NamedNode('http://example.org/o1') + ), + new NamedNode('http://example.org/p1'), + new Quad( + new Quad( + new Literal('"s1"'), + new NamedNode('http://example.org/p1'), + new BlankNode('o1') + ), + new NamedNode('p2'), + new Quad( + new Quad( + new Literal('"s1"'), + new NamedNode('http://example.org/p1'), + new BlankNode('o1') + ), + new NamedNode('http://example.org/p1'), + new NamedNode('http://example.org/o1') + ) + ) + ); + + expect(q).deep.equals(termFromId(termToId(q))); + expect(termFromId(termToId(q))).deep.equals(q); + expect(q.equals(termFromId(termToId(q)))).equal(true); + expect(termFromId(termToId(q)).equals(q)).equal(true); + expect(termFromId(termToId(q)).equals(termFromId(termToId(q)))).equal(true); }); it('should correctly handle deeply nested quads', () => { - termToId(new Quad( + const q = new Quad( new Quad( new Quad( new Quad( @@ -474,7 +564,9 @@ describe('Term', () => { new NamedNode('http://ex.org/d') ), new NamedNode('http://ex.org/d') - )).should.equal('<<<<<<<<_:n3-000 ?var-b "abc"@en-us http://ex.org/d>> ?var-b <<_:n3-000 ?var-b "abc"@en-us http://ex.org/d>> http://ex.org/d>> ?var-b <<_:n3-000 ?var-b "abc"@en-us http://ex.org/d>> http://ex.org/d>> http://ex.org/b <<<<_:n3-000 ?var-b "abc"@en-us http://ex.org/d>> ?var-b <<_:n3-000 ?var-b "abc"@en-us http://ex.org/d>> http://ex.org/d>> http://ex.org/d>>'); + ); + + expect(q.equals(termFromId(termToId(q)))).equal(true); }); it('should throw on an unknown type', () => {