n3 2.7.9 → 2.7.11

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/N3Lexer.js CHANGED
@@ -12,6 +12,11 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
12
12
  const {
13
13
  xsd
14
14
  } = _IRIs.default;
15
+ const SPACE = 0x20,
16
+ TAB = 0x09,
17
+ LF = 0x0A,
18
+ CR = 0x0D,
19
+ HASH = 0x23;
15
20
 
16
21
  // Regular expression and replacement strings to unescape N3 strings
17
22
  const escapeSequence = /\\u([a-fA-F0-9]{4})|\\U([a-fA-F0-9]{8})|\\([^])/g;
@@ -61,10 +66,8 @@ const lineModeRegExps = {
61
66
  _simpleQuotedString: true,
62
67
  _langcode: true,
63
68
  _blank: true,
64
- _newline: true,
65
- _comment: true,
66
- _whitespace: true,
67
- _endOfFile: true
69
+ _commentLine: true,
70
+ _whitespace: true
68
71
  };
69
72
  const invalidRegExp = /$0^/;
70
73
 
@@ -89,10 +92,8 @@ class N3Lexer {
89
92
  this._n3Verb = /^(?:has|is|of)(?=[\s#()\[\]\{\}"'<>?_+\-0-9])/;
90
93
  this._n3Id = /^id(?=[\s#<])/;
91
94
  this._shortPredicates = /^a(?=[\s#()\[\]\{\}"'<>])/;
92
- this._newline = /^[ \t]*(?:#[^\n\r]*)?(?:\r\n|\n|\r)[ \t]*/;
93
- this._comment = /#([^\n\r]*)/;
95
+ this._commentLine = /^[ \t]*#([^\n\r]*)(?:\r\n|\n|\r)[ \t]*/;
94
96
  this._whitespace = /^[ \t]+/;
95
- this._endOfFile = /^(?:#[^\n\r]*)?$/;
96
97
  options = options || {};
97
98
 
98
99
  // Whether the log:isImpliedBy predicate is supported
@@ -124,25 +125,48 @@ class N3Lexer {
124
125
  let input = this._input;
125
126
  let currentLineLength = input.length;
126
127
  while (true) {
127
- // Count and skip whitespace lines
128
- let whiteSpaceMatch, comment;
129
- while (whiteSpaceMatch = this._newline.exec(input)) {
130
- // Try to find a comment
131
- if (this.comments && (comment = this._comment.exec(whiteSpaceMatch[0]))) emitToken('comment', comment[1], '', this._line, whiteSpaceMatch[0].length);
132
- // Advance the input
133
- input = input.slice(whiteSpaceMatch[0].length);
134
- currentLineLength = input.length;
135
- this._line++;
128
+ // Consume one separator line at a time, including its following indentation.
129
+ while (true) {
130
+ let charCode = input.charCodeAt(0),
131
+ separatorLength = 0;
132
+ if (charCode === SPACE || charCode === TAB) {
133
+ const next = input.charCodeAt(1);
134
+ separatorLength = next === SPACE || next === TAB ? this._whitespace.exec(input)[0].length : 1;
135
+ charCode = input.charCodeAt(separatorLength);
136
+ }
137
+ if (charCode === HASH) {
138
+ const comment = this._commentLine.exec(input);
139
+ if (comment) {
140
+ if (this.comments) emitToken('comment', comment[1], '', this._line, comment[0].length);
141
+ input = input.slice(comment[0].length);
142
+ currentLineLength = input.length;
143
+ this._line++;
144
+ } else {
145
+ // A comment without a line ending stays buffered until EOF.
146
+ input = input.slice(separatorLength);
147
+ if (!inputFinished) return this._input = input;
148
+ if (this.comments) emitToken('comment', input.slice(1), '', this._line, input.length);
149
+ input = '';
150
+ break;
151
+ }
152
+ } else if (charCode === LF || charCode === CR) {
153
+ separatorLength += charCode === CR && input.charCodeAt(separatorLength + 1) === LF ? 2 : 1;
154
+ // Indentation is part of the same separator match as the newline.
155
+ const next = input.charCodeAt(separatorLength);
156
+ if (next === SPACE || next === TAB) {
157
+ const following = input.charCodeAt(separatorLength + 1);
158
+ separatorLength += following === SPACE || following === TAB ? this._whitespace.exec(input.slice(separatorLength))[0].length : 1;
159
+ }
160
+ input = input.slice(separatorLength);
161
+ currentLineLength = input.length;
162
+ this._line++;
163
+ } else {
164
+ if (separatorLength !== 0) input = input.slice(separatorLength);
165
+ break;
166
+ }
136
167
  }
137
- // Skip whitespace on current line
138
- if (!whiteSpaceMatch && (whiteSpaceMatch = this._whitespace.exec(input))) input = input.slice(whiteSpaceMatch[0].length);
139
-
140
- // Stop for now if we're at the end
141
- if (this._endOfFile.test(input)) {
142
- // If the input is finished, emit EOF
168
+ if (input.length === 0) {
143
169
  if (inputFinished) {
144
- // Try to find a final comment
145
- if (this.comments && (comment = this._comment.exec(input))) emitToken('comment', comment[1], '', this._line, input.length);
146
170
  input = null;
147
171
  emitToken('eof', '', '', this._line, 0);
148
172
  }
@@ -313,11 +337,11 @@ class N3Lexer {
313
337
  case 'f':
314
338
  case 't':
315
339
  // Try to match a boolean
316
- if (match = this._boolean.exec(input)) type = 'literal', value = match[0], prefix = xsd.boolean;else inconclusive = true;
340
+ if (this._boolean.test(input)) type = 'literal', value = firstChar === 't' ? 'true' : 'false', prefix = xsd.boolean, matchLength = value.length;else inconclusive = true;
317
341
  break;
318
342
  case 'a':
319
343
  // Try to find an abbreviated predicate
320
- if (match = this._shortPredicates.exec(input)) type = 'abbreviation', value = 'a';else inconclusive = true;
344
+ if (this._shortPredicates.test(input)) type = 'abbreviation', value = 'a', matchLength = 1;else inconclusive = true;
321
345
  break;
322
346
  case 'h':
323
347
  case 'o':
@@ -326,7 +350,7 @@ class N3Lexer {
326
350
  break;
327
351
  case 'i':
328
352
  // Try to find an IRI property list identifier or N3 verb keyword
329
- if (this._n3Mode && (match = this._n3Id.exec(input))) type = 'id';else if (this._n3Mode && (match = this._matchN3Verb(input, inputFinished))) type = match[0];else inconclusive = true;
353
+ if (this._n3Mode && this._n3Id.test(input)) type = 'id', matchLength = 2;else if (this._n3Mode && (match = this._matchN3Verb(input, inputFinished))) type = match[0];else inconclusive = true;
330
354
  break;
331
355
  case '=':
332
356
  // Try to find an implication arrow or equals sign
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n3",
3
- "version": "2.7.9",
3
+ "version": "2.7.11",
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/N3Lexer.js CHANGED
@@ -3,6 +3,7 @@ import { Buffer } from 'buffer';
3
3
  import namespaces from './IRIs';
4
4
 
5
5
  const { xsd } = namespaces;
6
+ const SPACE = 0x20, TAB = 0x09, LF = 0x0A, CR = 0x0D, HASH = 0x23;
6
7
 
7
8
  // Regular expression and replacement strings to unescape N3 strings
8
9
  const escapeSequence = /\\u([a-fA-F0-9]{4})|\\U([a-fA-F0-9]{8})|\\([^])/g;
@@ -30,10 +31,8 @@ const lineModeRegExps = {
30
31
  _simpleQuotedString: true,
31
32
  _langcode: true,
32
33
  _blank: true,
33
- _newline: true,
34
- _comment: true,
34
+ _commentLine: true,
35
35
  _whitespace: true,
36
- _endOfFile: true,
37
36
  };
38
37
  const invalidRegExp = /$0^/;
39
38
 
@@ -58,10 +57,8 @@ export default class N3Lexer {
58
57
  this._n3Verb = /^(?:has|is|of)(?=[\s#()\[\]\{\}"'<>?_+\-0-9])/;
59
58
  this._n3Id = /^id(?=[\s#<])/;
60
59
  this._shortPredicates = /^a(?=[\s#()\[\]\{\}"'<>])/;
61
- this._newline = /^[ \t]*(?:#[^\n\r]*)?(?:\r\n|\n|\r)[ \t]*/;
62
- this._comment = /#([^\n\r]*)/;
60
+ this._commentLine = /^[ \t]*#([^\n\r]*)(?:\r\n|\n|\r)[ \t]*/;
63
61
  this._whitespace = /^[ \t]+/;
64
- this._endOfFile = /^(?:#[^\n\r]*)?$/;
65
62
  options = options || {};
66
63
 
67
64
  // Whether the log:isImpliedBy predicate is supported
@@ -94,28 +91,56 @@ export default class N3Lexer {
94
91
  let input = this._input;
95
92
  let currentLineLength = input.length;
96
93
  while (true) {
97
- // Count and skip whitespace lines
98
- let whiteSpaceMatch, comment;
99
- while (whiteSpaceMatch = this._newline.exec(input)) {
100
- // Try to find a comment
101
- if (this.comments && (comment = this._comment.exec(whiteSpaceMatch[0])))
102
- emitToken('comment', comment[1], '', this._line, whiteSpaceMatch[0].length);
103
- // Advance the input
104
- input = input.slice(whiteSpaceMatch[0].length);
105
- currentLineLength = input.length;
106
- this._line++;
94
+ // Consume one separator line at a time, including its following indentation.
95
+ while (true) {
96
+ let charCode = input.charCodeAt(0), separatorLength = 0;
97
+ if (charCode === SPACE || charCode === TAB) {
98
+ const next = input.charCodeAt(1);
99
+ separatorLength = next === SPACE || next === TAB ?
100
+ this._whitespace.exec(input)[0].length : 1;
101
+ charCode = input.charCodeAt(separatorLength);
102
+ }
103
+ if (charCode === HASH) {
104
+ const comment = this._commentLine.exec(input);
105
+ if (comment) {
106
+ if (this.comments)
107
+ emitToken('comment', comment[1], '', this._line, comment[0].length);
108
+ input = input.slice(comment[0].length);
109
+ currentLineLength = input.length;
110
+ this._line++;
111
+ }
112
+ else {
113
+ // A comment without a line ending stays buffered until EOF.
114
+ input = input.slice(separatorLength);
115
+ if (!inputFinished)
116
+ return this._input = input;
117
+ if (this.comments)
118
+ emitToken('comment', input.slice(1), '', this._line, input.length);
119
+ input = '';
120
+ break;
121
+ }
122
+ }
123
+ else if (charCode === LF || charCode === CR) {
124
+ separatorLength += charCode === CR && input.charCodeAt(separatorLength + 1) === LF ? 2 : 1;
125
+ // Indentation is part of the same separator match as the newline.
126
+ const next = input.charCodeAt(separatorLength);
127
+ if (next === SPACE || next === TAB) {
128
+ const following = input.charCodeAt(separatorLength + 1);
129
+ separatorLength += following === SPACE || following === TAB ?
130
+ this._whitespace.exec(input.slice(separatorLength))[0].length : 1;
131
+ }
132
+ input = input.slice(separatorLength);
133
+ currentLineLength = input.length;
134
+ this._line++;
135
+ }
136
+ else {
137
+ if (separatorLength !== 0)
138
+ input = input.slice(separatorLength);
139
+ break;
140
+ }
107
141
  }
108
- // Skip whitespace on current line
109
- if (!whiteSpaceMatch && (whiteSpaceMatch = this._whitespace.exec(input)))
110
- input = input.slice(whiteSpaceMatch[0].length);
111
-
112
- // Stop for now if we're at the end
113
- if (this._endOfFile.test(input)) {
114
- // If the input is finished, emit EOF
142
+ if (input.length === 0) {
115
143
  if (inputFinished) {
116
- // Try to find a final comment
117
- if (this.comments && (comment = this._comment.exec(input)))
118
- emitToken('comment', comment[1], '', this._line, input.length);
119
144
  input = null;
120
145
  emitToken('eof', '', '', this._line, 0);
121
146
  }
@@ -311,16 +336,16 @@ export default class N3Lexer {
311
336
  case 'f':
312
337
  case 't':
313
338
  // Try to match a boolean
314
- if (match = this._boolean.exec(input))
315
- type = 'literal', value = match[0], prefix = xsd.boolean;
339
+ if (this._boolean.test(input))
340
+ type = 'literal', value = firstChar === 't' ? 'true' : 'false', prefix = xsd.boolean, matchLength = value.length;
316
341
  else
317
342
  inconclusive = true;
318
343
  break;
319
344
 
320
345
  case 'a':
321
346
  // Try to find an abbreviated predicate
322
- if (match = this._shortPredicates.exec(input))
323
- type = 'abbreviation', value = 'a';
347
+ if (this._shortPredicates.test(input))
348
+ type = 'abbreviation', value = 'a', matchLength = 1;
324
349
  else
325
350
  inconclusive = true;
326
351
  break;
@@ -336,8 +361,8 @@ export default class N3Lexer {
336
361
 
337
362
  case 'i':
338
363
  // Try to find an IRI property list identifier or N3 verb keyword
339
- if (this._n3Mode && (match = this._n3Id.exec(input)))
340
- type = 'id';
364
+ if (this._n3Mode && this._n3Id.test(input))
365
+ type = 'id', matchLength = 2;
341
366
  else if (this._n3Mode && (match = this._matchN3Verb(input, inputFinished)))
342
367
  type = match[0];
343
368
  else