n3 1.20.3 → 1.21.0

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.
package/lib/N3Lexer.js CHANGED
@@ -97,7 +97,7 @@ class N3Lexer {
97
97
  this._n3Mode = options.n3 !== false;
98
98
  }
99
99
  // Don't output comment tokens by default
100
- this._comments = !!options.comments;
100
+ this.comments = !!options.comments;
101
101
  // Cache the last tested closing position of long literals
102
102
  this._literalClosingPos = 0;
103
103
  }
@@ -114,7 +114,7 @@ class N3Lexer {
114
114
  let whiteSpaceMatch, comment;
115
115
  while (whiteSpaceMatch = this._newline.exec(input)) {
116
116
  // Try to find a comment
117
- if (this._comments && (comment = this._comment.exec(whiteSpaceMatch[0]))) emitToken('comment', comment[1], '', this._line, whiteSpaceMatch[0].length);
117
+ if (this.comments && (comment = this._comment.exec(whiteSpaceMatch[0]))) emitToken('comment', comment[1], '', this._line, whiteSpaceMatch[0].length);
118
118
  // Advance the input
119
119
  input = input.substr(whiteSpaceMatch[0].length, input.length);
120
120
  currentLineLength = input.length;
@@ -128,7 +128,7 @@ class N3Lexer {
128
128
  // If the input is finished, emit EOF
129
129
  if (inputFinished) {
130
130
  // Try to find a final comment
131
- if (this._comments && (comment = this._comment.exec(input))) emitToken('comment', comment[1], '', this._line, input.length);
131
+ if (this.comments && (comment = this._comment.exec(input))) emitToken('comment', comment[1], '', this._line, input.length);
132
132
  input = null;
133
133
  emitToken('eof', '', '', this._line, 0);
134
134
  }
package/lib/N3Parser.js CHANGED
@@ -943,20 +943,31 @@ class N3Parser {
943
943
 
944
944
  // ## Public methods
945
945
 
946
- // ### `parse` parses the N3 input and emits each parsed quad through the callback
946
+ // ### `parse` parses the N3 input and emits each parsed quad through the onQuad callback.
947
947
  parse(input, quadCallback, prefixCallback) {
948
+ // The second parameter accepts an object { onQuad: ..., onPrefix: ..., onComment: ...}
949
+ // As a second and third parameter it still accepts a separate quadCallback and prefixCallback for backward compatibility as well
950
+ let onQuad, onPrefix, onComment;
951
+ if (quadCallback && (quadCallback.onQuad || quadCallback.onPrefix || quadCallback.onComment)) {
952
+ onQuad = quadCallback.onQuad;
953
+ onPrefix = quadCallback.onPrefix;
954
+ onComment = quadCallback.onComment;
955
+ } else {
956
+ onQuad = quadCallback;
957
+ onPrefix = prefixCallback;
958
+ }
948
959
  // The read callback is the next function to be executed when a token arrives.
949
960
  // We start reading in the top context.
950
961
  this._readCallback = this._readInTopContext;
951
962
  this._sparqlStyle = false;
952
963
  this._prefixes = Object.create(null);
953
964
  this._prefixes._ = this._blankNodePrefix ? this._blankNodePrefix.substr(2) : `b${blankNodePrefix++}_`;
954
- this._prefixCallback = prefixCallback || noop;
965
+ this._prefixCallback = onPrefix || noop;
955
966
  this._inversePredicate = false;
956
967
  this._quantified = Object.create(null);
957
968
 
958
969
  // Parse synchronously if no quad callback is given
959
- if (!quadCallback) {
970
+ if (!onQuad) {
960
971
  const quads = [];
961
972
  let error;
962
973
  this._callback = (e, t) => {
@@ -968,12 +979,25 @@ class N3Parser {
968
979
  if (error) throw error;
969
980
  return quads;
970
981
  }
982
+ let processNextToken = (error, token) => {
983
+ if (error !== null) this._callback(error), this._callback = noop;else if (this._readCallback) this._readCallback = this._readCallback(token);
984
+ };
985
+
986
+ // Enable checking for comments on every token when a commentCallback has been set
987
+ if (onComment) {
988
+ // Enable the lexer to return comments as tokens first (disabled by default)
989
+ this._lexer.comments = true;
990
+ // Patch the processNextToken function
991
+ processNextToken = (error, token) => {
992
+ if (error !== null) this._callback(error), this._callback = noop;else if (this._readCallback) {
993
+ if (token.type === 'comment') onComment(token.value);else this._readCallback = this._readCallback(token);
994
+ }
995
+ };
996
+ }
971
997
 
972
998
  // Parse asynchronously otherwise, executing the read callback when a token arrives
973
- this._callback = quadCallback;
974
- this._lexer.tokenize(input, (error, token) => {
975
- if (error !== null) this._callback(error), this._callback = noop;else if (this._readCallback) this._readCallback = this._readCallback(token);
976
- });
999
+ this._callback = onQuad;
1000
+ this._lexer.tokenize(input, processNextToken);
977
1001
  }
978
1002
  }
979
1003
 
package/lib/N3Store.js CHANGED
@@ -15,6 +15,11 @@ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e;
15
15
  // **N3Store** objects store N3 quads by graph in memory.
16
16
 
17
17
  const ITERATOR = Symbol('iter');
18
+ function merge(target, source, depth = 4) {
19
+ if (depth === 0) return Object.assign(target, source);
20
+ for (const key in source) target[key] = merge(target[key] || Object.create(null), source[key], depth - 1);
21
+ return target;
22
+ }
18
23
 
19
24
  // ## Constructor
20
25
  class N3EntityIndex {
@@ -125,7 +130,7 @@ class N3Store {
125
130
  const index1 = index0[key0] || (index0[key0] = {});
126
131
  const index2 = index1[key1] || (index1[key1] = {});
127
132
  // Setting the key to _any_ value signals the presence of the quad
128
- const existed = (key2 in index2);
133
+ const existed = key2 in index2;
129
134
  if (!existed) index2[key2] = null;
130
135
  return !existed;
131
136
  }
@@ -345,7 +350,12 @@ class N3Store {
345
350
  // ### `removeQuad` removes a quad from the store if it exists
346
351
  removeQuad(subject, predicate, object, graph) {
347
352
  // Shift arguments if a quad object is given instead of components
348
- if (!predicate) graph = subject.graph, object = subject.object, predicate = subject.predicate, subject = subject.subject;
353
+ if (!predicate) ({
354
+ subject,
355
+ predicate,
356
+ object,
357
+ graph
358
+ } = subject);
349
359
  // Convert terms to internal string representation
350
360
  graph = graph ? this._termToNumericId(graph) : 1;
351
361
 
@@ -746,7 +756,12 @@ class N3Store {
746
756
  * Blank Nodes will be normalized.
747
757
  */
748
758
  addAll(quads) {
749
- if (Array.isArray(quads)) this.addQuads(quads);else {
759
+ if (Array.isArray(quads)) this.addQuads(quads);else if (quads instanceof N3Store && quads._entityIndex === this._entityIndex) {
760
+ if (quads._size !== 0) {
761
+ this._graphs = merge(this._graphs, quads._graphs);
762
+ this._size = null; // Invalidate the cached size
763
+ }
764
+ } else {
750
765
  for (const quad of quads) this.add(quad);
751
766
  }
752
767
  return this;
@@ -759,6 +774,7 @@ class N3Store {
759
774
  * Blank Nodes will be normalized.
760
775
  */
761
776
  contains(other) {
777
+ if (other === this) return true;
762
778
  if (!(other instanceof N3Store) || this._entityIndex !== other._entityIndex) return other.every(quad => this.has(quad));
763
779
  const g1 = this._graphs,
764
780
  g2 = other._graphs;
@@ -797,6 +813,9 @@ class N3Store {
797
813
  * Returns a new dataset that contains all quads from the current dataset that are not included in the given dataset.
798
814
  */
799
815
  difference(other) {
816
+ if (other === this) return new N3Store({
817
+ entityIndex: this._entityIndex
818
+ });
800
819
  return this.filter(quad => !other.has(quad));
801
820
  }
802
821
 
@@ -826,6 +845,13 @@ class N3Store {
826
845
  * Returns a new dataset containing all quads from the current dataset that are also included in the given dataset.
827
846
  */
828
847
  intersection(other) {
848
+ if (other === this) {
849
+ const store = new N3Store({
850
+ entityIndex: this._entityIndex
851
+ });
852
+ store._graphs = merge(Object.create(null), this._graphs);
853
+ store._size = this._size;
854
+ }
829
855
  return this.filter(quad => other.has(quad));
830
856
  }
831
857
 
@@ -898,7 +924,8 @@ class N3Store {
898
924
  const store = new N3Store({
899
925
  entityIndex: this._entityIndex
900
926
  });
901
- store.addAll(this);
927
+ store._graphs = merge(Object.create(null), this._graphs);
928
+ store._size = this._size;
902
929
  store.addAll(quads);
903
930
  return store;
904
931
  }
@@ -20,6 +20,19 @@ class N3StreamParser extends _readableStream.Transform {
20
20
  // Set up parser with dummy stream to obtain `data` and `end` callbacks
21
21
  const parser = new _N3Parser.default(options);
22
22
  let onData, onEnd;
23
+ const callbacks = {
24
+ // Handle quads by pushing them down the pipeline
25
+ onQuad: (error, quad) => {
26
+ error && this.emit('error', error) || quad && this.push(quad);
27
+ },
28
+ // Emit prefixes through the `prefix` event
29
+ onPrefix: (prefix, uri) => {
30
+ this.emit('prefix', prefix, uri);
31
+ }
32
+ };
33
+ if (options && options.comments) callbacks.onComment = comment => {
34
+ this.emit('comment', comment);
35
+ };
23
36
  parser.parse({
24
37
  on: (event, callback) => {
25
38
  switch (event) {
@@ -31,15 +44,7 @@ class N3StreamParser extends _readableStream.Transform {
31
44
  break;
32
45
  }
33
46
  }
34
- },
35
- // Handle quads by pushing them down the pipeline
36
- (error, quad) => {
37
- error && this.emit('error', error) || quad && this.push(quad);
38
- },
39
- // Emit prefixes through the `prefix` event
40
- (prefix, uri) => {
41
- this.emit('prefix', prefix, uri);
42
- });
47
+ }, callbacks);
43
48
 
44
49
  // Implement Transform methods through parser callbacks
45
50
  this._transform = (chunk, encoding, done) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n3",
3
- "version": "1.20.3",
3
+ "version": "1.21.0",
4
4
  "description": "Lightning fast, asynchronous, streaming Turtle / N3 / RDF library.",
5
5
  "author": "Ruben Verborgh <ruben.verborgh@gmail.com>",
6
6
  "keywords": [
@@ -36,10 +36,9 @@
36
36
  "@rdfjs/data-model": "^1",
37
37
  "arrayify-stream": "^1.0.0",
38
38
  "browserify": "^17.0.0",
39
- "colors": "^1.1.2",
40
39
  "deep-taxonomy-benchmark": "^1.2.0",
41
40
  "docco": "^0.9.1",
42
- "eslint": "^5.14.1",
41
+ "eslint": "^8.57.0",
43
42
  "eslint-plugin-import": "^2.29.1",
44
43
  "jest": "^29.7.0",
45
44
  "pre-commit": "^1.2.2",
@@ -229,7 +229,7 @@ export function termFromId(id, factory, nested) {
229
229
  termFromId(id[0], factory, true),
230
230
  termFromId(id[1], factory, true),
231
231
  termFromId(id[2], factory, true),
232
- id[3] && termFromId(id[3], factory, true)
232
+ id[3] && termFromId(id[3], factory, true),
233
233
  );
234
234
  }
235
235
 
package/src/N3Lexer.js CHANGED
@@ -68,7 +68,7 @@ export default class N3Lexer {
68
68
  this._n3Mode = options.n3 !== false;
69
69
  }
70
70
  // Don't output comment tokens by default
71
- this._comments = !!options.comments;
71
+ this.comments = !!options.comments;
72
72
  // Cache the last tested closing position of long literals
73
73
  this._literalClosingPos = 0;
74
74
  }
@@ -85,7 +85,7 @@ export default class N3Lexer {
85
85
  let whiteSpaceMatch, comment;
86
86
  while (whiteSpaceMatch = this._newline.exec(input)) {
87
87
  // Try to find a comment
88
- if (this._comments && (comment = this._comment.exec(whiteSpaceMatch[0])))
88
+ if (this.comments && (comment = this._comment.exec(whiteSpaceMatch[0])))
89
89
  emitToken('comment', comment[1], '', this._line, whiteSpaceMatch[0].length);
90
90
  // Advance the input
91
91
  input = input.substr(whiteSpaceMatch[0].length, input.length);
@@ -101,7 +101,7 @@ export default class N3Lexer {
101
101
  // If the input is finished, emit EOF
102
102
  if (inputFinished) {
103
103
  // Try to find a final comment
104
- if (this._comments && (comment = this._comment.exec(input)))
104
+ if (this.comments && (comment = this._comment.exec(input)))
105
105
  emitToken('comment', comment[1], '', this._line, input.length);
106
106
  input = null;
107
107
  emitToken('eof', '', '', this._line, 0);
package/src/N3Parser.js CHANGED
@@ -1010,8 +1010,20 @@ export default class N3Parser {
1010
1010
 
1011
1011
  // ## Public methods
1012
1012
 
1013
- // ### `parse` parses the N3 input and emits each parsed quad through the callback
1013
+ // ### `parse` parses the N3 input and emits each parsed quad through the onQuad callback.
1014
1014
  parse(input, quadCallback, prefixCallback) {
1015
+ // The second parameter accepts an object { onQuad: ..., onPrefix: ..., onComment: ...}
1016
+ // As a second and third parameter it still accepts a separate quadCallback and prefixCallback for backward compatibility as well
1017
+ let onQuad, onPrefix, onComment;
1018
+ if (quadCallback && (quadCallback.onQuad || quadCallback.onPrefix || quadCallback.onComment)) {
1019
+ onQuad = quadCallback.onQuad;
1020
+ onPrefix = quadCallback.onPrefix;
1021
+ onComment = quadCallback.onComment;
1022
+ }
1023
+ else {
1024
+ onQuad = quadCallback;
1025
+ onPrefix = prefixCallback;
1026
+ }
1015
1027
  // The read callback is the next function to be executed when a token arrives.
1016
1028
  // We start reading in the top context.
1017
1029
  this._readCallback = this._readInTopContext;
@@ -1019,12 +1031,12 @@ export default class N3Parser {
1019
1031
  this._prefixes = Object.create(null);
1020
1032
  this._prefixes._ = this._blankNodePrefix ? this._blankNodePrefix.substr(2)
1021
1033
  : `b${blankNodePrefix++}_`;
1022
- this._prefixCallback = prefixCallback || noop;
1034
+ this._prefixCallback = onPrefix || noop;
1023
1035
  this._inversePredicate = false;
1024
1036
  this._quantified = Object.create(null);
1025
1037
 
1026
1038
  // Parse synchronously if no quad callback is given
1027
- if (!quadCallback) {
1039
+ if (!onQuad) {
1028
1040
  const quads = [];
1029
1041
  let error;
1030
1042
  this._callback = (e, t) => { e ? (error = e) : t && quads.push(t); };
@@ -1035,14 +1047,33 @@ export default class N3Parser {
1035
1047
  return quads;
1036
1048
  }
1037
1049
 
1038
- // Parse asynchronously otherwise, executing the read callback when a token arrives
1039
- this._callback = quadCallback;
1040
- this._lexer.tokenize(input, (error, token) => {
1050
+ let processNextToken = (error, token) => {
1041
1051
  if (error !== null)
1042
1052
  this._callback(error), this._callback = noop;
1043
1053
  else if (this._readCallback)
1044
1054
  this._readCallback = this._readCallback(token);
1045
- });
1055
+ };
1056
+
1057
+ // Enable checking for comments on every token when a commentCallback has been set
1058
+ if (onComment) {
1059
+ // Enable the lexer to return comments as tokens first (disabled by default)
1060
+ this._lexer.comments = true;
1061
+ // Patch the processNextToken function
1062
+ processNextToken = (error, token) => {
1063
+ if (error !== null)
1064
+ this._callback(error), this._callback = noop;
1065
+ else if (this._readCallback) {
1066
+ if (token.type === 'comment')
1067
+ onComment(token.value);
1068
+ else
1069
+ this._readCallback = this._readCallback(token);
1070
+ }
1071
+ };
1072
+ }
1073
+
1074
+ // Parse asynchronously otherwise, executing the read callback when a token arrives
1075
+ this._callback = onQuad;
1076
+ this._lexer.tokenize(input, processNextToken);
1046
1077
  }
1047
1078
  }
1048
1079
 
package/src/N3Store.js CHANGED
@@ -7,6 +7,16 @@ import N3Writer from './N3Writer';
7
7
 
8
8
  const ITERATOR = Symbol('iter');
9
9
 
10
+ function merge(target, source, depth = 4) {
11
+ if (depth === 0)
12
+ return Object.assign(target, source);
13
+
14
+ for (const key in source)
15
+ target[key] = merge(target[key] || Object.create(null), source[key], depth - 1);
16
+
17
+ return target;
18
+ }
19
+
10
20
  // ## Constructor
11
21
  export class N3EntityIndex {
12
22
  constructor(options = {}) {
@@ -31,7 +41,7 @@ export class N3EntityIndex {
31
41
  this._termFromId(entities[terms[1]]),
32
42
  this._termFromId(entities[terms[2]]),
33
43
  this._termFromId(entities[terms[3]]),
34
- terms[4] && this._termFromId(entities[terms[4]])
44
+ terms[4] && this._termFromId(entities[terms[4]]),
35
45
  );
36
46
  return q;
37
47
  }
@@ -346,8 +356,7 @@ export default class N3Store {
346
356
  removeQuad(subject, predicate, object, graph) {
347
357
  // Shift arguments if a quad object is given instead of components
348
358
  if (!predicate)
349
- graph = subject.graph, object = subject.object,
350
- predicate = subject.predicate, subject = subject.subject;
359
+ ({ subject, predicate, object, graph } = subject);
351
360
  // Convert terms to internal string representation
352
361
  graph = graph ? this._termToNumericId(graph) : 1;
353
362
 
@@ -792,6 +801,12 @@ export default class N3Store {
792
801
  addAll(quads) {
793
802
  if (Array.isArray(quads))
794
803
  this.addQuads(quads);
804
+ else if (quads instanceof N3Store && quads._entityIndex === this._entityIndex) {
805
+ if (quads._size !== 0) {
806
+ this._graphs = merge(this._graphs, quads._graphs);
807
+ this._size = null; // Invalidate the cached size
808
+ }
809
+ }
795
810
  else {
796
811
  for (const quad of quads)
797
812
  this.add(quad);
@@ -799,7 +814,6 @@ export default class N3Store {
799
814
  return this;
800
815
  }
801
816
 
802
-
803
817
  /**
804
818
  * Returns `true` if the current dataset is a superset of the given dataset; in other words, returns `true` if
805
819
  * the given dataset is a subset of, i.e., is contained within, the current dataset.
@@ -807,6 +821,9 @@ export default class N3Store {
807
821
  * Blank Nodes will be normalized.
808
822
  */
809
823
  contains(other) {
824
+ if (other === this)
825
+ return true;
826
+
810
827
  if (!(other instanceof N3Store) || this._entityIndex !== other._entityIndex)
811
828
  return other.every(quad => this.has(quad));
812
829
 
@@ -848,6 +865,9 @@ export default class N3Store {
848
865
  * Returns a new dataset that contains all quads from the current dataset that are not included in the given dataset.
849
866
  */
850
867
  difference(other) {
868
+ if (other === this)
869
+ return new N3Store({ entityIndex: this._entityIndex });
870
+
851
871
  return this.filter(quad => !other.has(quad));
852
872
  }
853
873
 
@@ -877,6 +897,11 @@ export default class N3Store {
877
897
  * Returns a new dataset containing all quads from the current dataset that are also included in the given dataset.
878
898
  */
879
899
  intersection(other) {
900
+ if (other === this) {
901
+ const store = new N3Store({ entityIndex: this._entityIndex });
902
+ store._graphs = merge(Object.create(null), this._graphs);
903
+ store._size = this._size;
904
+ }
880
905
  return this.filter(quad => other.has(quad));
881
906
  }
882
907
 
@@ -947,7 +972,9 @@ export default class N3Store {
947
972
  */
948
973
  union(quads) {
949
974
  const store = new N3Store({ entityIndex: this._entityIndex });
950
- store.addAll(this);
975
+ store._graphs = merge(Object.create(null), this._graphs);
976
+ store._size = this._size;
977
+
951
978
  store.addAll(quads);
952
979
  return store;
953
980
  }
@@ -11,6 +11,17 @@ export default class N3StreamParser extends Transform {
11
11
  // Set up parser with dummy stream to obtain `data` and `end` callbacks
12
12
  const parser = new N3Parser(options);
13
13
  let onData, onEnd;
14
+
15
+ const callbacks = {
16
+ // Handle quads by pushing them down the pipeline
17
+ onQuad: (error, quad) => { error && this.emit('error', error) || quad && this.push(quad); },
18
+ // Emit prefixes through the `prefix` event
19
+ onPrefix: (prefix, uri) => { this.emit('prefix', prefix, uri); },
20
+ };
21
+
22
+ if (options && options.comments)
23
+ callbacks.onComment = comment => { this.emit('comment', comment); };
24
+
14
25
  parser.parse({
15
26
  on: (event, callback) => {
16
27
  switch (event) {
@@ -18,12 +29,7 @@ export default class N3StreamParser extends Transform {
18
29
  case 'end': onEnd = callback; break;
19
30
  }
20
31
  },
21
- },
22
- // Handle quads by pushing them down the pipeline
23
- (error, quad) => { error && this.emit('error', error) || quad && this.push(quad); },
24
- // Emit prefixes through the `prefix` event
25
- (prefix, uri) => { this.emit('prefix', prefix, uri); }
26
- );
32
+ }, callbacks);
27
33
 
28
34
  // Implement Transform methods through parser callbacks
29
35
  this._transform = (chunk, encoding, done) => { onData(chunk); done(); };