n3 2.10.2 → 2.10.4

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/N3Parser.js CHANGED
@@ -368,10 +368,14 @@ class N3Parser {
368
368
  case 'inversePredicate':
369
369
  this._inversePredicate = true;
370
370
  return this._readPredicateAfterVerb;
371
+ case '|}':
372
+ // Expected predicate didn't come, must have been trailing semicolon
373
+ // or an empty annotation block
374
+ this._subject = null;
375
+ return this._readAnnotationBlockPunctuation(token);
371
376
  case '.':
372
377
  case ']':
373
378
  case '}':
374
- case '|}':
375
379
  // Expected predicate didn't come, must have been trailing semicolon.
376
380
  // In N3 mode, a subject (such as a path) can be a statement by itself.
377
381
  if (this._predicate === null && !this._n3Mode) return this._error(`Unexpected ${type}`, token);
@@ -876,8 +880,7 @@ class N3Parser {
876
880
  // ### `_readPunctuation` reads punctuation between quads or quad parts
877
881
  _readPunctuation(token) {
878
882
  let next,
879
- graph = this._graph,
880
- startingAnnotation = false;
883
+ graph = this._graph;
881
884
  const subject = this._subject,
882
885
  inversePredicate = this._inversePredicate;
883
886
  switch (token.type) {
@@ -902,34 +905,13 @@ class N3Parser {
902
905
  case ',':
903
906
  next = this._readObject;
904
907
  break;
905
- // ~ is allowed in the annotation syntax
908
+ // A reifier or annotation block annotates the triple just read
906
909
  case '~':
907
- // Only invalidate the cache for a genuinely new triple - chained annotation blocks on the
908
- // same triple (subject already null from a preceding annotation) must keep reusing it.
909
- if (subject !== null) this._tripleTerm = null;
910
- next = this._readReifierInAnnotation;
911
- startingAnnotation = true;
912
- break;
913
- // {| means that the current triple is annotated with predicate-object pairs.
914
910
  case '{|':
915
- // Continue using the last triple as reified triple subject for the predicate-object pairs.
916
- // Same staleness rule as ~ above.
917
- if (subject !== null) this._tripleTerm = null;
918
- this._subject = this._readTripleTerm();
919
- this._inversePredicate = false;
920
- this._validAnnotation = false;
921
- startingAnnotation = true;
922
- next = this._readPredicate;
923
- break;
924
- // |} means that the current reified triple in annotation syntax is finalized.
911
+ return this._readAnnotationStart(token);
912
+ // An annotation block can only be closed from within one
925
913
  case '|}':
926
- if (!this._annotation) return this._error('Unexpected annotation syntax closing', token);
927
- if (!this._validAnnotation) return this._error('Annotation block can not be empty', token);
928
- this._subject = null;
929
- this._annotation = false;
930
- this._inversePredicate = false;
931
- next = this._getContextEndReader();
932
- break;
914
+ return this._error('Unexpected annotation syntax closing', token);
933
915
  default:
934
916
  // An entity means this is a quad (only allowed if not already inside a graph)
935
917
  if (this._supportsQuads && this._graph === null && (graph = this._readEntity(token)) !== undefined) {
@@ -939,14 +921,11 @@ class N3Parser {
939
921
  return this._error(`Expected punctuation to follow "${this._object.id}"`, token);
940
922
  }
941
923
  // A quad has been completed now, so return it
942
- if (subject !== null && (!startingAnnotation || startingAnnotation && !this._annotation)) {
924
+ if (subject !== null) {
943
925
  const predicate = this._predicate,
944
926
  object = this._object;
945
927
  this._emit(subject, predicate, object, graph, inversePredicate);
946
928
  }
947
- if (startingAnnotation) {
948
- this._annotation = true;
949
- }
950
929
  return next;
951
930
  }
952
931
 
@@ -965,19 +944,15 @@ class N3Parser {
965
944
  next = this._readObject;
966
945
  break;
967
946
  // Annotation syntax applies to the quad just read, exactly as it does
968
- // outside of a blank node property list. `|}` arrives here too, because
969
- // the objects inside the annotation block are themselves read within the
970
- // enclosing blank node context.
947
+ // outside of a blank node property list
971
948
  case '~':
972
949
  case '{|':
950
+ return this._readAnnotationStart(token);
973
951
  case '|}':
974
- return this._readPunctuation(token);
952
+ return this._error('Unexpected annotation syntax closing', token);
975
953
  default:
976
954
  return this._error(`Expected punctuation to follow "${this._object.id}"`, token);
977
955
  }
978
- // An annotation block consumes the subject it annotates, so there is
979
- // nothing left to share with a following predicate-object pair
980
- if (this._subject === null) return this._error('Expected ] to follow annotation', token);
981
956
  // A quad has been completed now, so return it
982
957
  this._emitCurrent(this._subject, this._predicate, this._object, this._graph);
983
958
  if (resetInversePredicate) this._inversePredicate = false;
@@ -1247,32 +1222,27 @@ class N3Parser {
1247
1222
  return this._readReifiedTripleTail;
1248
1223
  }
1249
1224
 
1250
- // ### `_readReifier` reads the optional triple term identifier after a tilde when in annotation syntax.
1251
- _readReifierInAnnotation(token) {
1252
- // If next token is a reifier, read it as such.
1253
- if (token.type === 'IRI' || token.type === 'typeIRI' || token.type === 'type' || token.type === 'prefixed' || token.type === 'blank' || token.type === 'var') {
1254
- this._reifier = this._readEntity(token);
1255
- return this._readAnnotationBlockOrPunctuation;
1256
- }
1257
- // Otherwise, emit and assert triple term.
1258
- this._readTripleTerm();
1259
- this._subject = null;
1260
- return this._getContextEndReader().call(this, token);
1225
+ // ### `_readAnnotationStart` reads the first reifier or annotation block after an object,
1226
+ // which completes the annotated quad
1227
+ _readAnnotationStart(token) {
1228
+ this._emitCurrent(this._subject, this._predicate, this._object, this._graph);
1229
+ // A new triple is annotated, so its triple term cannot be reused
1230
+ this._tripleTerm = null;
1231
+ return this._readAnnotation(token);
1261
1232
  }
1262
1233
 
1263
- // ### `_readAnnotationBlockOrPunctuation` reads what follows an explicit reifier:
1264
- // either an annotation block, which reuses the reifier as its subject,
1265
- // or punctuation, in which case the reifier stands alone and its triple
1266
- // term still needs to be asserted here.
1267
- _readAnnotationBlockOrPunctuation(token) {
1268
- if (token.type === '{|') return this._readPunctuation(token);
1269
- this._readTripleTerm();
1270
- this._annotation = false;
1271
- // A shared subject or predicate goes on to reify a *different* triple,
1272
- // so the term just asserted must not be reused for the next one.
1234
+ // ### `_readAnnotation` reads what follows an annotated quad:
1235
+ // further reifiers or annotation blocks for that same quad, or punctuation
1236
+ _readAnnotation(token) {
1237
+ switch (token.type) {
1238
+ case '~':
1239
+ return this._readReifierInAnnotation;
1240
+ case '{|':
1241
+ return this._readAnnotationBlockHead(token);
1242
+ }
1243
+ // The annotated quad was already emitted when its annotation started,
1244
+ // so continue without emitting it a second time
1273
1245
  this._tripleTerm = null;
1274
- // The annotated triple was already emitted when the tilde was read,
1275
- // so continue without letting `_readPunctuation` emit it a second time.
1276
1246
  switch (token.type) {
1277
1247
  // The subject stays shared with the next predicate-object pair
1278
1248
  case ';':
@@ -1283,11 +1253,70 @@ class N3Parser {
1283
1253
  return this._readObject;
1284
1254
  default:
1285
1255
  this._subject = null;
1286
- // Resume in the enclosing context, which is top-level punctuation
1287
- // unless the reified triple sits inside a blank node property list
1256
+ // Resume in the enclosing context
1288
1257
  return this._getContextEndReader().call(this, token);
1289
1258
  }
1290
1259
  }
1260
+
1261
+ // ### `_readReifierInAnnotation` reads the optional reifier after a tilde in annotation syntax
1262
+ _readReifierInAnnotation(token) {
1263
+ switch (token.type) {
1264
+ case 'IRI':
1265
+ case 'typeIRI':
1266
+ case 'type':
1267
+ case 'prefixed':
1268
+ case 'blank':
1269
+ case 'var':
1270
+ this._reifier = this._readEntity(token);
1271
+ return this._readAnnotationBlockOrReifier;
1272
+ }
1273
+ // Without an identifier, the reifier is a fresh blank node
1274
+ this._reifier = this._factory.blankNode();
1275
+ return this._readAnnotationBlockOrReifier(token);
1276
+ }
1277
+
1278
+ // ### `_readAnnotationBlockOrReifier` reads what follows a reifier:
1279
+ // either an annotation block, which uses the reifier as its subject,
1280
+ // or anything else, in which case the reifier stands alone
1281
+ _readAnnotationBlockOrReifier(token) {
1282
+ if (token.type === '{|') return this._readAnnotationBlockHead(token);
1283
+ this._readTripleTerm();
1284
+ return this._readAnnotation(token);
1285
+ }
1286
+
1287
+ // ### `_readAnnotationBlockHead` opens an annotation block,
1288
+ // whose predicate-object pairs describe the reifier of the annotated quad
1289
+ _readAnnotationBlockHead(token) {
1290
+ const reifier = this._readTripleTerm();
1291
+ this._saveContext('annotation', this._graph, this._subject, this._predicate, this._object);
1292
+ // Restored when the block closes, so further annotations reuse the same triple term
1293
+ this._contextStack[this._contextStack.length - 1].tripleTerm = this._tripleTerm;
1294
+ this._subject = reifier;
1295
+ this._predicate = this._object = this._tripleTerm = null;
1296
+ this._inversePredicate = false;
1297
+ this._validAnnotation = false;
1298
+ return this._readPredicate;
1299
+ }
1300
+
1301
+ // ### `_readAnnotationBlockPunctuation` reads punctuation inside an annotation block
1302
+ _readAnnotationBlockPunctuation(token) {
1303
+ const stack = this._contextStack;
1304
+ if (token.type === '|}') {
1305
+ if (!stack.length || stack[stack.length - 1].type !== 'annotation') return this._error('Unexpected annotation syntax closing', token);
1306
+ if (!this._validAnnotation) return this._error('Annotation block can not be empty', token);
1307
+ // Emit the last quad of the block, unless a trailing semicolon already did
1308
+ if (this._subject !== null) this._emitCurrent(this._subject, this._predicate, this._object, this._graph);
1309
+ // Return to the annotated quad, which can be followed by more annotations
1310
+ const {
1311
+ tripleTerm
1312
+ } = stack[stack.length - 1];
1313
+ this._restoreContext('annotation', token);
1314
+ this._tripleTerm = tripleTerm;
1315
+ return this._readAnnotation;
1316
+ }
1317
+ // Otherwise, punctuation inside a block works like inside a blank node property list
1318
+ return this._readBlankNodePunctuation(token);
1319
+ }
1291
1320
  _readTripleTerm() {
1292
1321
  const stack = this._contextStack,
1293
1322
  parent = stack.length && stack[stack.length - 1];
@@ -1314,6 +1343,8 @@ class N3Parser {
1314
1343
  return this._readTripleTermTail;
1315
1344
  case '<<':
1316
1345
  return this._readReifiedTripleTailOrReifier;
1346
+ case 'annotation':
1347
+ return this._readAnnotationBlockPunctuation;
1317
1348
  }
1318
1349
  }
1319
1350
 
package/lib/N3Writer.js CHANGED
@@ -135,7 +135,7 @@ class N3Writer {
135
135
 
136
136
  // ### `quadToString` serializes a quad as a string
137
137
  quadToString(subject, predicate, object, graph) {
138
- return `${this._encodeSubject(subject)} ${this._encodeIriOrBlank(predicate)} ${this._encodeObject(object)}${graph && !(0, _N3Util.isDefaultGraph)(graph) ? ` ${this._encodeIriOrBlank(graph)} .\n` : ' .\n'}`;
138
+ return `${this._encodeSubject(subject)} ${predicate.termType === 'Literal' ? this._encodeLiteral(predicate) : this._encodeIriOrBlank(predicate)} ${this._encodeObject(object)}${graph && !(0, _N3Util.isDefaultGraph)(graph) ? ` ${this._encodeIriOrBlank(graph)} .\n` : ' .\n'}`;
139
139
  }
140
140
 
141
141
  // ### `quadsToString` serializes an array of quads as a string
@@ -147,7 +147,15 @@ class N3Writer {
147
147
 
148
148
  // ### `_encodeSubject` represents a subject
149
149
  _encodeSubject(entity) {
150
- return entity.termType === 'Quad' ? this._encodeQuad(entity) : this._encodeIriOrBlank(entity);
150
+ switch (entity.termType) {
151
+ case 'Quad':
152
+ return this._encodeQuad(entity);
153
+ // Literal subjects are only valid in N3
154
+ case 'Literal':
155
+ return this._encodeLiteral(entity);
156
+ default:
157
+ return this._encodeIriOrBlank(entity);
158
+ }
151
159
  }
152
160
 
153
161
  // ### `_encodeIriOrBlank` represents an IRI or blank node
@@ -214,7 +222,15 @@ class N3Writer {
214
222
 
215
223
  // ### `_encodePredicate` represents a predicate
216
224
  _encodePredicate(predicate) {
217
- return predicate.value === rdf.type ? 'a' : this._encodeIriOrBlank(predicate);
225
+ switch (predicate.termType) {
226
+ case 'NamedNode':
227
+ return predicate.value === rdf.type ? 'a' : this._encodeIriOrBlank(predicate);
228
+ // Literal predicates are only valid in N3
229
+ case 'Literal':
230
+ return this._encodeLiteral(predicate);
231
+ default:
232
+ return this._encodeIriOrBlank(predicate);
233
+ }
218
234
  }
219
235
 
220
236
  // ### `_encodeObject` represents an object
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n3",
3
- "version": "2.10.2",
3
+ "version": "2.10.4",
4
4
  "description": "Lightning fast, asynchronous, streaming Turtle / N3 / RDF library.",
5
5
  "author": "Ruben Verborgh <ruben.verborgh@gmail.com>",
6
6
  "keywords": [
package/src/N3Parser.js CHANGED
@@ -371,10 +371,14 @@ export default class N3Parser {
371
371
  case 'inversePredicate':
372
372
  this._inversePredicate = true;
373
373
  return this._readPredicateAfterVerb;
374
+ case '|}':
375
+ // Expected predicate didn't come, must have been trailing semicolon
376
+ // or an empty annotation block
377
+ this._subject = null;
378
+ return this._readAnnotationBlockPunctuation(token);
374
379
  case '.':
375
380
  case ']':
376
381
  case '}':
377
- case '|}':
378
382
  // Expected predicate didn't come, must have been trailing semicolon.
379
383
  // In N3 mode, a subject (such as a path) can be a statement by itself.
380
384
  if (this._predicate === null && !this._n3Mode)
@@ -952,7 +956,7 @@ export default class N3Parser {
952
956
 
953
957
  // ### `_readPunctuation` reads punctuation between quads or quad parts
954
958
  _readPunctuation(token) {
955
- let next, graph = this._graph, startingAnnotation = false;
959
+ let next, graph = this._graph;
956
960
  const subject = this._subject, inversePredicate = this._inversePredicate;
957
961
  switch (token.type) {
958
962
  // A closing brace ends a graph
@@ -978,38 +982,13 @@ export default class N3Parser {
978
982
  case ',':
979
983
  next = this._readObject;
980
984
  break;
981
- // ~ is allowed in the annotation syntax
985
+ // A reifier or annotation block annotates the triple just read
982
986
  case '~':
983
- // Only invalidate the cache for a genuinely new triple - chained annotation blocks on the
984
- // same triple (subject already null from a preceding annotation) must keep reusing it.
985
- if (subject !== null)
986
- this._tripleTerm = null;
987
- next = this._readReifierInAnnotation;
988
- startingAnnotation = true;
989
- break;
990
- // {| means that the current triple is annotated with predicate-object pairs.
991
987
  case '{|':
992
- // Continue using the last triple as reified triple subject for the predicate-object pairs.
993
- // Same staleness rule as ~ above.
994
- if (subject !== null)
995
- this._tripleTerm = null;
996
- this._subject = this._readTripleTerm();
997
- this._inversePredicate = false;
998
- this._validAnnotation = false;
999
- startingAnnotation = true;
1000
- next = this._readPredicate;
1001
- break;
1002
- // |} means that the current reified triple in annotation syntax is finalized.
988
+ return this._readAnnotationStart(token);
989
+ // An annotation block can only be closed from within one
1003
990
  case '|}':
1004
- if (!this._annotation)
1005
- return this._error('Unexpected annotation syntax closing', token);
1006
- if (!this._validAnnotation)
1007
- return this._error('Annotation block can not be empty', token);
1008
- this._subject = null;
1009
- this._annotation = false;
1010
- this._inversePredicate = false;
1011
- next = this._getContextEndReader();
1012
- break;
991
+ return this._error('Unexpected annotation syntax closing', token);
1013
992
  default:
1014
993
  // An entity means this is a quad (only allowed if not already inside a graph)
1015
994
  if (this._supportsQuads && this._graph === null && (graph = this._readEntity(token)) !== undefined) {
@@ -1019,13 +998,10 @@ export default class N3Parser {
1019
998
  return this._error(`Expected punctuation to follow "${this._object.id}"`, token);
1020
999
  }
1021
1000
  // A quad has been completed now, so return it
1022
- if (subject !== null && (!startingAnnotation || (startingAnnotation && !this._annotation))) {
1001
+ if (subject !== null) {
1023
1002
  const predicate = this._predicate, object = this._object;
1024
1003
  this._emit(subject, predicate, object, graph, inversePredicate);
1025
1004
  }
1026
- if (startingAnnotation) {
1027
- this._annotation = true;
1028
- }
1029
1005
  return next;
1030
1006
  }
1031
1007
 
@@ -1043,20 +1019,15 @@ export default class N3Parser {
1043
1019
  next = this._readObject;
1044
1020
  break;
1045
1021
  // Annotation syntax applies to the quad just read, exactly as it does
1046
- // outside of a blank node property list. `|}` arrives here too, because
1047
- // the objects inside the annotation block are themselves read within the
1048
- // enclosing blank node context.
1022
+ // outside of a blank node property list
1049
1023
  case '~':
1050
1024
  case '{|':
1025
+ return this._readAnnotationStart(token);
1051
1026
  case '|}':
1052
- return this._readPunctuation(token);
1027
+ return this._error('Unexpected annotation syntax closing', token);
1053
1028
  default:
1054
1029
  return this._error(`Expected punctuation to follow "${this._object.id}"`, token);
1055
1030
  }
1056
- // An annotation block consumes the subject it annotates, so there is
1057
- // nothing left to share with a following predicate-object pair
1058
- if (this._subject === null)
1059
- return this._error('Expected ] to follow annotation', token);
1060
1031
  // A quad has been completed now, so return it
1061
1032
  this._emitCurrent(this._subject, this._predicate, this._object, this._graph);
1062
1033
  if (resetInversePredicate)
@@ -1356,34 +1327,27 @@ export default class N3Parser {
1356
1327
  return this._readReifiedTripleTail;
1357
1328
  }
1358
1329
 
1359
- // ### `_readReifier` reads the optional triple term identifier after a tilde when in annotation syntax.
1360
- _readReifierInAnnotation(token) {
1361
- // If next token is a reifier, read it as such.
1362
- if (token.type === 'IRI' || token.type === 'typeIRI' || token.type === 'type' || token.type === 'prefixed' || token.type === 'blank' || token.type === 'var') {
1363
- this._reifier = this._readEntity(token);
1364
- return this._readAnnotationBlockOrPunctuation;
1365
- }
1366
- // Otherwise, emit and assert triple term.
1367
- this._readTripleTerm();
1368
- this._subject = null;
1369
- return this._getContextEndReader().call(this, token);
1330
+ // ### `_readAnnotationStart` reads the first reifier or annotation block after an object,
1331
+ // which completes the annotated quad
1332
+ _readAnnotationStart(token) {
1333
+ this._emitCurrent(this._subject, this._predicate, this._object, this._graph);
1334
+ // A new triple is annotated, so its triple term cannot be reused
1335
+ this._tripleTerm = null;
1336
+ return this._readAnnotation(token);
1370
1337
  }
1371
1338
 
1372
- // ### `_readAnnotationBlockOrPunctuation` reads what follows an explicit reifier:
1373
- // either an annotation block, which reuses the reifier as its subject,
1374
- // or punctuation, in which case the reifier stands alone and its triple
1375
- // term still needs to be asserted here.
1376
- _readAnnotationBlockOrPunctuation(token) {
1377
- if (token.type === '{|')
1378
- return this._readPunctuation(token);
1379
-
1380
- this._readTripleTerm();
1381
- this._annotation = false;
1382
- // A shared subject or predicate goes on to reify a *different* triple,
1383
- // so the term just asserted must not be reused for the next one.
1339
+ // ### `_readAnnotation` reads what follows an annotated quad:
1340
+ // further reifiers or annotation blocks for that same quad, or punctuation
1341
+ _readAnnotation(token) {
1342
+ switch (token.type) {
1343
+ case '~':
1344
+ return this._readReifierInAnnotation;
1345
+ case '{|':
1346
+ return this._readAnnotationBlockHead(token);
1347
+ }
1348
+ // The annotated quad was already emitted when its annotation started,
1349
+ // so continue without emitting it a second time
1384
1350
  this._tripleTerm = null;
1385
- // The annotated triple was already emitted when the tilde was read,
1386
- // so continue without letting `_readPunctuation` emit it a second time.
1387
1351
  switch (token.type) {
1388
1352
  // The subject stays shared with the next predicate-object pair
1389
1353
  case ';':
@@ -1394,12 +1358,73 @@ export default class N3Parser {
1394
1358
  return this._readObject;
1395
1359
  default:
1396
1360
  this._subject = null;
1397
- // Resume in the enclosing context, which is top-level punctuation
1398
- // unless the reified triple sits inside a blank node property list
1361
+ // Resume in the enclosing context
1399
1362
  return this._getContextEndReader().call(this, token);
1400
1363
  }
1401
1364
  }
1402
1365
 
1366
+ // ### `_readReifierInAnnotation` reads the optional reifier after a tilde in annotation syntax
1367
+ _readReifierInAnnotation(token) {
1368
+ switch (token.type) {
1369
+ case 'IRI':
1370
+ case 'typeIRI':
1371
+ case 'type':
1372
+ case 'prefixed':
1373
+ case 'blank':
1374
+ case 'var':
1375
+ this._reifier = this._readEntity(token);
1376
+ return this._readAnnotationBlockOrReifier;
1377
+ }
1378
+ // Without an identifier, the reifier is a fresh blank node
1379
+ this._reifier = this._factory.blankNode();
1380
+ return this._readAnnotationBlockOrReifier(token);
1381
+ }
1382
+
1383
+ // ### `_readAnnotationBlockOrReifier` reads what follows a reifier:
1384
+ // either an annotation block, which uses the reifier as its subject,
1385
+ // or anything else, in which case the reifier stands alone
1386
+ _readAnnotationBlockOrReifier(token) {
1387
+ if (token.type === '{|')
1388
+ return this._readAnnotationBlockHead(token);
1389
+ this._readTripleTerm();
1390
+ return this._readAnnotation(token);
1391
+ }
1392
+
1393
+ // ### `_readAnnotationBlockHead` opens an annotation block,
1394
+ // whose predicate-object pairs describe the reifier of the annotated quad
1395
+ _readAnnotationBlockHead(token) {
1396
+ const reifier = this._readTripleTerm();
1397
+ this._saveContext('annotation', this._graph, this._subject, this._predicate, this._object);
1398
+ // Restored when the block closes, so further annotations reuse the same triple term
1399
+ this._contextStack[this._contextStack.length - 1].tripleTerm = this._tripleTerm;
1400
+ this._subject = reifier;
1401
+ this._predicate = this._object = this._tripleTerm = null;
1402
+ this._inversePredicate = false;
1403
+ this._validAnnotation = false;
1404
+ return this._readPredicate;
1405
+ }
1406
+
1407
+ // ### `_readAnnotationBlockPunctuation` reads punctuation inside an annotation block
1408
+ _readAnnotationBlockPunctuation(token) {
1409
+ const stack = this._contextStack;
1410
+ if (token.type === '|}') {
1411
+ if (!stack.length || stack[stack.length - 1].type !== 'annotation')
1412
+ return this._error('Unexpected annotation syntax closing', token);
1413
+ if (!this._validAnnotation)
1414
+ return this._error('Annotation block can not be empty', token);
1415
+ // Emit the last quad of the block, unless a trailing semicolon already did
1416
+ if (this._subject !== null)
1417
+ this._emitCurrent(this._subject, this._predicate, this._object, this._graph);
1418
+ // Return to the annotated quad, which can be followed by more annotations
1419
+ const { tripleTerm } = stack[stack.length - 1];
1420
+ this._restoreContext('annotation', token);
1421
+ this._tripleTerm = tripleTerm;
1422
+ return this._readAnnotation;
1423
+ }
1424
+ // Otherwise, punctuation inside a block works like inside a blank node property list
1425
+ return this._readBlankNodePunctuation(token);
1426
+ }
1427
+
1403
1428
  _readTripleTerm() {
1404
1429
  const stack = this._contextStack, parent = stack.length && stack[stack.length - 1];
1405
1430
  const parentGraph = parent ? parent.graph : undefined;
@@ -1429,6 +1454,8 @@ export default class N3Parser {
1429
1454
  return this._readTripleTermTail;
1430
1455
  case '<<':
1431
1456
  return this._readReifiedTripleTailOrReifier;
1457
+ case 'annotation':
1458
+ return this._readAnnotationBlockPunctuation;
1432
1459
  }
1433
1460
  }
1434
1461
 
package/src/N3Writer.js CHANGED
@@ -129,7 +129,8 @@ export default class N3Writer {
129
129
  // ### `quadToString` serializes a quad as a string
130
130
  quadToString(subject, predicate, object, graph) {
131
131
  return `${this._encodeSubject(subject)} ${
132
- this._encodeIriOrBlank(predicate)} ${
132
+ predicate.termType === 'Literal' ?
133
+ this._encodeLiteral(predicate) : this._encodeIriOrBlank(predicate)} ${
133
134
  this._encodeObject(object)
134
135
  }${graph && !isDefaultGraph(graph) ? ` ${this._encodeIriOrBlank(graph)} .\n` : ' .\n'}`;
135
136
  }
@@ -144,8 +145,15 @@ export default class N3Writer {
144
145
 
145
146
  // ### `_encodeSubject` represents a subject
146
147
  _encodeSubject(entity) {
147
- return entity.termType === 'Quad' ?
148
- this._encodeQuad(entity) : this._encodeIriOrBlank(entity);
148
+ switch (entity.termType) {
149
+ case 'Quad':
150
+ return this._encodeQuad(entity);
151
+ // Literal subjects are only valid in N3
152
+ case 'Literal':
153
+ return this._encodeLiteral(entity);
154
+ default:
155
+ return this._encodeIriOrBlank(entity);
156
+ }
149
157
  }
150
158
 
151
159
  // ### `_encodeIriOrBlank` represents an IRI or blank node
@@ -223,7 +231,15 @@ export default class N3Writer {
223
231
 
224
232
  // ### `_encodePredicate` represents a predicate
225
233
  _encodePredicate(predicate) {
226
- return predicate.value === rdf.type ? 'a' : this._encodeIriOrBlank(predicate);
234
+ switch (predicate.termType) {
235
+ case 'NamedNode':
236
+ return predicate.value === rdf.type ? 'a' : this._encodeIriOrBlank(predicate);
237
+ // Literal predicates are only valid in N3
238
+ case 'Literal':
239
+ return this._encodeLiteral(predicate);
240
+ default:
241
+ return this._encodeIriOrBlank(predicate);
242
+ }
227
243
  }
228
244
 
229
245
  // ### `_encodeObject` represents an object