n3 2.11.3 → 2.11.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/browser/n3.esm.min.js +7 -7
- package/browser/n3.min.js +7 -7
- package/lib/N3Lexer.js +11 -0
- package/lib/N3Writer.js +27 -4
- package/package.json +1 -1
- package/src/N3Lexer.js +14 -0
- package/src/N3Writer.js +30 -7
package/lib/N3Lexer.js
CHANGED
|
@@ -89,6 +89,11 @@ function execAtEnd(regExp, input, pos) {
|
|
|
89
89
|
return regExp.exec(`${input.slice(pos)} `);
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
// Whitespace or the start of a comment
|
|
93
|
+
function isSeparatorCode(code) {
|
|
94
|
+
return code === SPACE || code === TAB || code === LF || code === CR || code === HASH;
|
|
95
|
+
}
|
|
96
|
+
|
|
92
97
|
// ## Constructor
|
|
93
98
|
class N3Lexer {
|
|
94
99
|
constructor(options) {
|
|
@@ -194,6 +199,8 @@ class N3Lexer {
|
|
|
194
199
|
}
|
|
195
200
|
}
|
|
196
201
|
if (pos >= input.length) {
|
|
202
|
+
// A datatype marker needs a type
|
|
203
|
+
if (inputFinished && this._previousMarker === '^^') return reportSyntaxError(this, input, pos);
|
|
197
204
|
this._linePosition = currentLineLength;
|
|
198
205
|
if (inputFinished) {
|
|
199
206
|
emitToken('eof', '', '', this._line, currentLineLength, 0);
|
|
@@ -215,6 +222,8 @@ class N3Lexer {
|
|
|
215
222
|
inconclusive = false;
|
|
216
223
|
switch (firstChar) {
|
|
217
224
|
case '^':
|
|
225
|
+
// A datatype marker separated from its type cannot be followed by another marker
|
|
226
|
+
if (this._previousMarker === '^^') return reportSyntaxError(this, input, pos);
|
|
218
227
|
// We need at least 3 tokens lookahead to distinguish ^^<IRI> and ^^pre:fixed
|
|
219
228
|
if (input.length - pos < 3) break;
|
|
220
229
|
// Try to match a type
|
|
@@ -223,6 +232,8 @@ class N3Lexer {
|
|
|
223
232
|
// Move to type IRI or prefixed name
|
|
224
233
|
pos += 2;
|
|
225
234
|
if (input[pos] !== '<') {
|
|
235
|
+
// Whitespace and comments may separate the marker from the type
|
|
236
|
+
if (isSeparatorCode(input.charCodeAt(pos))) continue; // eslint-disable-line no-continue
|
|
226
237
|
inconclusive = true;
|
|
227
238
|
break;
|
|
228
239
|
}
|
package/lib/N3Writer.js
CHANGED
|
@@ -19,9 +19,15 @@ const {
|
|
|
19
19
|
xsd
|
|
20
20
|
} = _IRIs.default;
|
|
21
21
|
|
|
22
|
-
// Characters in
|
|
22
|
+
// Characters that require escaping in Turtle, TriG, and N3,
|
|
23
|
+
// where characters outside the Basic Multilingual Plane are escaped as well
|
|
23
24
|
const escape = /["\\\t\n\r\b\f\u0000-\u0019\ud800-\udbff]/,
|
|
24
25
|
escapeAll = /["\\\t\n\r\b\f\u0000-\u0019]|[\ud800-\udbff][\udc00-\udfff]/g,
|
|
26
|
+
// Characters that require escaping in canonical N-Triples and N-Quads:
|
|
27
|
+
// U+0000–U+001F, `"`, `\`, U+007F, U+FFFE, and U+FFFF.
|
|
28
|
+
// A negated class is as fast to test as a shorter class listing characters.
|
|
29
|
+
canonicalEscape = /[^ !#-\[\]-~\u0080-\uFFFD]/,
|
|
30
|
+
canonicalEscapeAll = /[^ !#-\[\]-~\u0080-\uFFFD]/g,
|
|
25
31
|
escapedCharacters = {
|
|
26
32
|
'\\': '\\\\',
|
|
27
33
|
'"': '\\"',
|
|
@@ -75,6 +81,7 @@ class N3Writer {
|
|
|
75
81
|
this._subject = null;
|
|
76
82
|
if (!/triple|quad/i.test(options.format)) {
|
|
77
83
|
this._lineMode = false;
|
|
84
|
+
this._escape = escape, this._escapeAll = escapeAll, this._characterReplacer = characterReplacer;
|
|
78
85
|
this._graph = DEFAULTGRAPH;
|
|
79
86
|
this._prefixIRIs = Object.create(null);
|
|
80
87
|
// Escaped prefix IRIs and names for the prefix matcher, computed once per prefix
|
|
@@ -87,6 +94,9 @@ class N3Writer {
|
|
|
87
94
|
} else {
|
|
88
95
|
this._lineMode = true;
|
|
89
96
|
this._writeQuad = this._writeQuadLine;
|
|
97
|
+
// N-Triples and N-Quads are written in their canonical form
|
|
98
|
+
this._escape = canonicalEscape, this._escapeAll = canonicalEscapeAll;
|
|
99
|
+
this._characterReplacer = canonicalCharacterReplacer;
|
|
90
100
|
}
|
|
91
101
|
}
|
|
92
102
|
|
|
@@ -176,7 +186,7 @@ class N3Writer {
|
|
|
176
186
|
iri = this._baseIri.toRelative(iri);
|
|
177
187
|
}
|
|
178
188
|
// Escape special characters
|
|
179
|
-
if (
|
|
189
|
+
if (this._escape.test(iri)) iri = iri.replace(this._escapeAll, this._characterReplacer);
|
|
180
190
|
// Try to represent the IRI as prefixed name, unless no prefixes were added
|
|
181
191
|
const prefixMatch = this._hasPrefixes ? this._prefixRegex.exec(iri) : null;
|
|
182
192
|
return !prefixMatch ? `<${iri}>` : !prefixMatch[1] ? iri : this._prefixIRIs[prefixMatch[1]] + prefixMatch[2];
|
|
@@ -186,7 +196,7 @@ class N3Writer {
|
|
|
186
196
|
_encodeLiteral(literal) {
|
|
187
197
|
// Escape special characters
|
|
188
198
|
let value = literal.value;
|
|
189
|
-
if (
|
|
199
|
+
if (this._escape.test(value)) value = value.replace(this._escapeAll, this._characterReplacer);
|
|
190
200
|
|
|
191
201
|
// Write a language-tagged literal
|
|
192
202
|
const language = literal.language;
|
|
@@ -256,7 +266,9 @@ class N3Writer {
|
|
|
256
266
|
object,
|
|
257
267
|
graph
|
|
258
268
|
}) {
|
|
259
|
-
|
|
269
|
+
// Canonical N-Triples and N-Quads put spaces inside the delimiters
|
|
270
|
+
const space = this._lineMode ? ' ' : '';
|
|
271
|
+
return `<<(${space}${this._encodeSubject(subject)} ${this._encodePredicate(predicate)} ${this._encodeObject(object)}${(0, _N3Util.isDefaultGraph)(graph) ? '' : ` ${this._encodeIriOrBlank(graph)}`}${space})>>`;
|
|
260
272
|
}
|
|
261
273
|
|
|
262
274
|
// ### `_blockedWrite` replaces `_write` after the writer has been closed
|
|
@@ -412,4 +424,15 @@ function characterReplacer(character) {
|
|
|
412
424
|
}
|
|
413
425
|
}
|
|
414
426
|
return result;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Replaces a character by its canonical N-Triples escape:
|
|
430
|
+
// a short escape where one exists, and an upper-case `\uXXXX` escape otherwise
|
|
431
|
+
function canonicalCharacterReplacer(character) {
|
|
432
|
+
let result = escapedCharacters[character];
|
|
433
|
+
if (result === undefined) {
|
|
434
|
+
result = character.charCodeAt(0).toString(16).toUpperCase();
|
|
435
|
+
result = '\\u0000'.substr(0, 6 - result.length) + result;
|
|
436
|
+
}
|
|
437
|
+
return result;
|
|
415
438
|
}
|
package/package.json
CHANGED
package/src/N3Lexer.js
CHANGED
|
@@ -54,6 +54,11 @@ function execAtEnd(regExp, input, pos) {
|
|
|
54
54
|
return regExp.exec(`${input.slice(pos)} `);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
// Whitespace or the start of a comment
|
|
58
|
+
function isSeparatorCode(code) {
|
|
59
|
+
return code === SPACE || code === TAB || code === LF || code === CR || code === HASH;
|
|
60
|
+
}
|
|
61
|
+
|
|
57
62
|
// ## Constructor
|
|
58
63
|
export default class N3Lexer {
|
|
59
64
|
constructor(options) {
|
|
@@ -170,6 +175,9 @@ export default class N3Lexer {
|
|
|
170
175
|
}
|
|
171
176
|
}
|
|
172
177
|
if (pos >= input.length) {
|
|
178
|
+
// A datatype marker needs a type
|
|
179
|
+
if (inputFinished && this._previousMarker === '^^')
|
|
180
|
+
return reportSyntaxError(this, input, pos);
|
|
173
181
|
this._linePosition = currentLineLength;
|
|
174
182
|
if (inputFinished) {
|
|
175
183
|
emitToken('eof', '', '', this._line, currentLineLength, 0);
|
|
@@ -185,6 +193,9 @@ export default class N3Lexer {
|
|
|
185
193
|
finalLineLength = 0, inconclusive = false;
|
|
186
194
|
switch (firstChar) {
|
|
187
195
|
case '^':
|
|
196
|
+
// A datatype marker separated from its type cannot be followed by another marker
|
|
197
|
+
if (this._previousMarker === '^^')
|
|
198
|
+
return reportSyntaxError(this, input, pos);
|
|
188
199
|
// We need at least 3 tokens lookahead to distinguish ^^<IRI> and ^^pre:fixed
|
|
189
200
|
if (input.length - pos < 3)
|
|
190
201
|
break;
|
|
@@ -194,6 +205,9 @@ export default class N3Lexer {
|
|
|
194
205
|
// Move to type IRI or prefixed name
|
|
195
206
|
pos += 2;
|
|
196
207
|
if (input[pos] !== '<') {
|
|
208
|
+
// Whitespace and comments may separate the marker from the type
|
|
209
|
+
if (isSeparatorCode(input.charCodeAt(pos)))
|
|
210
|
+
continue; // eslint-disable-line no-continue
|
|
197
211
|
inconclusive = true;
|
|
198
212
|
break;
|
|
199
213
|
}
|
package/src/N3Writer.js
CHANGED
|
@@ -9,9 +9,15 @@ const DEFAULTGRAPH = N3DataFactory.defaultGraph();
|
|
|
9
9
|
|
|
10
10
|
const { rdf, xsd } = namespaces;
|
|
11
11
|
|
|
12
|
-
// Characters in
|
|
12
|
+
// Characters that require escaping in Turtle, TriG, and N3,
|
|
13
|
+
// where characters outside the Basic Multilingual Plane are escaped as well
|
|
13
14
|
const escape = /["\\\t\n\r\b\f\u0000-\u0019\ud800-\udbff]/,
|
|
14
15
|
escapeAll = /["\\\t\n\r\b\f\u0000-\u0019]|[\ud800-\udbff][\udc00-\udfff]/g,
|
|
16
|
+
// Characters that require escaping in canonical N-Triples and N-Quads:
|
|
17
|
+
// U+0000–U+001F, `"`, `\`, U+007F, U+FFFE, and U+FFFF.
|
|
18
|
+
// A negated class is as fast to test as a shorter class listing characters.
|
|
19
|
+
canonicalEscape = /[^ !#-\[\]-~\u0080-\uFFFD]/,
|
|
20
|
+
canonicalEscapeAll = /[^ !#-\[\]-~\u0080-\uFFFD]/g,
|
|
15
21
|
escapedCharacters = {
|
|
16
22
|
'\\': '\\\\', '"': '\\"', '\t': '\\t',
|
|
17
23
|
'\n': '\\n', '\r': '\\r', '\b': '\\b', '\f': '\\f',
|
|
@@ -57,6 +63,7 @@ export default class N3Writer {
|
|
|
57
63
|
this._subject = null;
|
|
58
64
|
if (!(/triple|quad/i).test(options.format)) {
|
|
59
65
|
this._lineMode = false;
|
|
66
|
+
this._escape = escape, this._escapeAll = escapeAll, this._characterReplacer = characterReplacer;
|
|
60
67
|
this._graph = DEFAULTGRAPH;
|
|
61
68
|
this._prefixIRIs = Object.create(null);
|
|
62
69
|
// Escaped prefix IRIs and names for the prefix matcher, computed once per prefix
|
|
@@ -71,6 +78,9 @@ export default class N3Writer {
|
|
|
71
78
|
else {
|
|
72
79
|
this._lineMode = true;
|
|
73
80
|
this._writeQuad = this._writeQuadLine;
|
|
81
|
+
// N-Triples and N-Quads are written in their canonical form
|
|
82
|
+
this._escape = canonicalEscape, this._escapeAll = canonicalEscapeAll;
|
|
83
|
+
this._characterReplacer = canonicalCharacterReplacer;
|
|
74
84
|
}
|
|
75
85
|
}
|
|
76
86
|
|
|
@@ -176,8 +186,8 @@ export default class N3Writer {
|
|
|
176
186
|
iri = this._baseIri.toRelative(iri);
|
|
177
187
|
}
|
|
178
188
|
// Escape special characters
|
|
179
|
-
if (
|
|
180
|
-
iri = iri.replace(
|
|
189
|
+
if (this._escape.test(iri))
|
|
190
|
+
iri = iri.replace(this._escapeAll, this._characterReplacer);
|
|
181
191
|
// Try to represent the IRI as prefixed name, unless no prefixes were added
|
|
182
192
|
const prefixMatch = this._hasPrefixes ? this._prefixRegex.exec(iri) : null;
|
|
183
193
|
return !prefixMatch ? `<${iri}>` :
|
|
@@ -188,8 +198,8 @@ export default class N3Writer {
|
|
|
188
198
|
_encodeLiteral(literal) {
|
|
189
199
|
// Escape special characters
|
|
190
200
|
let value = literal.value;
|
|
191
|
-
if (
|
|
192
|
-
value = value.replace(
|
|
201
|
+
if (this._escape.test(value))
|
|
202
|
+
value = value.replace(this._escapeAll, this._characterReplacer);
|
|
193
203
|
|
|
194
204
|
// Write a language-tagged literal
|
|
195
205
|
const language = literal.language;
|
|
@@ -260,11 +270,13 @@ export default class N3Writer {
|
|
|
260
270
|
|
|
261
271
|
// ### `_encodeQuad` encodes an RDF-star quad
|
|
262
272
|
_encodeQuad({ subject, predicate, object, graph }) {
|
|
263
|
-
|
|
273
|
+
// Canonical N-Triples and N-Quads put spaces inside the delimiters
|
|
274
|
+
const space = this._lineMode ? ' ' : '';
|
|
275
|
+
return `<<(${space}${
|
|
264
276
|
this._encodeSubject(subject)} ${
|
|
265
277
|
this._encodePredicate(predicate)} ${
|
|
266
278
|
this._encodeObject(object)}${
|
|
267
|
-
isDefaultGraph(graph) ? '' : ` ${this._encodeIriOrBlank(graph)}`})>>`;
|
|
279
|
+
isDefaultGraph(graph) ? '' : ` ${this._encodeIriOrBlank(graph)}`}${space})>>`;
|
|
268
280
|
}
|
|
269
281
|
|
|
270
282
|
// ### `_blockedWrite` replaces `_write` after the writer has been closed
|
|
@@ -428,3 +440,14 @@ function characterReplacer(character) {
|
|
|
428
440
|
}
|
|
429
441
|
return result;
|
|
430
442
|
}
|
|
443
|
+
|
|
444
|
+
// Replaces a character by its canonical N-Triples escape:
|
|
445
|
+
// a short escape where one exists, and an upper-case `\uXXXX` escape otherwise
|
|
446
|
+
function canonicalCharacterReplacer(character) {
|
|
447
|
+
let result = escapedCharacters[character];
|
|
448
|
+
if (result === undefined) {
|
|
449
|
+
result = character.charCodeAt(0).toString(16).toUpperCase();
|
|
450
|
+
result = '\\u0000'.substr(0, 6 - result.length) + result;
|
|
451
|
+
}
|
|
452
|
+
return result;
|
|
453
|
+
}
|