n3 1.9.0 → 1.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,11 +3,11 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ exports.default = exports.Variable = exports.Triple = exports.Term = exports.Quad = exports.NamedNode = exports.Literal = exports.DefaultGraph = exports.BlankNode = void 0;
7
+ exports.escapeQuotes = escapeQuotes;
6
8
  exports.termFromId = termFromId;
7
9
  exports.termToId = termToId;
8
- exports.escapeQuotes = escapeQuotes;
9
10
  exports.unescapeQuotes = unescapeQuotes;
10
- exports.Triple = exports.Quad = exports.DefaultGraph = exports.Variable = exports.BlankNode = exports.Literal = exports.NamedNode = exports.Term = exports.default = void 0;
11
11
 
12
12
  var _IRIs = _interopRequireDefault(require("./IRIs"));
13
13
 
@@ -353,11 +353,11 @@ function literal(value, languageOrDataType) {
353
353
  // Convert a boolean
354
354
  if (typeof value === 'boolean') datatype = xsd.boolean; // Convert an integer or double
355
355
  else if (typeof value === 'number') {
356
- if (Number.isFinite(value)) datatype = Number.isInteger(value) ? xsd.integer : xsd.double;else {
357
- datatype = xsd.double;
358
- if (!Number.isNaN(value)) value = value > 0 ? 'INF' : '-INF';
359
- }
356
+ if (Number.isFinite(value)) datatype = Number.isInteger(value) ? xsd.integer : xsd.double;else {
357
+ datatype = xsd.double;
358
+ if (!Number.isNaN(value)) value = value > 0 ? 'INF' : '-INF';
360
359
  }
360
+ }
361
361
  } // Create a datatyped literal
362
362
 
363
363
 
package/lib/N3Lexer.js CHANGED
@@ -95,8 +95,8 @@ class N3Lexer {
95
95
  }
96
96
  } // When not in line mode, enable N3 functionality by default
97
97
  else {
98
- this._n3Mode = options.n3 !== false;
99
- } // Don't output comment tokens by default
98
+ this._n3Mode = options.n3 !== false;
99
+ } // Don't output comment tokens by default
100
100
 
101
101
 
102
102
  this._comments = !!options.comments; // Cache the last tested closing position of long literals
@@ -167,35 +167,35 @@ class N3Lexer {
167
167
  // We need at least 3 tokens lookahead to distinguish ^^<IRI> and ^^pre:fixed
168
168
  if (input.length < 3) break; // Try to match a type
169
169
  else if (input[1] === '^') {
170
- this._previousMarker = '^^'; // Move to type IRI or prefixed name
170
+ this._previousMarker = '^^'; // Move to type IRI or prefixed name
171
171
 
172
- input = input.substr(2);
172
+ input = input.substr(2);
173
173
 
174
- if (input[0] !== '<') {
175
- inconclusive = true;
176
- break;
177
- }
178
- } // If no type, it must be a path expression
179
- else {
180
- if (this._n3Mode) {
181
- matchLength = 1;
182
- type = '^';
183
- }
174
+ if (input[0] !== '<') {
175
+ inconclusive = true;
176
+ break;
177
+ }
178
+ } // If no type, it must be a path expression
179
+ else {
180
+ if (this._n3Mode) {
181
+ matchLength = 1;
182
+ type = '^';
183
+ }
184
184
 
185
- break;
186
- }
185
+ break;
186
+ }
187
187
  // Fall through in case the type is an IRI
188
188
 
189
189
  case '<':
190
190
  // Try to find a full IRI without escape sequences
191
191
  if (match = this._unescapedIri.exec(input)) type = 'IRI', value = match[1]; // Try to find a full IRI with escape sequences
192
192
  else if (match = this._iri.exec(input)) {
193
- value = this._unescape(match[1]);
194
- if (value === null || illegalIriChars.test(value)) return reportSyntaxError(this);
195
- type = 'IRI';
196
- } // Try to find a nested triple
197
- else if (input.length > 1 && input[1] === '<') type = '<<', matchLength = 2; // Try to find a backwards implication arrow
198
- else if (this._n3Mode && input.length > 1 && input[1] === '=') type = 'inverse', matchLength = 2, value = '>';
193
+ value = this._unescape(match[1]);
194
+ if (value === null || illegalIriChars.test(value)) return reportSyntaxError(this);
195
+ type = 'IRI';
196
+ } // Try to find a nested triple
197
+ else if (input.length > 1 && input[1] === '<') type = '<<', matchLength = 2; // Try to find a backwards implication arrow
198
+ else if (this._n3Mode && input.length > 1 && input[1] === '=') type = 'inverse', matchLength = 2, value = '>';
199
199
  break;
200
200
 
201
201
  case '>':
@@ -213,12 +213,12 @@ class N3Lexer {
213
213
  // Try to find a literal without escape sequences
214
214
  if (match = this._simpleQuotedString.exec(input)) value = match[1]; // Try to find a literal wrapped in three pairs of quotes
215
215
  else {
216
- ({
217
- value,
218
- matchLength
219
- } = this._parseLiteral(input));
220
- if (value === null) return reportSyntaxError(this);
221
- }
216
+ ({
217
+ value,
218
+ matchLength
219
+ } = this._parseLiteral(input));
220
+ if (value === null) return reportSyntaxError(this);
221
+ }
222
222
 
223
223
  if (match !== null || matchLength !== 0) {
224
224
  type = 'literal';
@@ -232,12 +232,12 @@ class N3Lexer {
232
232
  // Try to find a literal without escape sequences
233
233
  if (match = this._simpleApostropheString.exec(input)) value = match[1]; // Try to find a literal wrapped in three pairs of quotes
234
234
  else {
235
- ({
236
- value,
237
- matchLength
238
- } = this._parseLiteral(input));
239
- if (value === null) return reportSyntaxError(this);
240
- }
235
+ ({
236
+ value,
237
+ matchLength
238
+ } = this._parseLiteral(input));
239
+ if (value === null) return reportSyntaxError(this);
240
+ }
241
241
 
242
242
  if (match !== null || matchLength !== 0) {
243
243
  type = 'literal';
@@ -470,6 +470,11 @@ class N3Lexer {
470
470
  previousToken: this.previousToken
471
471
  };
472
472
  return err;
473
+ } // ### Strips off any starting UTF BOM mark.
474
+
475
+
476
+ _readStartingBom(input) {
477
+ return input.startsWith('\ufeff') ? input.substr(1) : input;
473
478
  } // ## Public methods
474
479
  // ### `tokenize` starts the transformation of an N3 document into an array of tokens.
475
480
  // The input can be a string or a stream.
@@ -479,49 +484,49 @@ class N3Lexer {
479
484
  this._line = 1; // If the input is a string, continuously emit tokens through the callback until the end
480
485
 
481
486
  if (typeof input === 'string') {
482
- this._input = input; // If a callback was passed, asynchronously call it
487
+ this._input = this._readStartingBom(input); // If a callback was passed, asynchronously call it
483
488
 
484
489
  if (typeof callback === 'function') (0, _queueMicrotask.default)(() => this._tokenizeToEnd(callback, true)); // If no callback was passed, tokenize synchronously and return
485
490
  else {
486
- const tokens = [];
487
- let error;
491
+ const tokens = [];
492
+ let error;
488
493
 
489
- this._tokenizeToEnd((e, t) => e ? error = e : tokens.push(t), true);
494
+ this._tokenizeToEnd((e, t) => e ? error = e : tokens.push(t), true);
490
495
 
491
- if (error) throw error;
492
- return tokens;
493
- }
496
+ if (error) throw error;
497
+ return tokens;
498
+ }
494
499
  } // Otherwise, the input must be a stream
495
500
  else {
496
- this._input = '';
497
- this._pendingBuffer = null;
498
- if (typeof input.setEncoding === 'function') input.setEncoding('utf8'); // Adds the data chunk to the buffer and parses as far as possible
499
-
500
- input.on('data', data => {
501
- if (this._input !== null && data.length !== 0) {
502
- // Prepend any previous pending writes
503
- if (this._pendingBuffer) {
504
- data = Buffer.concat([this._pendingBuffer, data]);
505
- this._pendingBuffer = null;
506
- } // Hold if the buffer ends in an incomplete unicode sequence
507
-
508
-
509
- if (data[data.length - 1] & 0x80) {
510
- this._pendingBuffer = data;
511
- } // Otherwise, tokenize as far as possible
512
- else {
513
- this._input += data;
501
+ this._pendingBuffer = null;
502
+ if (typeof input.setEncoding === 'function') input.setEncoding('utf8'); // Adds the data chunk to the buffer and parses as far as possible
514
503
 
515
- this._tokenizeToEnd(callback, false);
516
- }
504
+ input.on('data', data => {
505
+ if (this._input !== null && data.length !== 0) {
506
+ // Prepend any previous pending writes
507
+ if (this._pendingBuffer) {
508
+ data = Buffer.concat([this._pendingBuffer, data]);
509
+ this._pendingBuffer = null;
510
+ } // Hold if the buffer ends in an incomplete unicode sequence
511
+
512
+
513
+ if (data[data.length - 1] & 0x80) {
514
+ this._pendingBuffer = data;
515
+ } // Otherwise, tokenize as far as possible
516
+ else {
517
+ // Only read a BOM at the start
518
+ if (typeof this._input === 'undefined') this._input = this._readStartingBom(typeof data === 'string' ? data : data.toString());else this._input += data;
519
+
520
+ this._tokenizeToEnd(callback, false);
517
521
  }
518
- }); // Parses until the end
522
+ }
523
+ }); // Parses until the end
519
524
 
520
- input.on('end', () => {
521
- if (this._input !== null) this._tokenizeToEnd(callback, true);
522
- });
523
- input.on('error', callback);
524
- }
525
+ input.on('end', () => {
526
+ if (typeof this._input === 'string') this._tokenizeToEnd(callback, true);
527
+ });
528
+ input.on('error', callback);
529
+ }
525
530
  }
526
531
 
527
532
  }
package/lib/N3Parser.js CHANGED
@@ -303,6 +303,14 @@ class N3Parser {
303
303
  // Additional semicolons can be safely ignored
304
304
  return this._predicate !== null ? this._readPredicate : this._error('Expected predicate but got ;', token);
305
305
 
306
+ case '[':
307
+ if (this._n3Mode) {
308
+ // Start a new quad with a new blank node as subject
309
+ this._saveContext('blank', this._graph, this._subject, this._subject = this._blankNode(), null);
310
+
311
+ return this._readBlankNodeHead;
312
+ }
313
+
306
314
  case 'blank':
307
315
  if (!this._n3Mode) return this._error('Disallowed blank node as predicate', token);
308
316
 
@@ -398,12 +406,13 @@ class N3Parser {
398
406
 
399
407
  const empty = this._predicate === null;
400
408
 
401
- this._restoreContext(); // If the blank node was the subject, continue reading the predicate
409
+ this._restoreContext(); // If the blank node was the object, restore previous context and read punctuation
402
410
 
403
411
 
404
- if (this._object === null) // If the blank node was empty, it could be a named graph label
405
- return empty ? this._readPredicateOrNamedGraph : this._readPredicateAfterBlank; // If the blank node was the object, restore previous context and read punctuation
406
- else return this._getContextEndReader();
412
+ if (this._object !== null) return this._getContextEndReader(); // If the blank node was the predicate, continue reading the object
413
+ else if (this._predicate !== null) return this._readObject; // If the blank node was the subject, continue reading the predicate
414
+ else // If the blank node was empty, it could be a named graph label
415
+ return empty ? this._readPredicateOrNamedGraph : this._readPredicateAfterBlank;
407
416
  } // ### `_readPredicateAfterBlank` reads a predicate after an anonymous blank node
408
417
 
409
418
 
@@ -464,10 +473,10 @@ class N3Parser {
464
473
  if (this._subject === this.RDF_NIL) return next;
465
474
  } // The list was in the parent context's object
466
475
  else {
467
- next = this._getContextEndReader(); // No list tail if this was an empty list
476
+ next = this._getContextEndReader(); // No list tail if this was an empty list
468
477
 
469
- if (this._object === this.RDF_NIL) return next;
470
- } // Close the list by making the head nil
478
+ if (this._object === this.RDF_NIL) return next;
479
+ } // Close the list by making the head nil
471
480
 
472
481
 
473
482
  list = this.RDF_NIL;
@@ -480,9 +489,9 @@ class N3Parser {
480
489
  next = this._readListItemDataTypeOrLang;
481
490
  } // Pre-datatyped string literal (prefix stores the datatype)
482
491
  else {
483
- item = this._literal(token.value, this._namedNode(token.prefix));
484
- next = this._getContextEndReader();
485
- }
492
+ item = this._literal(token.value, this._namedNode(token.prefix));
493
+ next = this._getContextEndReader();
494
+ }
486
495
 
487
496
  break;
488
497
 
@@ -586,9 +595,9 @@ class N3Parser {
586
595
 
587
596
  if (completed.token === null) return this._getContextEndReader(); // Otherwise, consume the token now
588
597
  else {
589
- this._readCallback = this._getContextEndReader();
590
- return this._readCallback(completed.token);
591
- }
598
+ this._readCallback = this._getContextEndReader();
599
+ return this._readCallback(completed.token);
600
+ }
592
601
  } // ### `_readFormulaTail` reads the end of a formula
593
602
 
594
603
 
@@ -768,12 +777,12 @@ class N3Parser {
768
777
 
769
778
  if (!this._explicitQuantifiers) this._quantified[entity.id] = this._quantifier(this._blankNode().value); // With explicit quantifiers, output the reified quantifier
770
779
  else {
771
- // If this is the first item, start a new quantifier list
772
- if (this._subject === null) this._emit(this._graph || this.DEFAULTGRAPH, this._predicate, this._subject = this._blankNode(), this.QUANTIFIERS_GRAPH); // Otherwise, continue the previous list
773
- else this._emit(this._subject, this.RDF_REST, this._subject = this._blankNode(), this.QUANTIFIERS_GRAPH); // Output the list item
780
+ // If this is the first item, start a new quantifier list
781
+ if (this._subject === null) this._emit(this._graph || this.DEFAULTGRAPH, this._predicate, this._subject = this._blankNode(), this.QUANTIFIERS_GRAPH); // Otherwise, continue the previous list
782
+ else this._emit(this._subject, this.RDF_REST, this._subject = this._blankNode(), this.QUANTIFIERS_GRAPH); // Output the list item
774
783
 
775
- this._emit(this._subject, this.RDF_FIRST, entity, this.QUANTIFIERS_GRAPH);
776
- }
784
+ this._emit(this._subject, this.RDF_FIRST, entity, this.QUANTIFIERS_GRAPH);
785
+ }
777
786
  return this._readQuantifierPunctuation;
778
787
  } // Reads punctuation from a @forSome or @forAll statement
779
788
 
@@ -782,17 +791,17 @@ class N3Parser {
782
791
  // Read more quantifiers
783
792
  if (token.type === ',') return this._readQuantifierList; // End of the quantifier list
784
793
  else {
785
- // With explicit quantifiers, close the quantifier list
786
- if (this._explicitQuantifiers) {
787
- this._emit(this._subject, this.RDF_REST, this.RDF_NIL, this.QUANTIFIERS_GRAPH);
794
+ // With explicit quantifiers, close the quantifier list
795
+ if (this._explicitQuantifiers) {
796
+ this._emit(this._subject, this.RDF_REST, this.RDF_NIL, this.QUANTIFIERS_GRAPH);
788
797
 
789
- this._subject = null;
790
- } // Read a dot
798
+ this._subject = null;
799
+ } // Read a dot
791
800
 
792
801
 
793
- this._readCallback = this._getContextEndReader();
794
- return this._readCallback(token);
795
- }
802
+ this._readCallback = this._getContextEndReader();
803
+ return this._readCallback(token);
804
+ }
796
805
  } // ### `_getPathReader` reads a potential path and then resumes with the given function
797
806
 
798
807
 
@@ -889,9 +898,9 @@ class N3Parser {
889
898
  return this._readPredicate;
890
899
  } // If the triple was the object, read context end.
891
900
  else {
892
- this._object = quad;
893
- return this._getContextEndReader();
894
- }
901
+ this._object = quad;
902
+ return this._getContextEndReader();
903
+ }
895
904
  } // ### `_getContextEndReader` gets the next reader function at the end of a context
896
905
 
897
906
 
package/lib/N3Store.js CHANGED
@@ -13,9 +13,9 @@ var _IRIs = _interopRequireDefault(require("./IRIs"));
13
13
 
14
14
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
15
 
16
- function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
16
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
17
17
 
18
- function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
18
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
19
19
 
20
20
  // **N3Store** objects store N3 quads by graph in memory.
21
21
  // ## Constructor
@@ -224,7 +224,15 @@ class N3Store {
224
224
  }
225
225
  };
226
226
  } // ## Public methods
227
- // ### `addQuad` adds a new quad to the store.
227
+ // ### `add` adds the specified quad to the dataset.
228
+ // Returns the dataset instance it was called on.
229
+ // Existing quads, as defined in Quad.equals, will be ignored.
230
+
231
+
232
+ add(quad) {
233
+ this.addQuad(quad);
234
+ return this;
235
+ } // ### `addQuad` adds a new quad to the store.
228
236
  // Returns if the quad index has changed, if the quad did not already exist.
229
237
 
230
238
 
@@ -273,6 +281,20 @@ class N3Store {
273
281
 
274
282
  addQuads(quads) {
275
283
  for (let i = 0; i < quads.length; i++) this.addQuad(quads[i]);
284
+ } // ### `delete` removes the specified quad from the dataset.
285
+ // Returns the dataset instance it was called on.
286
+
287
+
288
+ delete(quad) {
289
+ this.removeQuad(quad);
290
+ return this;
291
+ } // ### `has` determines whether a dataset includes a certain quad.
292
+ // Returns true or false as appropriate.
293
+
294
+
295
+ has(quad) {
296
+ const quads = this.getQuads(quad.subject, quad.predicate, quad.object, quad.graph);
297
+ return quads.length !== 0;
276
298
  } // ### `import` adds a stream of quads to the store
277
299
 
278
300
 
@@ -329,7 +351,17 @@ class N3Store {
329
351
 
330
352
 
331
353
  removeMatches(subject, predicate, object, graph) {
332
- return this.remove(this.match(subject, predicate, object, graph));
354
+ const stream = new _readableStream.Readable({
355
+ objectMode: true
356
+ });
357
+
358
+ stream._read = () => {
359
+ for (const quad of this.getQuads(subject, predicate, object, graph)) stream.push(quad);
360
+
361
+ stream.push(null);
362
+ };
363
+
364
+ return this.remove(stream);
333
365
  } // ### `deleteGraph` removes all triples with the given graph from the store
334
366
 
335
367
 
@@ -370,22 +402,16 @@ class N3Store {
370
402
  }
371
403
 
372
404
  return quads;
373
- } // ### `match` returns a stream of quads matching a pattern.
405
+ } // ### `match` returns a new dataset that is comprised of all quads in the current instance matching the given arguments.
406
+ // The logic described in Quad Matching is applied for each quad in this dataset to check if it should be included in the output dataset.
407
+ // Note: This method always returns a new DatasetCore, even if that dataset contains no quads.
408
+ // Note: Since a DatasetCore is an unordered set, the order of the quads within the returned sequence is arbitrary.
374
409
  // Setting any field to `undefined` or `null` indicates a wildcard.
410
+ // For backwards compatibility, the object return also implements the Readable stream interface.
375
411
 
376
412
 
377
413
  match(subject, predicate, object, graph) {
378
- const stream = new _readableStream.Readable({
379
- objectMode: true
380
- }); // Initialize stream once it is being read
381
-
382
- stream._read = () => {
383
- for (const quad of this.getQuads(subject, predicate, object, graph)) stream.push(quad);
384
-
385
- stream.push(null);
386
- };
387
-
388
- return stream;
414
+ return new DatasetCoreAndReadableStream(this, subject, predicate, object, graph);
389
415
  } // ### `countQuads` returns the number of quads matching a pattern.
390
416
  // Setting any field to `undefined` or `null` indicates a wildcard.
391
417
 
@@ -651,10 +677,10 @@ class N3Store {
651
677
  while (this._ids[name]) name = suggestedName + index++;
652
678
  } // Generate a generic blank node name
653
679
  else {
654
- do {
655
- name = `_:b${this._blankNodeIndex++}`;
656
- } while (this._ids[name]);
657
- } // Add the blank node to the entities, avoiding the generation of duplicates
680
+ do {
681
+ name = `_:b${this._blankNodeIndex++}`;
682
+ } while (this._ids[name]);
683
+ } // Add the blank node to the entities, avoiding the generation of duplicates
658
684
 
659
685
 
660
686
  this._ids[name] = ++this._id;
@@ -702,16 +728,16 @@ class N3Store {
702
728
  quad = subjectQuads[i];
703
729
  if (!quad.graph.equals(graph)) malformed = onError(current, 'not confined to single graph');else if (head) malformed = onError(current, 'has non-list arcs out'); // one rdf:first
704
730
  else if (quad.predicate.value === _IRIs.default.rdf.first) {
705
- if (first) malformed = onError(current, 'has multiple rdf:first arcs');else toRemove.push(first = quad);
706
- } // one rdf:rest
707
- else if (quad.predicate.value === _IRIs.default.rdf.rest) {
708
- if (rest) malformed = onError(current, 'has multiple rdf:rest arcs');else toRemove.push(rest = quad);
709
- } // alien triple
710
- else if (objectQuads.length) malformed = onError(current, 'can\'t be subject and object');else {
711
- head = quad; // e.g. { (1 2 3) :p :o }
712
-
713
- headPos = 'subject';
714
- }
731
+ if (first) malformed = onError(current, 'has multiple rdf:first arcs');else toRemove.push(first = quad);
732
+ } // one rdf:rest
733
+ else if (quad.predicate.value === _IRIs.default.rdf.rest) {
734
+ if (rest) malformed = onError(current, 'has multiple rdf:rest arcs');else toRemove.push(rest = quad);
735
+ } // alien triple
736
+ else if (objectQuads.length) malformed = onError(current, 'can\'t be subject and object');else {
737
+ head = quad; // e.g. { (1 2 3) :p :o }
738
+
739
+ headPos = 'subject';
740
+ }
715
741
  } // { :s :p (1 2) } arrives here with no head
716
742
  // { (1 2) :p :o } arrives here with head set to the list.
717
743
 
@@ -720,12 +746,12 @@ class N3Store {
720
746
  quad = objectQuads[i];
721
747
  if (head) malformed = onError(current, 'can\'t have coreferences'); // one rdf:rest
722
748
  else if (quad.predicate.value === _IRIs.default.rdf.rest) {
723
- if (parent) malformed = onError(current, 'has incoming rdf:rest arcs');else parent = quad;
724
- } else {
725
- head = quad; // e.g. { :s :p (1 2) }
749
+ if (parent) malformed = onError(current, 'has incoming rdf:rest arcs');else parent = quad;
750
+ } else {
751
+ head = quad; // e.g. { :s :p (1 2) }
726
752
 
727
- headPos = 'object';
728
- }
753
+ headPos = 'object';
754
+ }
729
755
  } // Store the list item and continue with parent
730
756
 
731
757
 
@@ -740,6 +766,13 @@ class N3Store {
740
766
 
741
767
  if (remove) this.removeQuads(toRemove);
742
768
  return lists;
769
+ } // ### Store is an iterable.
770
+ // Can be used where iterables are expected: for...of loops, array spread operator,
771
+ // `yield*`, and destructuring assignment (order is not guaranteed).
772
+
773
+
774
+ *[Symbol.iterator]() {
775
+ yield* this.getQuads();
743
776
  }
744
777
 
745
778
  } // Determines whether the argument is a string
@@ -749,4 +782,72 @@ exports.default = N3Store;
749
782
 
750
783
  function isString(s) {
751
784
  return typeof s === 'string' || s instanceof String;
785
+ }
786
+ /**
787
+ * A class that implements both DatasetCore and Readable.
788
+ */
789
+
790
+
791
+ class DatasetCoreAndReadableStream extends _readableStream.Readable {
792
+ constructor(n3Store, subject, predicate, object, graph) {
793
+ super({
794
+ objectMode: true
795
+ });
796
+ Object.assign(this, {
797
+ n3Store,
798
+ subject,
799
+ predicate,
800
+ object,
801
+ graph
802
+ });
803
+ }
804
+
805
+ get filtered() {
806
+ if (!this._filtered) {
807
+ const {
808
+ n3Store,
809
+ graph,
810
+ object,
811
+ predicate,
812
+ subject
813
+ } = this;
814
+ const quads = n3Store.getQuads(subject, predicate, object, graph);
815
+ this._filtered = new N3Store(quads, {
816
+ factory: n3Store._factory
817
+ });
818
+ }
819
+
820
+ return this._filtered;
821
+ }
822
+
823
+ get size() {
824
+ return this.filtered.size;
825
+ }
826
+
827
+ _read() {
828
+ for (const quad of this.filtered.getQuads()) this.push(quad);
829
+
830
+ this.push(null);
831
+ }
832
+
833
+ add(quad) {
834
+ return this.filtered.add(quad);
835
+ }
836
+
837
+ delete(quad) {
838
+ return this.filtered.delete(quad);
839
+ }
840
+
841
+ has(quad) {
842
+ return this.filtered.has(quad);
843
+ }
844
+
845
+ match(subject, predicate, object, graph) {
846
+ return new DatasetCoreAndReadableStream(this.filtered, subject, predicate, object, graph);
847
+ }
848
+
849
+ *[Symbol.iterator]() {
850
+ yield* this.filtered.getQuads();
851
+ }
852
+
752
853
  }
package/lib/N3Util.js CHANGED
@@ -3,12 +3,12 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.isNamedNode = isNamedNode;
6
+ exports.inDefaultGraph = inDefaultGraph;
7
7
  exports.isBlankNode = isBlankNode;
8
+ exports.isDefaultGraph = isDefaultGraph;
8
9
  exports.isLiteral = isLiteral;
10
+ exports.isNamedNode = isNamedNode;
9
11
  exports.isVariable = isVariable;
10
- exports.isDefaultGraph = isDefaultGraph;
11
- exports.inDefaultGraph = inDefaultGraph;
12
12
  exports.prefix = prefix;
13
13
  exports.prefixes = prefixes;
14
14
 
package/lib/N3Writer.js CHANGED
@@ -11,9 +11,9 @@ var _N3DataFactory = _interopRequireWildcard(require("./N3DataFactory"));
11
11
 
12
12
  var _N3Util = require("./N3Util");
13
13
 
14
- function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
14
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
15
15
 
16
- function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
16
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
17
17
 
18
18
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
19
19
 
@@ -247,7 +247,7 @@ class N3Writer {
247
247
  // The quad was given as an object, so shift parameters
248
248
  if (object === undefined) this._writeQuad(subject.subject, subject.predicate, subject.object, subject.graph, predicate); // The optional `graph` parameter was not provided
249
249
  else if (typeof graph === 'function') this._writeQuad(subject, predicate, object, DEFAULTGRAPH, graph); // The `graph` parameter was provided
250
- else this._writeQuad(subject, predicate, object, graph || DEFAULTGRAPH, done);
250
+ else this._writeQuad(subject, predicate, object, graph || DEFAULTGRAPH, done);
251
251
  } // ### `addQuads` adds the quads to the output stream
252
252
 
253
253
 
@@ -312,10 +312,10 @@ class N3Writer {
312
312
 
313
313
  if (predicate === undefined) children = []; // Blank node passed as blank(Term("predicate"), Term("object"))
314
314
  else if (predicate.termType) children = [{
315
- predicate: predicate,
316
- object: object
317
- }]; // Blank node passed as blank({ predicate: predicate, object: object })
318
- else if (!('length' in predicate)) children = [predicate];
315
+ predicate: predicate,
316
+ object: object
317
+ }]; // Blank node passed as blank({ predicate: predicate, object: object })
318
+ else if (!('length' in predicate)) children = [predicate];
319
319
 
320
320
  switch (length = children.length) {
321
321
  // Generate an empty blank node
@@ -336,9 +336,9 @@ class N3Writer {
336
336
 
337
337
  if (child.predicate.equals(predicate)) contents += `, ${this._encodeObject(child.object)}`; // Otherwise, write the predicate and the object
338
338
  else {
339
- contents += `${(i ? ';\n ' : '\n ') + this._encodePredicate(child.predicate)} ${this._encodeObject(child.object)}`;
340
- predicate = child.predicate;
341
- }
339
+ contents += `${(i ? ';\n ' : '\n ') + this._encodePredicate(child.predicate)} ${this._encodeObject(child.object)}`;
340
+ predicate = child.predicate;
341
+ }
342
342
  }
343
343
 
344
344
  return new SerializedTerm(`${contents}\n]`);
@@ -398,9 +398,9 @@ function characterReplacer(character) {
398
398
  result = '\\u0000'.substr(0, 6 - result.length) + result;
399
399
  } // Replace a surrogate pair with its 8-bit unicode escape sequence
400
400
  else {
401
- result = ((character.charCodeAt(0) - 0xD800) * 0x400 + character.charCodeAt(1) + 0x2400).toString(16);
402
- result = '\\U00000000'.substr(0, 10 - result.length) + result;
403
- }
401
+ result = ((character.charCodeAt(0) - 0xD800) * 0x400 + character.charCodeAt(1) + 0x2400).toString(16);
402
+ result = '\\U00000000'.substr(0, 10 - result.length) + result;
403
+ }
404
404
  }
405
405
 
406
406
  return result;
package/lib/index.js CHANGED
@@ -3,94 +3,95 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- Object.defineProperty(exports, "Lexer", {
6
+ Object.defineProperty(exports, "BlankNode", {
7
7
  enumerable: true,
8
8
  get: function () {
9
- return _N3Lexer.default;
9
+ return _N3DataFactory.BlankNode;
10
10
  }
11
11
  });
12
- Object.defineProperty(exports, "Parser", {
12
+ Object.defineProperty(exports, "DataFactory", {
13
13
  enumerable: true,
14
14
  get: function () {
15
- return _N3Parser.default;
15
+ return _N3DataFactory.default;
16
16
  }
17
17
  });
18
- Object.defineProperty(exports, "Writer", {
18
+ Object.defineProperty(exports, "DefaultGraph", {
19
19
  enumerable: true,
20
20
  get: function () {
21
- return _N3Writer.default;
21
+ return _N3DataFactory.DefaultGraph;
22
22
  }
23
23
  });
24
- Object.defineProperty(exports, "Store", {
24
+ Object.defineProperty(exports, "Lexer", {
25
25
  enumerable: true,
26
26
  get: function () {
27
- return _N3Store.default;
27
+ return _N3Lexer.default;
28
28
  }
29
29
  });
30
- Object.defineProperty(exports, "StreamParser", {
30
+ Object.defineProperty(exports, "Literal", {
31
31
  enumerable: true,
32
32
  get: function () {
33
- return _N3StreamParser.default;
33
+ return _N3DataFactory.Literal;
34
34
  }
35
35
  });
36
- Object.defineProperty(exports, "StreamWriter", {
36
+ Object.defineProperty(exports, "NamedNode", {
37
37
  enumerable: true,
38
38
  get: function () {
39
- return _N3StreamWriter.default;
39
+ return _N3DataFactory.NamedNode;
40
40
  }
41
41
  });
42
- Object.defineProperty(exports, "DataFactory", {
42
+ Object.defineProperty(exports, "Parser", {
43
43
  enumerable: true,
44
44
  get: function () {
45
- return _N3DataFactory.default;
45
+ return _N3Parser.default;
46
46
  }
47
47
  });
48
- Object.defineProperty(exports, "Term", {
48
+ Object.defineProperty(exports, "Quad", {
49
49
  enumerable: true,
50
50
  get: function () {
51
- return _N3DataFactory.Term;
51
+ return _N3DataFactory.Quad;
52
52
  }
53
53
  });
54
- Object.defineProperty(exports, "NamedNode", {
54
+ Object.defineProperty(exports, "Store", {
55
55
  enumerable: true,
56
56
  get: function () {
57
- return _N3DataFactory.NamedNode;
57
+ return _N3Store.default;
58
58
  }
59
59
  });
60
- Object.defineProperty(exports, "Literal", {
60
+ Object.defineProperty(exports, "StreamParser", {
61
61
  enumerable: true,
62
62
  get: function () {
63
- return _N3DataFactory.Literal;
63
+ return _N3StreamParser.default;
64
64
  }
65
65
  });
66
- Object.defineProperty(exports, "BlankNode", {
66
+ Object.defineProperty(exports, "StreamWriter", {
67
67
  enumerable: true,
68
68
  get: function () {
69
- return _N3DataFactory.BlankNode;
69
+ return _N3StreamWriter.default;
70
70
  }
71
71
  });
72
- Object.defineProperty(exports, "Variable", {
72
+ Object.defineProperty(exports, "Term", {
73
73
  enumerable: true,
74
74
  get: function () {
75
- return _N3DataFactory.Variable;
75
+ return _N3DataFactory.Term;
76
76
  }
77
77
  });
78
- Object.defineProperty(exports, "DefaultGraph", {
78
+ Object.defineProperty(exports, "Triple", {
79
79
  enumerable: true,
80
80
  get: function () {
81
- return _N3DataFactory.DefaultGraph;
81
+ return _N3DataFactory.Triple;
82
82
  }
83
83
  });
84
- Object.defineProperty(exports, "Quad", {
84
+ exports.Util = void 0;
85
+ Object.defineProperty(exports, "Variable", {
85
86
  enumerable: true,
86
87
  get: function () {
87
- return _N3DataFactory.Quad;
88
+ return _N3DataFactory.Variable;
88
89
  }
89
90
  });
90
- Object.defineProperty(exports, "Triple", {
91
+ Object.defineProperty(exports, "Writer", {
91
92
  enumerable: true,
92
93
  get: function () {
93
- return _N3DataFactory.Triple;
94
+ return _N3Writer.default;
94
95
  }
95
96
  });
96
97
  Object.defineProperty(exports, "termFromId", {
@@ -105,7 +106,6 @@ Object.defineProperty(exports, "termToId", {
105
106
  return _N3DataFactory.termToId;
106
107
  }
107
108
  });
108
- exports.Util = void 0;
109
109
 
110
110
  var _N3Lexer = _interopRequireDefault(require("./N3Lexer"));
111
111
 
@@ -125,8 +125,8 @@ exports.Util = Util;
125
125
 
126
126
  var _N3DataFactory = _interopRequireWildcard(require("./N3DataFactory"));
127
127
 
128
- function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
128
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
129
129
 
130
- function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
130
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
131
131
 
132
132
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n3",
3
- "version": "1.9.0",
3
+ "version": "1.11.2",
4
4
  "description": "Lightning fast, asynchronous, streaming Turtle / N3 / RDF library.",
5
5
  "author": "Ruben Verborgh <ruben.verborgh@gmail.com>",
6
6
  "keywords": [
@@ -27,10 +27,10 @@
27
27
  "readable-stream": "^3.6.0"
28
28
  },
29
29
  "devDependencies": {
30
- "@babel/cli": "^7.5.5",
31
- "@babel/core": "^7.5.5",
32
- "@babel/preset-env": "^7.5.5",
33
- "@babel/register": "^7.5.5",
30
+ "@babel/cli": "^7.16.0",
31
+ "@babel/core": "^7.16.0",
32
+ "@babel/preset-env": "^7.16.0",
33
+ "@babel/register": "^7.16.0",
34
34
  "arrayify-stream": "^1.0.0",
35
35
  "chai": "^4.0.2",
36
36
  "chai-things": "^0.2.0",
package/src/N3Lexer.js CHANGED
@@ -429,6 +429,11 @@ export default class N3Lexer {
429
429
  return err;
430
430
  }
431
431
 
432
+ // ### Strips off any starting UTF BOM mark.
433
+ _readStartingBom(input) {
434
+ return input.startsWith('\ufeff') ? input.substr(1) : input;
435
+ }
436
+
432
437
  // ## Public methods
433
438
 
434
439
  // ### `tokenize` starts the transformation of an N3 document into an array of tokens.
@@ -438,7 +443,7 @@ export default class N3Lexer {
438
443
 
439
444
  // If the input is a string, continuously emit tokens through the callback until the end
440
445
  if (typeof input === 'string') {
441
- this._input = input;
446
+ this._input = this._readStartingBom(input);
442
447
  // If a callback was passed, asynchronously call it
443
448
  if (typeof callback === 'function')
444
449
  queueMicrotask(() => this._tokenizeToEnd(callback, true));
@@ -453,7 +458,6 @@ export default class N3Lexer {
453
458
  }
454
459
  // Otherwise, the input must be a stream
455
460
  else {
456
- this._input = '';
457
461
  this._pendingBuffer = null;
458
462
  if (typeof input.setEncoding === 'function')
459
463
  input.setEncoding('utf8');
@@ -471,14 +475,18 @@ export default class N3Lexer {
471
475
  }
472
476
  // Otherwise, tokenize as far as possible
473
477
  else {
474
- this._input += data;
478
+ // Only read a BOM at the start
479
+ if (typeof this._input === 'undefined')
480
+ this._input = this._readStartingBom(typeof data === 'string' ? data : data.toString());
481
+ else
482
+ this._input += data;
475
483
  this._tokenizeToEnd(callback, false);
476
484
  }
477
485
  }
478
486
  });
479
487
  // Parses until the end
480
488
  input.on('end', () => {
481
- if (this._input !== null)
489
+ if (typeof this._input === 'string')
482
490
  this._tokenizeToEnd(callback, true);
483
491
  });
484
492
  input.on('error', callback);
package/src/N3Parser.js CHANGED
@@ -272,6 +272,13 @@ export default class N3Parser {
272
272
  // Additional semicolons can be safely ignored
273
273
  return this._predicate !== null ? this._readPredicate :
274
274
  this._error('Expected predicate but got ;', token);
275
+ case '[':
276
+ if (this._n3Mode) {
277
+ // Start a new quad with a new blank node as subject
278
+ this._saveContext('blank', this._graph, this._subject,
279
+ this._subject = this._blankNode(), null);
280
+ return this._readBlankNodeHead;
281
+ }
275
282
  case 'blank':
276
283
  if (!this._n3Mode)
277
284
  return this._error('Disallowed blank node as predicate', token);
@@ -368,13 +375,16 @@ export default class N3Parser {
368
375
  // Restore the parent context containing this blank node
369
376
  const empty = this._predicate === null;
370
377
  this._restoreContext();
378
+ // If the blank node was the object, restore previous context and read punctuation
379
+ if (this._object !== null)
380
+ return this._getContextEndReader();
381
+ // If the blank node was the predicate, continue reading the object
382
+ else if (this._predicate !== null)
383
+ return this._readObject;
371
384
  // If the blank node was the subject, continue reading the predicate
372
- if (this._object === null)
385
+ else
373
386
  // If the blank node was empty, it could be a named graph label
374
387
  return empty ? this._readPredicateOrNamedGraph : this._readPredicateAfterBlank;
375
- // If the blank node was the object, restore previous context and read punctuation
376
- else
377
- return this._getContextEndReader();
378
388
  }
379
389
 
380
390
  // ### `_readPredicateAfterBlank` reads a predicate after an anonymous blank node
package/src/N3Store.js CHANGED
@@ -211,6 +211,14 @@ export default class N3Store {
211
211
 
212
212
  // ## Public methods
213
213
 
214
+ // ### `add` adds the specified quad to the dataset.
215
+ // Returns the dataset instance it was called on.
216
+ // Existing quads, as defined in Quad.equals, will be ignored.
217
+ add(quad) {
218
+ this.addQuad(quad);
219
+ return this;
220
+ }
221
+
214
222
  // ### `addQuad` adds a new quad to the store.
215
223
  // Returns if the quad index has changed, if the quad did not already exist.
216
224
  addQuad(subject, predicate, object, graph) {
@@ -259,6 +267,20 @@ export default class N3Store {
259
267
  this.addQuad(quads[i]);
260
268
  }
261
269
 
270
+ // ### `delete` removes the specified quad from the dataset.
271
+ // Returns the dataset instance it was called on.
272
+ delete(quad) {
273
+ this.removeQuad(quad);
274
+ return this;
275
+ }
276
+
277
+ // ### `has` determines whether a dataset includes a certain quad.
278
+ // Returns true or false as appropriate.
279
+ has(quad) {
280
+ const quads = this.getQuads(quad.subject, quad.predicate, quad.object, quad.graph);
281
+ return quads.length !== 0;
282
+ }
283
+
262
284
  // ### `import` adds a stream of quads to the store
263
285
  import(stream) {
264
286
  stream.on('data', quad => { this.addQuad(quad); });
@@ -316,7 +338,15 @@ export default class N3Store {
316
338
  // ### `removeMatches` removes all matching quads from the store
317
339
  // Setting any field to `undefined` or `null` indicates a wildcard.
318
340
  removeMatches(subject, predicate, object, graph) {
319
- return this.remove(this.match(subject, predicate, object, graph));
341
+ const stream = new Readable({ objectMode: true });
342
+
343
+ stream._read = () => {
344
+ for (const quad of this.getQuads(subject, predicate, object, graph))
345
+ stream.push(quad);
346
+ stream.push(null);
347
+ };
348
+
349
+ return this.remove(stream);
320
350
  }
321
351
 
322
352
  // ### `deleteGraph` removes all triples with the given graph from the store
@@ -373,19 +403,14 @@ export default class N3Store {
373
403
  return quads;
374
404
  }
375
405
 
376
- // ### `match` returns a stream of quads matching a pattern.
406
+ // ### `match` returns a new dataset that is comprised of all quads in the current instance matching the given arguments.
407
+ // The logic described in Quad Matching is applied for each quad in this dataset to check if it should be included in the output dataset.
408
+ // Note: This method always returns a new DatasetCore, even if that dataset contains no quads.
409
+ // Note: Since a DatasetCore is an unordered set, the order of the quads within the returned sequence is arbitrary.
377
410
  // Setting any field to `undefined` or `null` indicates a wildcard.
411
+ // For backwards compatibility, the object return also implements the Readable stream interface.
378
412
  match(subject, predicate, object, graph) {
379
- const stream = new Readable({ objectMode: true });
380
-
381
- // Initialize stream once it is being read
382
- stream._read = () => {
383
- for (const quad of this.getQuads(subject, predicate, object, graph))
384
- stream.push(quad);
385
- stream.push(null);
386
- };
387
-
388
- return stream;
413
+ return new DatasetCoreAndReadableStream(this, subject, predicate, object, graph);
389
414
  }
390
415
 
391
416
  // ### `countQuads` returns the number of quads matching a pattern.
@@ -790,9 +815,64 @@ export default class N3Store {
790
815
  this.removeQuads(toRemove);
791
816
  return lists;
792
817
  }
818
+
819
+ // ### Store is an iterable.
820
+ // Can be used where iterables are expected: for...of loops, array spread operator,
821
+ // `yield*`, and destructuring assignment (order is not guaranteed).
822
+ *[Symbol.iterator]() {
823
+ yield* this.getQuads();
824
+ }
793
825
  }
794
826
 
795
827
  // Determines whether the argument is a string
796
828
  function isString(s) {
797
829
  return typeof s === 'string' || s instanceof String;
798
830
  }
831
+
832
+ /**
833
+ * A class that implements both DatasetCore and Readable.
834
+ */
835
+ class DatasetCoreAndReadableStream extends Readable {
836
+ constructor(n3Store, subject, predicate, object, graph) {
837
+ super({ objectMode: true });
838
+ Object.assign(this, { n3Store, subject, predicate, object, graph });
839
+ }
840
+
841
+ get filtered() {
842
+ if (!this._filtered) {
843
+ const { n3Store, graph, object, predicate, subject } = this;
844
+ const quads = n3Store.getQuads(subject, predicate, object, graph);
845
+ this._filtered = new N3Store(quads, { factory: n3Store._factory });
846
+ }
847
+ return this._filtered;
848
+ }
849
+ get size() {
850
+ return this.filtered.size;
851
+ }
852
+
853
+ _read() {
854
+ for (const quad of this.filtered.getQuads())
855
+ this.push(quad);
856
+ this.push(null);
857
+ }
858
+
859
+ add(quad) {
860
+ return this.filtered.add(quad);
861
+ }
862
+
863
+ delete(quad) {
864
+ return this.filtered.delete(quad);
865
+ }
866
+
867
+ has(quad) {
868
+ return this.filtered.has(quad);
869
+ }
870
+
871
+ match(subject, predicate, object, graph) {
872
+ return new DatasetCoreAndReadableStream(this.filtered, subject, predicate, object, graph);
873
+ }
874
+
875
+ *[Symbol.iterator]() {
876
+ yield* this.filtered.getQuads();
877
+ }
878
+ }