n3 1.26.0 → 2.0.0-beta.2

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/IRIs.js CHANGED
@@ -20,7 +20,9 @@ var _default = exports.default = {
20
20
  nil: `${RDF}nil`,
21
21
  first: `${RDF}first`,
22
22
  rest: `${RDF}rest`,
23
- langString: `${RDF}langString`
23
+ langString: `${RDF}langString`,
24
+ dirLangString: `${RDF}dirLangString`,
25
+ reifies: `${RDF}reifies`
24
26
  },
25
27
  owl: {
26
28
  sameAs: 'http://www.w3.org/2002/07/owl#sameAs'
@@ -30,7 +32,6 @@ var _default = exports.default = {
30
32
  forAll: `${SWAP}reify#forAll`
31
33
  },
32
34
  log: {
33
- implies: `${SWAP}log#implies`,
34
- isImpliedBy: `${SWAP}log#isImpliedBy`
35
+ implies: `${SWAP}log#implies`
35
36
  }
36
37
  };
@@ -99,8 +99,17 @@ class Literal extends Term {
99
99
  // Find the last quotation mark (e.g., '"abc"@en-us')
100
100
  const id = this.id;
101
101
  let atPos = id.lastIndexOf('"') + 1;
102
+ const dirPos = id.lastIndexOf('--');
102
103
  // If "@" it follows, return the remaining substring; empty otherwise
103
- return atPos < id.length && id[atPos++] === '@' ? id.substr(atPos).toLowerCase() : '';
104
+ return atPos < id.length && id[atPos++] === '@' ? (dirPos > atPos ? id.substr(0, dirPos) : id).substr(atPos).toLowerCase() : '';
105
+ }
106
+
107
+ // ### The direction of this literal
108
+ get direction() {
109
+ // Find the last double dash (e.g., '"abc"@en-us--ltr')
110
+ const id = this.id;
111
+ const atPos = id.lastIndexOf('--') + 2;
112
+ return atPos > 1 && atPos < id.length ? id.substr(atPos).toLowerCase() : '';
104
113
  }
105
114
 
106
115
  // ### The datatype IRI of this literal
@@ -116,8 +125,8 @@ class Literal extends Term {
116
125
  const char = dtPos < id.length ? id[dtPos] : '';
117
126
  // If "^" it follows, return the remaining substring
118
127
  return char === '^' ? id.substr(dtPos + 2) :
119
- // If "@" follows, return rdf:langString; xsd:string otherwise
120
- char !== '@' ? xsd.string : rdf.langString;
128
+ // If "@" follows, return rdf:langString or rdf:dirLangString; xsd:string otherwise
129
+ char !== '@' ? xsd.string : id.indexOf('--', dtPos) > 0 ? rdf.dirLangString : rdf.langString;
121
130
  }
122
131
 
123
132
  // ### Returns whether this object represents the same term as the other
@@ -126,13 +135,14 @@ class Literal extends Term {
126
135
  // equality can be computed through ids
127
136
  if (other instanceof Literal) return this.id === other.id;
128
137
  // Otherwise, compare term type, value, language, and datatype
129
- return !!other && !!other.datatype && this.termType === other.termType && this.value === other.value && this.language === other.language && this.datatype.value === other.datatype.value;
138
+ return !!other && !!other.datatype && this.termType === other.termType && this.value === other.value && this.language === other.language && (this.direction === other.direction || this.direction === '' && !other.direction) && this.datatype.value === other.datatype.value;
130
139
  }
131
140
  toJSON() {
132
141
  return {
133
142
  termType: this.termType,
134
143
  value: this.value,
135
144
  language: this.language,
145
+ direction: this.direction,
136
146
  datatype: {
137
147
  termType: 'NamedNode',
138
148
  value: this.datatypeString
@@ -225,7 +235,20 @@ function termFromId(id, factory, nested) {
225
235
  if (id[id.length - 1] === '"') return factory.literal(id.substr(1, id.length - 2));
226
236
  // Literal with datatype or language
227
237
  const endPos = id.lastIndexOf('"', id.length - 1);
228
- return factory.literal(id.substr(1, endPos - 1), id[endPos + 1] === '@' ? id.substr(endPos + 2) : factory.namedNode(id.substr(endPos + 3)));
238
+ let languageOrDatatype;
239
+ if (id[endPos + 1] === '@') {
240
+ languageOrDatatype = id.substr(endPos + 2);
241
+ const dashDashIndex = languageOrDatatype.lastIndexOf('--');
242
+ if (dashDashIndex > 0 && dashDashIndex < languageOrDatatype.length) {
243
+ languageOrDatatype = {
244
+ language: languageOrDatatype.substr(0, dashDashIndex),
245
+ direction: languageOrDatatype.substr(dashDashIndex + 2)
246
+ };
247
+ }
248
+ } else {
249
+ languageOrDatatype = factory.namedNode(id.substr(endPos + 3));
250
+ }
251
+ return factory.literal(id.substr(1, endPos - 1), languageOrDatatype);
229
252
  case '[':
230
253
  id = JSON.parse(id);
231
254
  break;
@@ -258,7 +281,7 @@ function termToId(term, nested) {
258
281
  case 'DefaultGraph':
259
282
  return '';
260
283
  case 'Literal':
261
- return `"${term.value}"${term.language ? `@${term.language}` : term.datatype && term.datatype.value !== xsd.string ? `^^${term.datatype.value}` : ''}`;
284
+ return `"${term.value}"${term.language ? `@${term.language}${term.direction ? `--${term.direction}` : ''}` : term.datatype && term.datatype.value !== xsd.string ? `^^${term.datatype.value}` : ''}`;
262
285
  case 'Quad':
263
286
  const res = [termToId(term.subject, true), termToId(term.predicate, true), termToId(term.object, true)];
264
287
  if (term.graph && term.graph.termType !== 'DefaultGraph') {
@@ -339,6 +362,11 @@ function literal(value, languageOrDataType) {
339
362
  // Create a language-tagged string
340
363
  if (typeof languageOrDataType === 'string') return new Literal(`"${value}"@${languageOrDataType.toLowerCase()}`);
341
364
 
365
+ // Create a language-tagged string with base direction
366
+ if (languageOrDataType !== undefined && !('termType' in languageOrDataType)) {
367
+ return new Literal(`"${value}"@${languageOrDataType.language.toLowerCase()}--${languageOrDataType.direction.toLowerCase()}`);
368
+ }
369
+
342
370
  // Automatically determine datatype for booleans and numbers
343
371
  let datatype = languageOrDataType ? languageOrDataType.value : '';
344
372
  if (datatype === '') {
package/lib/N3Lexer.js CHANGED
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
  var _buffer = require("buffer");
8
+ var _queueMicrotask = _interopRequireDefault(require("queue-microtask"));
8
9
  var _IRIs = _interopRequireDefault(require("./IRIs"));
9
10
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
11
  // **N3Lexer** tokenizes N3 documents.
@@ -50,6 +51,7 @@ const lineModeRegExps = {
50
51
  _unescapedIri: true,
51
52
  _simpleQuotedString: true,
52
53
  _langcode: true,
54
+ _dircode: true,
53
55
  _blank: true,
54
56
  _newline: true,
55
57
  _comment: true,
@@ -67,15 +69,16 @@ class N3Lexer {
67
69
  this._unescapedIri = /^<([^\x00-\x20<>\\"\{\}\|\^\`]*)>[ \t]*/; // IRI without escape sequences; no unescaping
68
70
  this._simpleQuotedString = /^"([^"\\\r\n]*)"(?=[^"])/; // string without escape sequences
69
71
  this._simpleApostropheString = /^'([^'\\\r\n]*)'(?=[^'])/;
70
- this._langcode = /^@([a-z]+(?:-[a-z0-9]+)*)(?=[^a-z0-9\-])/i;
72
+ this._langcode = /^@([a-z]+(?:-[a-z0-9]+)*)(?=[^a-z0-9])/i;
73
+ this._dircode = /^--(ltr)|(rtl)/;
71
74
  this._prefix = /^((?:[A-Za-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])(?:\.?[\-0-9A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])*)?:(?=[#\s<])/;
72
75
  this._prefixed = /^((?:[A-Za-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])(?:\.?[\-0-9A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])*)?:((?:(?:[0-:A-Z_a-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff]|%[0-9a-fA-F]{2}|\\[!#-\/;=?\-@_~])(?:(?:[\.\-0-:A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff]|%[0-9a-fA-F]{2}|\\[!#-\/;=?\-@_~])*(?:[\-0-:A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff]|%[0-9a-fA-F]{2}|\\[!#-\/;=?\-@_~]))?)?)(?:[ \t]+|(?=\.?[,;!\^\s#()\[\]\{\}"'<>]))/;
73
76
  this._variable = /^\?(?:(?:[A-Z_a-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])(?:[\-0-:A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])*)(?=[.,;!\^\s#()\[\]\{\}"'<>])/;
74
77
  this._blank = /^_:((?:[0-9A-Z_a-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])(?:\.?[\-0-9A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])*)(?:[ \t]+|(?=\.?[,;:\s#()\[\]\{\}"'<>]))/;
75
78
  this._number = /^[\-+]?(?:(\d+\.\d*|\.?\d+)[eE][\-+]?|\d*(\.)?)\d+(?=\.?[,;:\s#()\[\]\{\}"'<>])/;
76
79
  this._boolean = /^(?:true|false)(?=[.,;\s#()\[\]\{\}"'<>])/;
77
- this._keyword = /^@[a-z]+(?=[\s#<:])/i;
78
- this._sparqlKeyword = /^(?:PREFIX|BASE|GRAPH)(?=[\s#<])/i;
80
+ this._atKeyword = /^@[a-z]+(?=[\s#<:])/i;
81
+ this._keyword = /^(?:PREFIX|BASE|VERSION|GRAPH)(?=[\s#<])/i;
79
82
  this._shortPredicates = /^a(?=[\s#()\[\]\{\}"'<>])/;
80
83
  this._newline = /^[ \t]*(?:#[^\n\r]*)?(?:\r\n|\n|\r)[ \t]*/;
81
84
  this._comment = /#([^\n\r]*)/;
@@ -83,9 +86,6 @@ class N3Lexer {
83
86
  this._endOfFile = /^(?:#[^\n\r]*)?$/;
84
87
  options = options || {};
85
88
 
86
- // Whether the log:isImpliedBy predicate is supported
87
- this._isImpliedBy = options.isImpliedBy;
88
-
89
89
  // In line mode (N-Triples or N-Quads), only simple features may be parsed
90
90
  if (this._lineMode = !!options.lineMode) {
91
91
  this._n3Mode = false;
@@ -178,15 +178,15 @@ class N3Lexer {
178
178
  if (value === null || illegalIriChars.test(value)) return reportSyntaxError(this);
179
179
  type = 'IRI';
180
180
  }
181
- // Try to find a nested triple
182
- else if (input.length > 1 && input[1] === '<') type = '<<', matchLength = 2;
181
+ // Try to find a triple term
182
+ else if (input.length > 2 && input[1] === '<' && input[2] === '(') type = '<<(', matchLength = 3;
183
+ // Try to find a reified triple
184
+ else if (!this._lineMode && input.length > (inputFinished ? 1 : 2) && input[1] === '<') type = '<<', matchLength = 2;
183
185
  // Try to find a backwards implication arrow
184
- else if (this._n3Mode && input.length > 1 && input[1] === '=') {
185
- matchLength = 2;
186
- if (this._isImpliedBy) type = 'abbreviation', value = '<';else type = 'inverse', value = '>';
187
- }
186
+ else if (this._n3Mode && input.length > 1 && input[1] === '=') type = 'inverse', matchLength = 2, value = '>';
188
187
  break;
189
188
  case '>':
189
+ // Try to find a reified triple
190
190
  if (input.length > 1 && input[1] === '>') type = '>>', matchLength = 2;
191
191
  break;
192
192
  case '_':
@@ -235,9 +235,9 @@ class N3Lexer {
235
235
  break;
236
236
  case '@':
237
237
  // Try to find a language code
238
- if (this._previousMarker === 'literal' && (match = this._langcode.exec(input))) type = 'langcode', value = match[1];
238
+ if (this._previousMarker === 'literal' && (match = this._langcode.exec(input)) && match[1] !== 'version') type = 'langcode', value = match[1];
239
239
  // Try to find a keyword
240
- else if (match = this._keyword.exec(input)) type = match[0];
240
+ else if (match = this._atKeyword.exec(input)) type = match[0];
241
241
  break;
242
242
  case '.':
243
243
  // Try to find a dot as punctuation
@@ -260,6 +260,12 @@ class N3Lexer {
260
260
  case '9':
261
261
  case '+':
262
262
  case '-':
263
+ if (input[1] === '-') {
264
+ // Try to find a direction code
265
+ if (this._previousMarker === 'langcode' && (match = this._dircode.exec(input))) type = 'dircode', matchLength = 2, value = match[1] || match[2], matchLength = value.length + 2;
266
+ break;
267
+ }
268
+
263
269
  // Try to find a number. Since it can contain (but not end with) a dot,
264
270
  // we always need a non-dot character before deciding it is a number.
265
271
  // Therefore, try inserting a space if we're at the end of the input.
@@ -274,8 +280,10 @@ class N3Lexer {
274
280
  case 'P':
275
281
  case 'G':
276
282
  case 'g':
283
+ case 'V':
284
+ case 'v':
277
285
  // Try to find a SPARQL-style keyword
278
- if (match = this._sparqlKeyword.exec(input)) type = match[0].toUpperCase();else inconclusive = true;
286
+ if (match = this._keyword.exec(input)) type = match[0].toUpperCase();else inconclusive = true;
279
287
  break;
280
288
  case 'f':
281
289
  case 't':
@@ -295,13 +303,23 @@ class N3Lexer {
295
303
  break;
296
304
  case '!':
297
305
  if (!this._n3Mode) break;
306
+ case ')':
307
+ if (!inputFinished && (input.length === 1 || input.length === 2 && input[1] === '>')) {
308
+ // Don't consume yet, as it *could* become a triple term end.
309
+ break;
310
+ }
311
+ // Try to find a triple term
312
+ if (input.length > 2 && input[1] === '>' && input[2] === '>') {
313
+ type = ')>>', matchLength = 3;
314
+ break;
315
+ }
298
316
  case ',':
299
317
  case ';':
300
318
  case '[':
301
319
  case ']':
302
320
  case '(':
303
- case ')':
304
321
  case '}':
322
+ case '~':
305
323
  if (!this._lineMode) {
306
324
  matchLength = 1;
307
325
  type = firstChar;
@@ -474,7 +492,7 @@ class N3Lexer {
474
492
  if (typeof input === 'string') {
475
493
  this._input = this._readStartingBom(input);
476
494
  // If a callback was passed, asynchronously call it
477
- if (typeof callback === 'function') queueMicrotask(() => this._tokenizeToEnd(callback, true));
495
+ if (typeof callback === 'function') (0, _queueMicrotask.default)(() => this._tokenizeToEnd(callback, true));
478
496
  // If no callback was passed, tokenize synchronously and return
479
497
  else {
480
498
  const tokens = [];