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/lib/N3Store.js
CHANGED
|
@@ -31,90 +31,6 @@ function hasInIndex(index0, key0, key1, key2) {
|
|
|
31
31
|
const index2 = index1 && index1[key1];
|
|
32
32
|
return !!index2 && key2 in index2;
|
|
33
33
|
}
|
|
34
|
-
function merge(target, source, depth = 4) {
|
|
35
|
-
let size = target[SIZE] || 0;
|
|
36
|
-
for (const key in source) {
|
|
37
|
-
if (!(key in target)) {
|
|
38
|
-
size++;
|
|
39
|
-
target[key] = depth === 0 ? null : merge(Object.create(null), source[key], depth - 1);
|
|
40
|
-
}
|
|
41
|
-
// Merge into the existing object in place,
|
|
42
|
-
// as graph objects are frozen and cannot be reassigned
|
|
43
|
-
else if (depth !== 0) merge(target[key], source[key], depth - 1);
|
|
44
|
-
}
|
|
45
|
-
// Depth 2 is the level of the `subjects`, `predicates`, and `objects` indexes.
|
|
46
|
-
if (depth <= 2) target[SIZE] = size;
|
|
47
|
-
return target;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Determines the intersection of the `_graphs` index s1 and s2.
|
|
52
|
-
* s1 and s2 *must* belong to Stores that share an `_entityIndex`.
|
|
53
|
-
*
|
|
54
|
-
* False is returned when there is no intersection; this should
|
|
55
|
-
* *not* be set as the value for an index.
|
|
56
|
-
*/
|
|
57
|
-
function intersect(s1, s2, depth = 4) {
|
|
58
|
-
let target = false,
|
|
59
|
-
size = 0;
|
|
60
|
-
if (depth <= 2 && s2[SIZE] < s1[SIZE]) [s1, s2] = [s2, s1];
|
|
61
|
-
for (const key in s1) {
|
|
62
|
-
if (key in s2) {
|
|
63
|
-
const intersection = depth === 0 ? null : intersect(s1[key], s2[key], depth - 1);
|
|
64
|
-
if (intersection !== false) {
|
|
65
|
-
target = target || Object.create(null);
|
|
66
|
-
target[key] = intersection;
|
|
67
|
-
size++;
|
|
68
|
-
}
|
|
69
|
-
// Depth 3 is the 'subjects', 'predicates' and 'objects' keys.
|
|
70
|
-
// If the 'subjects' index is empty, so will the 'predicates' and 'objects' index.
|
|
71
|
-
else if (depth === 3) {
|
|
72
|
-
return false;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Depth 2 is the level of the `subjects`, `predicates`, and `objects` indexes.
|
|
78
|
-
if (depth <= 2 && target) target[SIZE] = size;
|
|
79
|
-
return target;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Determines the difference of the `_graphs` index s1 and s2.
|
|
84
|
-
* s1 and s2 *must* belong to Stores that share an `_entityIndex`.
|
|
85
|
-
*
|
|
86
|
-
* False is returned when there is no difference; this should
|
|
87
|
-
* *not* be set as the value for an index.
|
|
88
|
-
*/
|
|
89
|
-
function difference(s1, s2, depth = 4) {
|
|
90
|
-
let target = false,
|
|
91
|
-
size = 0;
|
|
92
|
-
for (const key in s1) {
|
|
93
|
-
// When the key is not in the index, then none of the triples defined by s1[key] are
|
|
94
|
-
// in s2 and so we want to copy them over to the resultant store.
|
|
95
|
-
if (!(key in s2)) {
|
|
96
|
-
target = target || Object.create(null);
|
|
97
|
-
target[key] = depth === 0 ? null : merge({}, s1[key], depth - 1);
|
|
98
|
-
size++;
|
|
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) target[SIZE] = size;
|
|
116
|
-
return target;
|
|
117
|
-
}
|
|
118
34
|
|
|
119
35
|
// Returns the key of a term in the entity index.
|
|
120
36
|
// Keys mark the term type by their first character, so the IRI of a named node
|
|
@@ -216,14 +132,21 @@ class N3EntityIndex {
|
|
|
216
132
|
}
|
|
217
133
|
}
|
|
218
134
|
|
|
219
|
-
//
|
|
135
|
+
// Returns the size of a store from this copy of N3 if it is known without counting,
|
|
136
|
+
// or null otherwise
|
|
220
137
|
exports.N3EntityIndex = N3EntityIndex;
|
|
138
|
+
function knownSize(dataset) {
|
|
139
|
+
return dataset instanceof N3Store ? dataset._size : null;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// ## Constructor
|
|
221
143
|
class N3Store {
|
|
222
144
|
constructor(quads, options) {
|
|
223
145
|
// The number of quads is initially zero
|
|
224
146
|
this._size = 0;
|
|
225
147
|
// `_graphs` contains subject, predicate, and object indexes per graph
|
|
226
148
|
this._graphs = Object.create(null);
|
|
149
|
+
this._graphCount = 0;
|
|
227
150
|
// `_observers` contains weak references to views notified before every mutation
|
|
228
151
|
this._observers = null;
|
|
229
152
|
|
|
@@ -248,16 +171,10 @@ class N3Store {
|
|
|
248
171
|
|
|
249
172
|
// ### `size` returns the number of quads in the store
|
|
250
173
|
get size() {
|
|
251
|
-
//
|
|
252
|
-
|
|
253
|
-
if (
|
|
254
|
-
|
|
255
|
-
// Calculate the number of quads by counting to the deepest level
|
|
256
|
-
size = 0;
|
|
257
|
-
const graphs = this._graphs;
|
|
258
|
-
let subjects, subject;
|
|
259
|
-
for (const graphKey in graphs) for (const subjectKey in subjects = graphs[graphKey].subjects) for (const predicateKey in subject = subjects[subjectKey]) size += subject[predicateKey][SIZE];
|
|
260
|
-
return this._size = size;
|
|
174
|
+
// The quad count is kept up to date by every change,
|
|
175
|
+
// except by reasoners from earlier versions of N3, which set it to null
|
|
176
|
+
if (this._size === null) this._size = this.countQuads();
|
|
177
|
+
return this._size;
|
|
261
178
|
}
|
|
262
179
|
|
|
263
180
|
// ## Private methods
|
|
@@ -524,6 +441,7 @@ class N3Store {
|
|
|
524
441
|
// Freezing a graph helps subsequent `add` performance,
|
|
525
442
|
// and properties will never be modified anyway
|
|
526
443
|
Object.freeze(graphItem);
|
|
444
|
+
this._graphCount++;
|
|
527
445
|
}
|
|
528
446
|
|
|
529
447
|
// Notify observers before inserting a new quad so snapshots retain their prior contents
|
|
@@ -534,12 +452,68 @@ class N3Store {
|
|
|
534
452
|
if (!this._addToIndex(graphItem.subjects, subject, predicate, object)) return false;
|
|
535
453
|
this._addToIndex(graphItem.predicates, predicate, object, subject);
|
|
536
454
|
this._addToIndex(graphItem.objects, object, subject, predicate);
|
|
537
|
-
|
|
538
|
-
// The cached quad count is now invalid
|
|
539
|
-
this._size = null;
|
|
455
|
+
if (this._size !== null) this._size++;
|
|
540
456
|
return true;
|
|
541
457
|
}
|
|
542
458
|
|
|
459
|
+
// ### `_addFromIndex` adds the quads in the given graph indexes of a store
|
|
460
|
+
// that shares this store's entity index, so no terms need to be converted.
|
|
461
|
+
// With `otherGraphs`, it only adds the quads that are not in those indexes.
|
|
462
|
+
// Index keys are strings, so the ids are converted back to the numbers that
|
|
463
|
+
// `addQuad` uses: forwarded views compare the ids they are notified with to
|
|
464
|
+
// their own numeric ids.
|
|
465
|
+
_addFromIndex(graphs, otherGraphs = null) {
|
|
466
|
+
for (const graphKey in graphs) {
|
|
467
|
+
const subjects = graphs[graphKey].subjects,
|
|
468
|
+
other = otherGraphs && otherGraphs[graphKey];
|
|
469
|
+
const otherSubjects = other ? other.subjects : null;
|
|
470
|
+
for (const subjectKey in subjects) {
|
|
471
|
+
const subject = Number(subjectKey),
|
|
472
|
+
predicates = subjects[subjectKey];
|
|
473
|
+
const otherPredicates = otherSubjects && otherSubjects[subjectKey];
|
|
474
|
+
for (const predicateKey in predicates) {
|
|
475
|
+
const predicate = Number(predicateKey),
|
|
476
|
+
objects = predicates[predicateKey];
|
|
477
|
+
const otherObjects = otherPredicates && otherPredicates[predicateKey];
|
|
478
|
+
for (const objectKey in objects) {
|
|
479
|
+
if (!otherObjects || !(objectKey in otherObjects)) this._addQuad(subject, predicate, Number(objectKey), Number(graphKey));
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// ### `_addIntersectionFromIndex` adds the quads that are in both of the
|
|
487
|
+
// given graph indexes, walking the graphs of the first and, below them,
|
|
488
|
+
// whichever index has fewer keys
|
|
489
|
+
_addIntersectionFromIndex(graphs, otherGraphs) {
|
|
490
|
+
for (const graphKey in graphs) {
|
|
491
|
+
const other = otherGraphs[graphKey];
|
|
492
|
+
if (other) {
|
|
493
|
+
let subjects = graphs[graphKey].subjects,
|
|
494
|
+
otherSubjects = other.subjects;
|
|
495
|
+
if (otherSubjects[SIZE] < subjects[SIZE]) [subjects, otherSubjects] = [otherSubjects, subjects];
|
|
496
|
+
for (const subjectKey in subjects) {
|
|
497
|
+
let predicates = subjects[subjectKey],
|
|
498
|
+
otherPredicates = otherSubjects[subjectKey];
|
|
499
|
+
if (otherPredicates) {
|
|
500
|
+
if (otherPredicates[SIZE] < predicates[SIZE]) [predicates, otherPredicates] = [otherPredicates, predicates];
|
|
501
|
+
for (const predicateKey in predicates) {
|
|
502
|
+
let objects = predicates[predicateKey],
|
|
503
|
+
otherObjects = otherPredicates[predicateKey];
|
|
504
|
+
if (otherObjects) {
|
|
505
|
+
if (otherObjects[SIZE] < objects[SIZE]) [objects, otherObjects] = [otherObjects, objects];
|
|
506
|
+
for (const objectKey in objects) {
|
|
507
|
+
if (objectKey in otherObjects) this._addQuad(Number(subjectKey), Number(predicateKey), Number(objectKey), Number(graphKey));
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
543
517
|
// ### `addQuads` adds multiple quads to the store
|
|
544
518
|
addQuads(quads) {
|
|
545
519
|
for (let i = 0; i < quads.length; i++) this.addQuad(quads[i]);
|
|
@@ -667,7 +641,10 @@ class N3Store {
|
|
|
667
641
|
if (this._size !== null) this._size--;
|
|
668
642
|
|
|
669
643
|
// Remove the graph if it is empty
|
|
670
|
-
if (graphItem.subjects[SIZE] === 0)
|
|
644
|
+
if (graphItem.subjects[SIZE] === 0) {
|
|
645
|
+
delete graphs[graph];
|
|
646
|
+
this._graphCount--;
|
|
647
|
+
}
|
|
671
648
|
return true;
|
|
672
649
|
}
|
|
673
650
|
|
|
@@ -792,9 +769,12 @@ class N3Store {
|
|
|
792
769
|
} else if (predicate) {
|
|
793
770
|
// If only predicate and possibly object are given, the predicate index will be the fastest
|
|
794
771
|
count += this._countInIndex(content.predicates, predicateId, objectId, subjectId);
|
|
795
|
-
} else {
|
|
796
|
-
// If only object is
|
|
772
|
+
} else if (object) {
|
|
773
|
+
// If only object is given, the object index will be the fastest
|
|
797
774
|
count += this._countInIndex(content.objects, objectId, subjectId, predicateId);
|
|
775
|
+
} else {
|
|
776
|
+
// Without a pattern, the subject index sums the fewest leaf counts
|
|
777
|
+
count += this._countInIndex(content.subjects);
|
|
798
778
|
}
|
|
799
779
|
}
|
|
800
780
|
}
|
|
@@ -1078,13 +1058,8 @@ class N3Store {
|
|
|
1078
1058
|
addAll(quads) {
|
|
1079
1059
|
if (quads instanceof DatasetCoreAndReadableStream) quads = quads.filtered;
|
|
1080
1060
|
if (Array.isArray(quads)) this.addQuads(quads);
|
|
1081
|
-
//
|
|
1082
|
-
else if (
|
|
1083
|
-
if (quads._size !== 0) {
|
|
1084
|
-
this._graphs = merge(this._graphs, quads._graphs);
|
|
1085
|
-
this._size = null; // Invalidate the cached size
|
|
1086
|
-
}
|
|
1087
|
-
} else {
|
|
1061
|
+
// A store with the same entity index can be copied by identifier
|
|
1062
|
+
else if (quads instanceof N3Store && quads._entityIndex === this._entityIndex) this._addFromIndex(quads._graphs);else {
|
|
1088
1063
|
for (const quad of quads) this.add(quad);
|
|
1089
1064
|
}
|
|
1090
1065
|
return this;
|
|
@@ -1099,18 +1074,27 @@ class N3Store {
|
|
|
1099
1074
|
contains(other) {
|
|
1100
1075
|
if (other instanceof DatasetCoreAndReadableStream) other = other.filtered;
|
|
1101
1076
|
if (other === this) return true;
|
|
1102
|
-
if (!(other instanceof N3Store) || this._entityIndex !== other._entityIndex)
|
|
1077
|
+
if (!(other instanceof N3Store) || this._entityIndex !== other._entityIndex) {
|
|
1078
|
+
// A larger set cannot be a subset, but only compare sizes that are known without counting
|
|
1079
|
+
const otherSize = knownSize(other),
|
|
1080
|
+
thisSize = this._size;
|
|
1081
|
+
if (otherSize !== null && thisSize !== null && otherSize > thisSize) return false;
|
|
1082
|
+
return other.every(quad => this.has(quad));
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
// At every level, the index of the subset cannot have more entries
|
|
1103
1086
|
const g1 = this._graphs,
|
|
1104
1087
|
g2 = other._graphs;
|
|
1105
|
-
let s1, s2, p1, p2, o1;
|
|
1088
|
+
let s1, s2, p1, p2, o1, o2;
|
|
1106
1089
|
for (const graph in g2) {
|
|
1107
1090
|
if (!(s1 = g1[graph])) return false;
|
|
1108
1091
|
s1 = s1.subjects;
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1092
|
+
if ((s2 = g2[graph].subjects)[SIZE] > s1[SIZE]) return false;
|
|
1093
|
+
for (const subject in s2) {
|
|
1094
|
+
if (!(p1 = s1[subject]) || (p2 = s2[subject])[SIZE] > p1[SIZE]) return false;
|
|
1095
|
+
for (const predicate in p2) {
|
|
1096
|
+
if (!(o1 = p1[predicate]) || (o2 = p2[predicate])[SIZE] > o1[SIZE]) return false;
|
|
1097
|
+
for (const object in o2) if (!(object in o1)) return false;
|
|
1114
1098
|
}
|
|
1115
1099
|
}
|
|
1116
1100
|
}
|
|
@@ -1147,11 +1131,7 @@ class N3Store {
|
|
|
1147
1131
|
const store = new N3Store({
|
|
1148
1132
|
entityIndex: this._entityIndex
|
|
1149
1133
|
});
|
|
1150
|
-
|
|
1151
|
-
if (graphs) {
|
|
1152
|
-
store._graphs = graphs;
|
|
1153
|
-
store._size = null;
|
|
1154
|
-
}
|
|
1134
|
+
store._addFromIndex(this._graphs, other._graphs);
|
|
1155
1135
|
return store;
|
|
1156
1136
|
}
|
|
1157
1137
|
return this.filter(quad => !other.has(quad));
|
|
@@ -1189,20 +1169,33 @@ class N3Store {
|
|
|
1189
1169
|
const store = new N3Store({
|
|
1190
1170
|
entityIndex: this._entityIndex
|
|
1191
1171
|
});
|
|
1192
|
-
store.
|
|
1193
|
-
store._size = this._size;
|
|
1172
|
+
store._addFromIndex(this._graphs);
|
|
1194
1173
|
return store;
|
|
1195
1174
|
} else if (other instanceof N3Store && this._entityIndex === other._entityIndex) {
|
|
1196
1175
|
const store = new N3Store({
|
|
1197
1176
|
entityIndex: this._entityIndex
|
|
1198
1177
|
});
|
|
1199
|
-
|
|
1200
|
-
if (
|
|
1201
|
-
store._graphs
|
|
1202
|
-
store._size = null;
|
|
1178
|
+
// Starting a loop over no graphs costs more than checking for an empty store
|
|
1179
|
+
if (this._size !== 0 && other._size !== 0) {
|
|
1180
|
+
if (other._graphCount < this._graphCount) store._addIntersectionFromIndex(other._graphs, this._graphs);else store._addIntersectionFromIndex(this._graphs, other._graphs);
|
|
1203
1181
|
}
|
|
1204
1182
|
return store;
|
|
1205
1183
|
}
|
|
1184
|
+
|
|
1185
|
+
// Test the quads of the smaller dataset against the larger one
|
|
1186
|
+
// when both sizes are known without counting
|
|
1187
|
+
const otherSize = knownSize(other),
|
|
1188
|
+
thisSize = this._size;
|
|
1189
|
+
if (otherSize !== null && thisSize !== null && otherSize < thisSize && typeof other[Symbol.iterator] === 'function' &&
|
|
1190
|
+
// unless it is a store whose custom factories may not create RDF/JS quads,
|
|
1191
|
+
// either for its quads or, through its entity index, for their terms
|
|
1192
|
+
other._factory === _N3DataFactory.default && other._entityIndex._factory === _N3DataFactory.default) {
|
|
1193
|
+
const store = new N3Store({
|
|
1194
|
+
entityIndex: this._entityIndex
|
|
1195
|
+
});
|
|
1196
|
+
for (const quad of other) if (this.has(quad)) store.add(quad);
|
|
1197
|
+
return store;
|
|
1198
|
+
}
|
|
1206
1199
|
return this.filter(quad => other.has(quad));
|
|
1207
1200
|
}
|
|
1208
1201
|
|
|
@@ -1277,8 +1270,7 @@ class N3Store {
|
|
|
1277
1270
|
const store = new N3Store({
|
|
1278
1271
|
entityIndex: this._entityIndex
|
|
1279
1272
|
});
|
|
1280
|
-
store.
|
|
1281
|
-
store._size = this._size;
|
|
1273
|
+
store._addFromIndex(this._graphs);
|
|
1282
1274
|
store.addAll(quads);
|
|
1283
1275
|
return store;
|
|
1284
1276
|
}
|
|
@@ -1543,11 +1535,14 @@ class DatasetCoreAndReadableStream extends _readableStream.Readable {
|
|
|
1543
1535
|
predicates = indexMatch(content.predicates, [predicateId, objectId, subjectId]);
|
|
1544
1536
|
objects = indexMatch(content.objects, [objectId, subjectId, predicateId]);
|
|
1545
1537
|
}
|
|
1546
|
-
if (subjects)
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1538
|
+
if (subjects) {
|
|
1539
|
+
newStore._graphs[graphKey] = {
|
|
1540
|
+
subjects,
|
|
1541
|
+
predicates,
|
|
1542
|
+
objects
|
|
1543
|
+
};
|
|
1544
|
+
newStore._graphCount++;
|
|
1545
|
+
}
|
|
1551
1546
|
}
|
|
1552
1547
|
}
|
|
1553
1548
|
newStore._size = null;
|
package/lib/N3Writer.js
CHANGED
|
@@ -22,15 +22,11 @@ const {
|
|
|
22
22
|
hasOwnProperty
|
|
23
23
|
} = Object.prototype;
|
|
24
24
|
|
|
25
|
-
// Characters that require escaping in
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
// U+0000–U+001F, `"`, `\`, U+007F, U+FFFE, and U+FFFF.
|
|
31
|
-
// A negated class is as fast to test as a shorter class listing characters.
|
|
32
|
-
canonicalEscape = /[^ !#-\[\]-~\u0080-\uFFFD]/,
|
|
33
|
-
canonicalEscapeAll = /[^ !#-\[\]-~\u0080-\uFFFD]/g,
|
|
25
|
+
// Characters that require escaping, as in canonical N-Triples:
|
|
26
|
+
// U+0000–U+001F, `"`, `\`, U+007F, U+FFFE, and U+FFFF.
|
|
27
|
+
// A negated class is as fast to test as a shorter class listing characters.
|
|
28
|
+
const escape = /[^ !#-\[\]-~\u0080-\uFFFD]/,
|
|
29
|
+
escapeAll = /[^ !#-\[\]-~\u0080-\uFFFD]/g,
|
|
34
30
|
escapedCharacters = {
|
|
35
31
|
'\\': '\\\\',
|
|
36
32
|
'"': '\\"',
|
|
@@ -91,7 +87,6 @@ class N3Writer {
|
|
|
91
87
|
this._subject = null;
|
|
92
88
|
if (!/triple|quad/i.test(options.format)) {
|
|
93
89
|
this._lineMode = false;
|
|
94
|
-
this._escape = escape, this._escapeAll = escapeAll, this._characterReplacer = characterReplacer;
|
|
95
90
|
this._graph = DEFAULTGRAPH;
|
|
96
91
|
if (options.version) this._write(`@version "${options.version}".\n`);
|
|
97
92
|
this._prefixIRIs = Object.create(null);
|
|
@@ -105,9 +100,6 @@ class N3Writer {
|
|
|
105
100
|
} else {
|
|
106
101
|
this._lineMode = true;
|
|
107
102
|
this._writeQuad = this._writeQuadLine;
|
|
108
|
-
// N-Triples and N-Quads are written in their canonical form
|
|
109
|
-
this._escape = canonicalEscape, this._escapeAll = canonicalEscapeAll;
|
|
110
|
-
this._characterReplacer = canonicalCharacterReplacer;
|
|
111
103
|
if (options.version) this._write(`VERSION "${options.version}"\n`);
|
|
112
104
|
}
|
|
113
105
|
}
|
|
@@ -207,7 +199,7 @@ class N3Writer {
|
|
|
207
199
|
iri = this._baseIri.toRelative(iri);
|
|
208
200
|
}
|
|
209
201
|
// Escape special characters
|
|
210
|
-
if (
|
|
202
|
+
if (escape.test(iri)) iri = iri.replace(escapeAll, characterReplacer);
|
|
211
203
|
// Try to represent the IRI as prefixed name, unless no prefixes were added
|
|
212
204
|
const prefixMatch = this._hasPrefixes ? (this._prefixRegex || this._createPrefixRegex()).exec(iri) : null;
|
|
213
205
|
return !prefixMatch ? `<${iri}>` : this._prefixIRIs[prefixMatch[1]] + prefixMatch[2];
|
|
@@ -217,7 +209,7 @@ class N3Writer {
|
|
|
217
209
|
_encodeLiteral(literal) {
|
|
218
210
|
// Escape special characters
|
|
219
211
|
let value = literal.value;
|
|
220
|
-
if (
|
|
212
|
+
if (escape.test(value)) value = value.replace(escapeAll, characterReplacer);
|
|
221
213
|
|
|
222
214
|
// Write a language-tagged literal
|
|
223
215
|
const language = literal.language;
|
|
@@ -287,9 +279,7 @@ class N3Writer {
|
|
|
287
279
|
object,
|
|
288
280
|
graph
|
|
289
281
|
}) {
|
|
290
|
-
|
|
291
|
-
const space = this._lineMode ? ' ' : '';
|
|
292
|
-
return `<<(${space}${this._encodeSubject(subject)} ${this._encodePredicate(predicate)} ${this._encodeObject(object)}${(0, _N3Util.isDefaultGraph)(graph) ? '' : ` ${this._encodeIriOrBlank(graph)}`}${space})>>`;
|
|
282
|
+
return `<<( ${this._encodeSubject(subject)} ${this._encodePredicate(predicate)} ${this._encodeObject(object)}${(0, _N3Util.isDefaultGraph)(graph) ? '' : ` ${this._encodeIriOrBlank(graph)}`} )>>`;
|
|
293
283
|
}
|
|
294
284
|
|
|
295
285
|
// ### `_blockedWrite` replaces `_write` after the writer has been closed
|
|
@@ -425,26 +415,7 @@ class N3Writer {
|
|
|
425
415
|
// Replaces a character by its escaped version
|
|
426
416
|
exports.default = N3Writer;
|
|
427
417
|
function characterReplacer(character) {
|
|
428
|
-
//
|
|
429
|
-
let result = escapedCharacters[character];
|
|
430
|
-
if (result === undefined) {
|
|
431
|
-
// Replace a single character with its 4-bit unicode escape sequence
|
|
432
|
-
if (character.length === 1) {
|
|
433
|
-
result = character.charCodeAt(0).toString(16);
|
|
434
|
-
result = '\\u0000'.substr(0, 6 - result.length) + result;
|
|
435
|
-
}
|
|
436
|
-
// Replace a surrogate pair with its 8-bit unicode escape sequence
|
|
437
|
-
else {
|
|
438
|
-
result = ((character.charCodeAt(0) - 0xD800) * 0x400 + character.charCodeAt(1) + 0x2400).toString(16);
|
|
439
|
-
result = '\\U00000000'.substr(0, 10 - result.length) + result;
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
return result;
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
// Replaces a character by its canonical N-Triples escape:
|
|
446
|
-
// a short escape where one exists, and an upper-case `\uXXXX` escape otherwise
|
|
447
|
-
function canonicalCharacterReplacer(character) {
|
|
418
|
+
// Use a short escape where one exists, and an upper-case `\uXXXX` escape otherwise
|
|
448
419
|
let result = escapedCharacters[character];
|
|
449
420
|
if (result === undefined) {
|
|
450
421
|
result = character.charCodeAt(0).toString(16).toUpperCase();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n3",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.9",
|
|
4
4
|
"description": "Lightning fast, asynchronous, streaming Turtle / N3 / RDF library.",
|
|
5
5
|
"author": "Ruben Verborgh <ruben.verborgh@gmail.com>",
|
|
6
6
|
"keywords": [
|
|
@@ -131,7 +131,12 @@
|
|
|
131
131
|
}
|
|
132
132
|
],
|
|
133
133
|
"@semantic-release/npm",
|
|
134
|
-
|
|
134
|
+
[
|
|
135
|
+
"@semantic-release/github",
|
|
136
|
+
{
|
|
137
|
+
"successCommentCondition": "<% return !branch.prerelease; %>"
|
|
138
|
+
}
|
|
139
|
+
]
|
|
135
140
|
]
|
|
136
141
|
},
|
|
137
142
|
"publishConfig": {
|
package/src/N3DataFactory.js
CHANGED
|
@@ -41,9 +41,10 @@ export class Term {
|
|
|
41
41
|
// ### Returns whether this object represents the same term as the other
|
|
42
42
|
equals(other) {
|
|
43
43
|
// If both terms were created by this library,
|
|
44
|
-
// equality can be computed through ids
|
|
44
|
+
// equality can be computed through ids of the same term type,
|
|
45
|
+
// since IRIs such as `?x` have the same id as other terms
|
|
45
46
|
if (other instanceof Term)
|
|
46
|
-
return this.id === other.id;
|
|
47
|
+
return this.id === other.id && this.termType === other.termType;
|
|
47
48
|
// Otherwise, compare term type and value
|
|
48
49
|
return !!other && this.termType === other.termType &&
|
|
49
50
|
this.value === other.value;
|