n3 2.7.8 → 2.7.10

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
  }
@@ -498,9 +522,11 @@ class N3Lexer {
498
522
  _parseLiteral(input) {
499
523
  // Ensure we have enough lookahead to identify triple-quoted strings
500
524
  if (input.length >= 3) {
501
- // Identify the opening quote(s)
502
- const opening = input.match(/^(?:"""|"|'''|'|)/)[0];
503
- const openingLength = opening.length;
525
+ // The caller has already identified a single or double quote.
526
+ const quote = input[0];
527
+ const openingLength = input[1] === quote && input[2] === quote ? 3 : 1;
528
+ let opening = quote;
529
+ if (openingLength === 3) opening = quote === '"' ? '"""' : "'''";
504
530
 
505
531
  // Find the next candidate closing quotes
506
532
  let closingPos = Math.max(this._literalClosingPos, openingLength);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n3",
3
- "version": "2.7.8",
3
+ "version": "2.7.10",
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
  }
@@ -524,9 +549,12 @@ export default class N3Lexer {
524
549
  _parseLiteral(input) {
525
550
  // Ensure we have enough lookahead to identify triple-quoted strings
526
551
  if (input.length >= 3) {
527
- // Identify the opening quote(s)
528
- const opening = input.match(/^(?:"""|"|'''|'|)/)[0];
529
- const openingLength = opening.length;
552
+ // The caller has already identified a single or double quote.
553
+ const quote = input[0];
554
+ const openingLength = input[1] === quote && input[2] === quote ? 3 : 1;
555
+ let opening = quote;
556
+ if (openingLength === 3)
557
+ opening = quote === '"' ? '"""' : "'''";
530
558
 
531
559
  // Find the next candidate closing quotes
532
560
  let closingPos = Math.max(this._literalClosingPos, openingLength);