n3 3.0.0-alpha.7 → 3.0.0-alpha.9
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/README.md +10 -1
- package/browser/n3.esm.min.js +10 -9
- package/browser/n3.min.js +10 -9
- package/lib/N3DataFactory.js +3 -2
- package/lib/N3Lexer.js +153 -39
- package/lib/N3Parser.js +22 -3
- package/lib/N3Reasoner.js +5 -4
- package/lib/N3Store.js +128 -133
- package/lib/N3Writer.js +9 -38
- package/package.json +7 -2
- package/src/N3DataFactory.js +3 -2
- package/src/N3Lexer.js +176 -43
- package/src/N3Parser.js +26 -3
- package/src/N3Reasoner.js +6 -4
- package/src/N3Store.js +122 -143
- package/src/N3Writer.js +12 -42
package/src/N3Store.js
CHANGED
|
@@ -23,101 +23,6 @@ function hasInIndex(index0, key0, key1, key2) {
|
|
|
23
23
|
return !!index2 && key2 in index2;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
function merge(target, source, depth = 4) {
|
|
27
|
-
let size = target[SIZE] || 0;
|
|
28
|
-
for (const key in source) {
|
|
29
|
-
if (!(key in target)) {
|
|
30
|
-
size++;
|
|
31
|
-
target[key] = depth === 0 ? null : merge(Object.create(null), source[key], depth - 1);
|
|
32
|
-
}
|
|
33
|
-
// Merge into the existing object in place,
|
|
34
|
-
// as graph objects are frozen and cannot be reassigned
|
|
35
|
-
else if (depth !== 0)
|
|
36
|
-
merge(target[key], source[key], depth - 1);
|
|
37
|
-
}
|
|
38
|
-
// Depth 2 is the level of the `subjects`, `predicates`, and `objects` indexes.
|
|
39
|
-
if (depth <= 2)
|
|
40
|
-
target[SIZE] = size;
|
|
41
|
-
|
|
42
|
-
return target;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Determines the intersection of the `_graphs` index s1 and s2.
|
|
47
|
-
* s1 and s2 *must* belong to Stores that share an `_entityIndex`.
|
|
48
|
-
*
|
|
49
|
-
* False is returned when there is no intersection; this should
|
|
50
|
-
* *not* be set as the value for an index.
|
|
51
|
-
*/
|
|
52
|
-
function intersect(s1, s2, depth = 4) {
|
|
53
|
-
let target = false, size = 0;
|
|
54
|
-
|
|
55
|
-
if (depth <= 2 && s2[SIZE] < s1[SIZE])
|
|
56
|
-
[s1, s2] = [s2, s1];
|
|
57
|
-
|
|
58
|
-
for (const key in s1) {
|
|
59
|
-
if (key in s2) {
|
|
60
|
-
const intersection = depth === 0 ? null : intersect(s1[key], s2[key], depth - 1);
|
|
61
|
-
if (intersection !== false) {
|
|
62
|
-
target = target || Object.create(null);
|
|
63
|
-
target[key] = intersection;
|
|
64
|
-
size++;
|
|
65
|
-
}
|
|
66
|
-
// Depth 3 is the 'subjects', 'predicates' and 'objects' keys.
|
|
67
|
-
// If the 'subjects' index is empty, so will the 'predicates' and 'objects' index.
|
|
68
|
-
else if (depth === 3) {
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Depth 2 is the level of the `subjects`, `predicates`, and `objects` indexes.
|
|
75
|
-
if (depth <= 2 && target)
|
|
76
|
-
target[SIZE] = size;
|
|
77
|
-
|
|
78
|
-
return target;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Determines the difference of the `_graphs` index s1 and s2.
|
|
83
|
-
* s1 and s2 *must* belong to Stores that share an `_entityIndex`.
|
|
84
|
-
*
|
|
85
|
-
* False is returned when there is no difference; this should
|
|
86
|
-
* *not* be set as the value for an index.
|
|
87
|
-
*/
|
|
88
|
-
function difference(s1, s2, depth = 4) {
|
|
89
|
-
let target = false, size = 0;
|
|
90
|
-
|
|
91
|
-
for (const key in s1) {
|
|
92
|
-
// When the key is not in the index, then none of the triples defined by s1[key] are
|
|
93
|
-
// in s2 and so we want to copy them over to the resultant store.
|
|
94
|
-
if (!(key in s2)) {
|
|
95
|
-
target = target || Object.create(null);
|
|
96
|
-
target[key] = depth === 0 ? null : merge({}, s1[key], depth - 1);
|
|
97
|
-
size++;
|
|
98
|
-
}
|
|
99
|
-
else if (depth !== 0) {
|
|
100
|
-
const diff = difference(s1[key], s2[key], depth - 1);
|
|
101
|
-
if (diff !== false) {
|
|
102
|
-
target = target || Object.create(null);
|
|
103
|
-
target[key] = diff;
|
|
104
|
-
size++;
|
|
105
|
-
}
|
|
106
|
-
// Depth 3 is the 'subjects', 'predicates' and 'objects' keys.
|
|
107
|
-
// If the 'subjects' index is empty, so will the 'predicates' and 'objects' index.
|
|
108
|
-
else if (depth === 3) {
|
|
109
|
-
return false;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Depth 2 is the level of the `subjects`, `predicates`, and `objects` indexes.
|
|
115
|
-
if (depth <= 2 && target)
|
|
116
|
-
target[SIZE] = size;
|
|
117
|
-
|
|
118
|
-
return target;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
26
|
// Returns the key of a term in the entity index.
|
|
122
27
|
// Keys mark the term type by their first character, so the IRI of a named node
|
|
123
28
|
// that starts with such a marker (as relative IRIs can) is wrapped in < and >.
|
|
@@ -242,6 +147,12 @@ export class N3EntityIndex {
|
|
|
242
147
|
}
|
|
243
148
|
}
|
|
244
149
|
|
|
150
|
+
// Returns the size of a store from this copy of N3 if it is known without counting,
|
|
151
|
+
// or null otherwise
|
|
152
|
+
function knownSize(dataset) {
|
|
153
|
+
return dataset instanceof N3Store ? dataset._size : null;
|
|
154
|
+
}
|
|
155
|
+
|
|
245
156
|
// ## Constructor
|
|
246
157
|
export default class N3Store {
|
|
247
158
|
constructor(quads, options) {
|
|
@@ -249,6 +160,7 @@ export default class N3Store {
|
|
|
249
160
|
this._size = 0;
|
|
250
161
|
// `_graphs` contains subject, predicate, and object indexes per graph
|
|
251
162
|
this._graphs = Object.create(null);
|
|
163
|
+
this._graphCount = 0;
|
|
252
164
|
// `_observers` contains weak references to views notified before every mutation
|
|
253
165
|
this._observers = null;
|
|
254
166
|
|
|
@@ -273,20 +185,11 @@ export default class N3Store {
|
|
|
273
185
|
|
|
274
186
|
// ### `size` returns the number of quads in the store
|
|
275
187
|
get size() {
|
|
276
|
-
//
|
|
277
|
-
|
|
278
|
-
if (
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
// Calculate the number of quads by counting to the deepest level
|
|
282
|
-
size = 0;
|
|
283
|
-
const graphs = this._graphs;
|
|
284
|
-
let subjects, subject;
|
|
285
|
-
for (const graphKey in graphs)
|
|
286
|
-
for (const subjectKey in (subjects = graphs[graphKey].subjects))
|
|
287
|
-
for (const predicateKey in (subject = subjects[subjectKey]))
|
|
288
|
-
size += subject[predicateKey][SIZE];
|
|
289
|
-
return this._size = size;
|
|
188
|
+
// The quad count is kept up to date by every change,
|
|
189
|
+
// except by reasoners from earlier versions of N3, which set it to null
|
|
190
|
+
if (this._size === null)
|
|
191
|
+
this._size = this.countQuads();
|
|
192
|
+
return this._size;
|
|
290
193
|
}
|
|
291
194
|
|
|
292
195
|
// ## Private methods
|
|
@@ -554,6 +457,7 @@ export default class N3Store {
|
|
|
554
457
|
// Freezing a graph helps subsequent `add` performance,
|
|
555
458
|
// and properties will never be modified anyway
|
|
556
459
|
Object.freeze(graphItem);
|
|
460
|
+
this._graphCount++;
|
|
557
461
|
}
|
|
558
462
|
|
|
559
463
|
// Notify observers before inserting a new quad so snapshots retain their prior contents
|
|
@@ -568,11 +472,67 @@ export default class N3Store {
|
|
|
568
472
|
this._addToIndex(graphItem.predicates, predicate, object, subject);
|
|
569
473
|
this._addToIndex(graphItem.objects, object, subject, predicate);
|
|
570
474
|
|
|
571
|
-
|
|
572
|
-
this._size = null;
|
|
475
|
+
if (this._size !== null) this._size++;
|
|
573
476
|
return true;
|
|
574
477
|
}
|
|
575
478
|
|
|
479
|
+
// ### `_addFromIndex` adds the quads in the given graph indexes of a store
|
|
480
|
+
// that shares this store's entity index, so no terms need to be converted.
|
|
481
|
+
// With `otherGraphs`, it only adds the quads that are not in those indexes.
|
|
482
|
+
// Index keys are strings, so the ids are converted back to the numbers that
|
|
483
|
+
// `addQuad` uses: forwarded views compare the ids they are notified with to
|
|
484
|
+
// their own numeric ids.
|
|
485
|
+
_addFromIndex(graphs, otherGraphs = null) {
|
|
486
|
+
for (const graphKey in graphs) {
|
|
487
|
+
const subjects = graphs[graphKey].subjects, other = otherGraphs && otherGraphs[graphKey];
|
|
488
|
+
const otherSubjects = other ? other.subjects : null;
|
|
489
|
+
for (const subjectKey in subjects) {
|
|
490
|
+
const subject = Number(subjectKey), predicates = subjects[subjectKey];
|
|
491
|
+
const otherPredicates = otherSubjects && otherSubjects[subjectKey];
|
|
492
|
+
for (const predicateKey in predicates) {
|
|
493
|
+
const predicate = Number(predicateKey), objects = predicates[predicateKey];
|
|
494
|
+
const otherObjects = otherPredicates && otherPredicates[predicateKey];
|
|
495
|
+
for (const objectKey in objects) {
|
|
496
|
+
if (!otherObjects || !(objectKey in otherObjects))
|
|
497
|
+
this._addQuad(subject, predicate, Number(objectKey), Number(graphKey));
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// ### `_addIntersectionFromIndex` adds the quads that are in both of the
|
|
505
|
+
// given graph indexes, walking the graphs of the first and, below them,
|
|
506
|
+
// whichever index has fewer keys
|
|
507
|
+
_addIntersectionFromIndex(graphs, otherGraphs) {
|
|
508
|
+
for (const graphKey in graphs) {
|
|
509
|
+
const other = otherGraphs[graphKey];
|
|
510
|
+
if (other) {
|
|
511
|
+
let subjects = graphs[graphKey].subjects, otherSubjects = other.subjects;
|
|
512
|
+
if (otherSubjects[SIZE] < subjects[SIZE])
|
|
513
|
+
[subjects, otherSubjects] = [otherSubjects, subjects];
|
|
514
|
+
for (const subjectKey in subjects) {
|
|
515
|
+
let predicates = subjects[subjectKey], otherPredicates = otherSubjects[subjectKey];
|
|
516
|
+
if (otherPredicates) {
|
|
517
|
+
if (otherPredicates[SIZE] < predicates[SIZE])
|
|
518
|
+
[predicates, otherPredicates] = [otherPredicates, predicates];
|
|
519
|
+
for (const predicateKey in predicates) {
|
|
520
|
+
let objects = predicates[predicateKey], otherObjects = otherPredicates[predicateKey];
|
|
521
|
+
if (otherObjects) {
|
|
522
|
+
if (otherObjects[SIZE] < objects[SIZE])
|
|
523
|
+
[objects, otherObjects] = [otherObjects, objects];
|
|
524
|
+
for (const objectKey in objects) {
|
|
525
|
+
if (objectKey in otherObjects)
|
|
526
|
+
this._addQuad(Number(subjectKey), Number(predicateKey), Number(objectKey), Number(graphKey));
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
576
536
|
// ### `addQuads` adds multiple quads to the store
|
|
577
537
|
addQuads(quads) {
|
|
578
538
|
for (let i = 0; i < quads.length; i++)
|
|
@@ -688,8 +648,10 @@ export default class N3Store {
|
|
|
688
648
|
if (this._size !== null) this._size--;
|
|
689
649
|
|
|
690
650
|
// Remove the graph if it is empty
|
|
691
|
-
if (graphItem.subjects[SIZE] === 0)
|
|
651
|
+
if (graphItem.subjects[SIZE] === 0) {
|
|
692
652
|
delete graphs[graph];
|
|
653
|
+
this._graphCount--;
|
|
654
|
+
}
|
|
693
655
|
return true;
|
|
694
656
|
}
|
|
695
657
|
|
|
@@ -827,10 +789,14 @@ export default class N3Store {
|
|
|
827
789
|
// If only predicate and possibly object are given, the predicate index will be the fastest
|
|
828
790
|
count += this._countInIndex(content.predicates, predicateId, objectId, subjectId);
|
|
829
791
|
}
|
|
830
|
-
else {
|
|
831
|
-
// If only object is
|
|
792
|
+
else if (object) {
|
|
793
|
+
// If only object is given, the object index will be the fastest
|
|
832
794
|
count += this._countInIndex(content.objects, objectId, subjectId, predicateId);
|
|
833
795
|
}
|
|
796
|
+
else {
|
|
797
|
+
// Without a pattern, the subject index sums the fewest leaf counts
|
|
798
|
+
count += this._countInIndex(content.subjects);
|
|
799
|
+
}
|
|
834
800
|
}
|
|
835
801
|
}
|
|
836
802
|
return count;
|
|
@@ -1148,13 +1114,9 @@ export default class N3Store {
|
|
|
1148
1114
|
|
|
1149
1115
|
if (Array.isArray(quads))
|
|
1150
1116
|
this.addQuads(quads);
|
|
1151
|
-
//
|
|
1152
|
-
else if (
|
|
1153
|
-
|
|
1154
|
-
this._graphs = merge(this._graphs, quads._graphs);
|
|
1155
|
-
this._size = null; // Invalidate the cached size
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1117
|
+
// A store with the same entity index can be copied by identifier
|
|
1118
|
+
else if (quads instanceof N3Store && quads._entityIndex === this._entityIndex)
|
|
1119
|
+
this._addFromIndex(quads._graphs);
|
|
1158
1120
|
else {
|
|
1159
1121
|
for (const quad of quads)
|
|
1160
1122
|
this.add(quad);
|
|
@@ -1175,19 +1137,26 @@ export default class N3Store {
|
|
|
1175
1137
|
if (other === this)
|
|
1176
1138
|
return true;
|
|
1177
1139
|
|
|
1178
|
-
if (!(other instanceof N3Store) || this._entityIndex !== other._entityIndex)
|
|
1140
|
+
if (!(other instanceof N3Store) || this._entityIndex !== other._entityIndex) {
|
|
1141
|
+
// A larger set cannot be a subset, but only compare sizes that are known without counting
|
|
1142
|
+
const otherSize = knownSize(other), thisSize = this._size;
|
|
1143
|
+
if (otherSize !== null && thisSize !== null && otherSize > thisSize)
|
|
1144
|
+
return false;
|
|
1179
1145
|
return other.every(quad => this.has(quad));
|
|
1146
|
+
}
|
|
1180
1147
|
|
|
1148
|
+
// At every level, the index of the subset cannot have more entries
|
|
1181
1149
|
const g1 = this._graphs, g2 = other._graphs;
|
|
1182
|
-
let s1, s2, p1, p2, o1;
|
|
1150
|
+
let s1, s2, p1, p2, o1, o2;
|
|
1183
1151
|
for (const graph in g2) {
|
|
1184
1152
|
if (!(s1 = g1[graph])) return false;
|
|
1185
1153
|
s1 = s1.subjects;
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1154
|
+
if ((s2 = g2[graph].subjects)[SIZE] > s1[SIZE]) return false;
|
|
1155
|
+
for (const subject in s2) {
|
|
1156
|
+
if (!(p1 = s1[subject]) || (p2 = s2[subject])[SIZE] > p1[SIZE]) return false;
|
|
1157
|
+
for (const predicate in p2) {
|
|
1158
|
+
if (!(o1 = p1[predicate]) || (o2 = p2[predicate])[SIZE] > o1[SIZE]) return false;
|
|
1159
|
+
for (const object in o2)
|
|
1191
1160
|
if (!(object in o1)) return false;
|
|
1192
1161
|
}
|
|
1193
1162
|
}
|
|
@@ -1224,11 +1193,7 @@ export default class N3Store {
|
|
|
1224
1193
|
|
|
1225
1194
|
if ((other instanceof N3Store) && other._entityIndex === this._entityIndex) {
|
|
1226
1195
|
const store = new N3Store({ entityIndex: this._entityIndex });
|
|
1227
|
-
|
|
1228
|
-
if (graphs) {
|
|
1229
|
-
store._graphs = graphs;
|
|
1230
|
-
store._size = null;
|
|
1231
|
-
}
|
|
1196
|
+
store._addFromIndex(this._graphs, other._graphs);
|
|
1232
1197
|
return store;
|
|
1233
1198
|
}
|
|
1234
1199
|
|
|
@@ -1269,20 +1234,34 @@ export default class N3Store {
|
|
|
1269
1234
|
|
|
1270
1235
|
if (other === this) {
|
|
1271
1236
|
const store = new N3Store({ entityIndex: this._entityIndex });
|
|
1272
|
-
store.
|
|
1273
|
-
store._size = this._size;
|
|
1237
|
+
store._addFromIndex(this._graphs);
|
|
1274
1238
|
return store;
|
|
1275
1239
|
}
|
|
1276
1240
|
else if ((other instanceof N3Store) && this._entityIndex === other._entityIndex) {
|
|
1277
1241
|
const store = new N3Store({ entityIndex: this._entityIndex });
|
|
1278
|
-
|
|
1279
|
-
if (
|
|
1280
|
-
|
|
1281
|
-
|
|
1242
|
+
// Starting a loop over no graphs costs more than checking for an empty store
|
|
1243
|
+
if (this._size !== 0 && other._size !== 0) {
|
|
1244
|
+
if (other._graphCount < this._graphCount)
|
|
1245
|
+
store._addIntersectionFromIndex(other._graphs, this._graphs);
|
|
1246
|
+
else
|
|
1247
|
+
store._addIntersectionFromIndex(this._graphs, other._graphs);
|
|
1282
1248
|
}
|
|
1283
1249
|
return store;
|
|
1284
1250
|
}
|
|
1285
1251
|
|
|
1252
|
+
// Test the quads of the smaller dataset against the larger one
|
|
1253
|
+
// when both sizes are known without counting
|
|
1254
|
+
const otherSize = knownSize(other), thisSize = this._size;
|
|
1255
|
+
if (otherSize !== null && thisSize !== null && otherSize < thisSize && typeof other[Symbol.iterator] === 'function' &&
|
|
1256
|
+
// unless it is a store whose custom factories may not create RDF/JS quads,
|
|
1257
|
+
// either for its quads or, through its entity index, for their terms
|
|
1258
|
+
other._factory === N3DataFactory && other._entityIndex._factory === N3DataFactory) {
|
|
1259
|
+
const store = new N3Store({ entityIndex: this._entityIndex });
|
|
1260
|
+
for (const quad of other)
|
|
1261
|
+
if (this.has(quad))
|
|
1262
|
+
store.add(quad);
|
|
1263
|
+
return store;
|
|
1264
|
+
}
|
|
1286
1265
|
return this.filter(quad => other.has(quad));
|
|
1287
1266
|
}
|
|
1288
1267
|
|
|
@@ -1353,9 +1332,7 @@ export default class N3Store {
|
|
|
1353
1332
|
*/
|
|
1354
1333
|
union(quads) {
|
|
1355
1334
|
const store = new N3Store({ entityIndex: this._entityIndex });
|
|
1356
|
-
store.
|
|
1357
|
-
store._size = this._size;
|
|
1358
|
-
|
|
1335
|
+
store._addFromIndex(this._graphs);
|
|
1359
1336
|
store.addAll(quads);
|
|
1360
1337
|
return store;
|
|
1361
1338
|
}
|
|
@@ -1620,8 +1597,10 @@ class DatasetCoreAndReadableStream extends Readable {
|
|
|
1620
1597
|
objects = indexMatch(content.objects, [objectId, subjectId, predicateId]);
|
|
1621
1598
|
}
|
|
1622
1599
|
|
|
1623
|
-
if (subjects)
|
|
1600
|
+
if (subjects) {
|
|
1624
1601
|
newStore._graphs[graphKey] = { subjects, predicates, objects };
|
|
1602
|
+
newStore._graphCount++;
|
|
1603
|
+
}
|
|
1625
1604
|
}
|
|
1626
1605
|
}
|
|
1627
1606
|
newStore._size = null;
|
package/src/N3Writer.js
CHANGED
|
@@ -10,15 +10,11 @@ const DEFAULTGRAPH = N3DataFactory.defaultGraph();
|
|
|
10
10
|
const { rdf, xsd } = namespaces;
|
|
11
11
|
const { hasOwnProperty } = Object.prototype;
|
|
12
12
|
|
|
13
|
-
// Characters that require escaping in
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
// U+0000–U+001F, `"`, `\`, U+007F, U+FFFE, and U+FFFF.
|
|
19
|
-
// A negated class is as fast to test as a shorter class listing characters.
|
|
20
|
-
canonicalEscape = /[^ !#-\[\]-~\u0080-\uFFFD]/,
|
|
21
|
-
canonicalEscapeAll = /[^ !#-\[\]-~\u0080-\uFFFD]/g,
|
|
13
|
+
// Characters that require escaping, as in canonical N-Triples:
|
|
14
|
+
// U+0000–U+001F, `"`, `\`, U+007F, U+FFFE, and U+FFFF.
|
|
15
|
+
// A negated class is as fast to test as a shorter class listing characters.
|
|
16
|
+
const escape = /[^ !#-\[\]-~\u0080-\uFFFD]/,
|
|
17
|
+
escapeAll = /[^ !#-\[\]-~\u0080-\uFFFD]/g,
|
|
22
18
|
escapedCharacters = {
|
|
23
19
|
'\\': '\\\\', '"': '\\"', '\t': '\\t',
|
|
24
20
|
'\n': '\\n', '\r': '\\r', '\b': '\\b', '\f': '\\f',
|
|
@@ -72,7 +68,6 @@ export default class N3Writer {
|
|
|
72
68
|
this._subject = null;
|
|
73
69
|
if (!(/triple|quad/i).test(options.format)) {
|
|
74
70
|
this._lineMode = false;
|
|
75
|
-
this._escape = escape, this._escapeAll = escapeAll, this._characterReplacer = characterReplacer;
|
|
76
71
|
this._graph = DEFAULTGRAPH;
|
|
77
72
|
if (options.version)
|
|
78
73
|
this._write(`@version "${options.version}".\n`);
|
|
@@ -89,9 +84,6 @@ export default class N3Writer {
|
|
|
89
84
|
else {
|
|
90
85
|
this._lineMode = true;
|
|
91
86
|
this._writeQuad = this._writeQuadLine;
|
|
92
|
-
// N-Triples and N-Quads are written in their canonical form
|
|
93
|
-
this._escape = canonicalEscape, this._escapeAll = canonicalEscapeAll;
|
|
94
|
-
this._characterReplacer = canonicalCharacterReplacer;
|
|
95
87
|
if (options.version)
|
|
96
88
|
this._write(`VERSION "${options.version}"\n`);
|
|
97
89
|
}
|
|
@@ -208,8 +200,8 @@ export default class N3Writer {
|
|
|
208
200
|
iri = this._baseIri.toRelative(iri);
|
|
209
201
|
}
|
|
210
202
|
// Escape special characters
|
|
211
|
-
if (
|
|
212
|
-
iri = iri.replace(
|
|
203
|
+
if (escape.test(iri))
|
|
204
|
+
iri = iri.replace(escapeAll, characterReplacer);
|
|
213
205
|
// Try to represent the IRI as prefixed name, unless no prefixes were added
|
|
214
206
|
const prefixMatch = this._hasPrefixes ? (this._prefixRegex || this._createPrefixRegex()).exec(iri) : null;
|
|
215
207
|
return !prefixMatch ? `<${iri}>` : this._prefixIRIs[prefixMatch[1]] + prefixMatch[2];
|
|
@@ -219,8 +211,8 @@ export default class N3Writer {
|
|
|
219
211
|
_encodeLiteral(literal) {
|
|
220
212
|
// Escape special characters
|
|
221
213
|
let value = literal.value;
|
|
222
|
-
if (
|
|
223
|
-
value = value.replace(
|
|
214
|
+
if (escape.test(value))
|
|
215
|
+
value = value.replace(escapeAll, characterReplacer);
|
|
224
216
|
|
|
225
217
|
// Write a language-tagged literal
|
|
226
218
|
const language = literal.language;
|
|
@@ -291,13 +283,11 @@ export default class N3Writer {
|
|
|
291
283
|
|
|
292
284
|
// ### `_encodeQuad` encodes an RDF-star quad
|
|
293
285
|
_encodeQuad({ subject, predicate, object, graph }) {
|
|
294
|
-
|
|
295
|
-
const space = this._lineMode ? ' ' : '';
|
|
296
|
-
return `<<(${space}${
|
|
286
|
+
return `<<( ${
|
|
297
287
|
this._encodeSubject(subject)} ${
|
|
298
288
|
this._encodePredicate(predicate)} ${
|
|
299
289
|
this._encodeObject(object)}${
|
|
300
|
-
isDefaultGraph(graph) ? '' : ` ${this._encodeIriOrBlank(graph)}`}
|
|
290
|
+
isDefaultGraph(graph) ? '' : ` ${this._encodeIriOrBlank(graph)}`} )>>`;
|
|
301
291
|
}
|
|
302
292
|
|
|
303
293
|
// ### `_blockedWrite` replaces `_write` after the writer has been closed
|
|
@@ -440,27 +430,7 @@ export default class N3Writer {
|
|
|
440
430
|
|
|
441
431
|
// Replaces a character by its escaped version
|
|
442
432
|
function characterReplacer(character) {
|
|
443
|
-
//
|
|
444
|
-
let result = escapedCharacters[character];
|
|
445
|
-
if (result === undefined) {
|
|
446
|
-
// Replace a single character with its 4-bit unicode escape sequence
|
|
447
|
-
if (character.length === 1) {
|
|
448
|
-
result = character.charCodeAt(0).toString(16);
|
|
449
|
-
result = '\\u0000'.substr(0, 6 - result.length) + result;
|
|
450
|
-
}
|
|
451
|
-
// Replace a surrogate pair with its 8-bit unicode escape sequence
|
|
452
|
-
else {
|
|
453
|
-
result = ((character.charCodeAt(0) - 0xD800) * 0x400 +
|
|
454
|
-
character.charCodeAt(1) + 0x2400).toString(16);
|
|
455
|
-
result = '\\U00000000'.substr(0, 10 - result.length) + result;
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
return result;
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
// Replaces a character by its canonical N-Triples escape:
|
|
462
|
-
// a short escape where one exists, and an upper-case `\uXXXX` escape otherwise
|
|
463
|
-
function canonicalCharacterReplacer(character) {
|
|
433
|
+
// Use a short escape where one exists, and an upper-case `\uXXXX` escape otherwise
|
|
464
434
|
let result = escapedCharacters[character];
|
|
465
435
|
if (result === undefined) {
|
|
466
436
|
result = character.charCodeAt(0).toString(16).toUpperCase();
|