n3 1.17.0 → 1.17.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/N3Lexer.js CHANGED
@@ -4,18 +4,16 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
-
8
7
  var _IRIs = _interopRequireDefault(require("./IRIs"));
9
-
10
8
  var _queueMicrotask = _interopRequireDefault(require("queue-microtask"));
11
-
12
9
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
-
14
10
  // **N3Lexer** tokenizes N3 documents.
11
+
15
12
  const {
16
13
  xsd
17
- } = _IRIs.default; // Regular expression and replacement string to escape N3 strings
14
+ } = _IRIs.default;
18
15
 
16
+ // Regular expression and replacement string to escape N3 strings
19
17
  const escapeSequence = /\\u([a-fA-F0-9]{4})|\\U([a-fA-F0-9]{8})|\\([^])/g;
20
18
  const escapeReplacements = {
21
19
  '\\': '\\',
@@ -58,18 +56,16 @@ const lineModeRegExps = {
58
56
  _whitespace: true,
59
57
  _endOfFile: true
60
58
  };
61
- const invalidRegExp = /$0^/; // ## Constructor
59
+ const invalidRegExp = /$0^/;
62
60
 
61
+ // ## Constructor
63
62
  class N3Lexer {
64
63
  constructor(options) {
65
64
  // ## Regular expressions
66
65
  // It's slightly faster to have these as properties than as in-scope variables
67
66
  this._iri = /^<((?:[^ <>{}\\]|\\[uU])+)>[ \t]*/; // IRI with escape sequences; needs sanity check after unescaping
68
-
69
67
  this._unescapedIri = /^<([^\x00-\x20<>\\"\{\}\|\^\`]*)>[ \t]*/; // IRI without escape sequences; no unescaping
70
-
71
68
  this._simpleQuotedString = /^"([^"\\\r\n]*)"(?=[^"])/; // string without escape sequences
72
-
73
69
  this._simpleApostropheString = /^'([^'\\\r\n]*)'(?=[^'])/;
74
70
  this._langcode = /^@([a-z]+(?:-[a-z0-9]+)*)(?=[^a-z0-9\-])/i;
75
71
  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<])/;
@@ -85,48 +81,48 @@ class N3Lexer {
85
81
  this._comment = /#([^\n\r]*)/;
86
82
  this._whitespace = /^[ \t]+/;
87
83
  this._endOfFile = /^(?:#[^\n\r]*)?$/;
88
- options = options || {}; // In line mode (N-Triples or N-Quads), only simple features may be parsed
84
+ options = options || {};
89
85
 
86
+ // In line mode (N-Triples or N-Quads), only simple features may be parsed
90
87
  if (this._lineMode = !!options.lineMode) {
91
- this._n3Mode = false; // Don't tokenize special literals
92
-
88
+ this._n3Mode = false;
89
+ // Don't tokenize special literals
93
90
  for (const key in this) {
94
91
  if (!(key in lineModeRegExps) && this[key] instanceof RegExp) this[key] = invalidRegExp;
95
92
  }
96
- } // When not in line mode, enable N3 functionality by default
93
+ }
94
+ // When not in line mode, enable N3 functionality by default
97
95
  else {
98
96
  this._n3Mode = options.n3 !== false;
99
- } // Don't output comment tokens by default
100
-
101
-
102
- this._comments = !!options.comments; // Cache the last tested closing position of long literals
103
-
97
+ }
98
+ // Don't output comment tokens by default
99
+ this._comments = !!options.comments;
100
+ // Cache the last tested closing position of long literals
104
101
  this._literalClosingPos = 0;
105
- } // ## Private methods
106
- // ### `_tokenizeToEnd` tokenizes as for as possible, emitting tokens through the callback
102
+ }
107
103
 
104
+ // ## Private methods
108
105
 
106
+ // ### `_tokenizeToEnd` tokenizes as for as possible, emitting tokens through the callback
109
107
  _tokenizeToEnd(callback, inputFinished) {
110
108
  // Continue parsing as far as possible; the loop will return eventually
111
109
  let input = this._input;
112
110
  let currentLineLength = input.length;
113
-
114
111
  while (true) {
115
112
  // Count and skip whitespace lines
116
113
  let whiteSpaceMatch, comment;
117
-
118
114
  while (whiteSpaceMatch = this._newline.exec(input)) {
119
115
  // Try to find a comment
120
- if (this._comments && (comment = this._comment.exec(whiteSpaceMatch[0]))) emitToken('comment', comment[1], '', this._line, whiteSpaceMatch[0].length); // Advance the input
121
-
116
+ if (this._comments && (comment = this._comment.exec(whiteSpaceMatch[0]))) emitToken('comment', comment[1], '', this._line, whiteSpaceMatch[0].length);
117
+ // Advance the input
122
118
  input = input.substr(whiteSpaceMatch[0].length, input.length);
123
119
  currentLineLength = input.length;
124
120
  this._line++;
125
- } // Skip whitespace on current line
126
-
127
-
128
- if (!whiteSpaceMatch && (whiteSpaceMatch = this._whitespace.exec(input))) input = input.substr(whiteSpaceMatch[0].length, input.length); // Stop for now if we're at the end
121
+ }
122
+ // Skip whitespace on current line
123
+ if (!whiteSpaceMatch && (whiteSpaceMatch = this._whitespace.exec(input))) input = input.substr(whiteSpaceMatch[0].length, input.length);
129
124
 
125
+ // Stop for now if we're at the end
130
126
  if (this._endOfFile.test(input)) {
131
127
  // If the input is finished, emit EOF
132
128
  if (inputFinished) {
@@ -135,70 +131,68 @@ class N3Lexer {
135
131
  input = null;
136
132
  emitToken('eof', '', '', this._line, 0);
137
133
  }
138
-
139
134
  return this._input = input;
140
- } // Look for specific token types based on the first character
141
-
135
+ }
142
136
 
137
+ // Look for specific token types based on the first character
143
138
  const line = this._line,
144
- firstChar = input[0];
139
+ firstChar = input[0];
145
140
  let type = '',
146
- value = '',
147
- prefix = '',
148
- match = null,
149
- matchLength = 0,
150
- inconclusive = false;
151
-
141
+ value = '',
142
+ prefix = '',
143
+ match = null,
144
+ matchLength = 0,
145
+ inconclusive = false;
152
146
  switch (firstChar) {
153
147
  case '^':
154
148
  // We need at least 3 tokens lookahead to distinguish ^^<IRI> and ^^pre:fixed
155
- if (input.length < 3) break; // Try to match a type
149
+ if (input.length < 3) break;
150
+ // Try to match a type
156
151
  else if (input[1] === '^') {
157
- this._previousMarker = '^^'; // Move to type IRI or prefixed name
158
-
152
+ this._previousMarker = '^^';
153
+ // Move to type IRI or prefixed name
159
154
  input = input.substr(2);
160
-
161
155
  if (input[0] !== '<') {
162
156
  inconclusive = true;
163
157
  break;
164
158
  }
165
- } // If no type, it must be a path expression
159
+ }
160
+ // If no type, it must be a path expression
166
161
  else {
167
162
  if (this._n3Mode) {
168
163
  matchLength = 1;
169
164
  type = '^';
170
165
  }
171
-
172
166
  break;
173
167
  }
174
168
  // Fall through in case the type is an IRI
175
-
176
169
  case '<':
177
170
  // Try to find a full IRI without escape sequences
178
- if (match = this._unescapedIri.exec(input)) type = 'IRI', value = match[1]; // Try to find a full IRI with escape sequences
171
+ if (match = this._unescapedIri.exec(input)) type = 'IRI', value = match[1];
172
+ // Try to find a full IRI with escape sequences
179
173
  else if (match = this._iri.exec(input)) {
180
174
  value = this._unescape(match[1]);
181
175
  if (value === null || illegalIriChars.test(value)) return reportSyntaxError(this);
182
176
  type = 'IRI';
183
- } // Try to find a nested triple
184
- else if (input.length > 1 && input[1] === '<') type = '<<', matchLength = 2; // Try to find a backwards implication arrow
177
+ }
178
+ // Try to find a nested triple
179
+ else if (input.length > 1 && input[1] === '<') type = '<<', matchLength = 2;
180
+ // Try to find a backwards implication arrow
185
181
  else if (this._n3Mode && input.length > 1 && input[1] === '=') type = 'inverse', matchLength = 2, value = '>';
186
182
  break;
187
-
188
183
  case '>':
189
184
  if (input.length > 1 && input[1] === '>') type = '>>', matchLength = 2;
190
185
  break;
191
-
192
186
  case '_':
193
187
  // Try to find a blank node. Since it can contain (but not end with) a dot,
194
188
  // we always need a non-dot character before deciding it is a blank node.
195
189
  // Therefore, try inserting a space if we're at the end of the input.
196
190
  if ((match = this._blank.exec(input)) || inputFinished && (match = this._blank.exec(`${input} `))) type = 'blank', prefix = '_', value = match[1];
197
191
  break;
198
-
199
192
  case '"':
200
193
  // Try to find a literal without escape sequences
201
- if (match = this._simpleQuotedString.exec(input)) value = match[1]; // Try to find a literal wrapped in three pairs of quotes
194
+ if (match = this._simpleQuotedString.exec(input)) value = match[1];
195
+ // Try to find a literal wrapped in three pairs of quotes
202
196
  else {
203
197
  ({
204
198
  value,
@@ -206,18 +200,16 @@ class N3Lexer {
206
200
  } = this._parseLiteral(input));
207
201
  if (value === null) return reportSyntaxError(this);
208
202
  }
209
-
210
203
  if (match !== null || matchLength !== 0) {
211
204
  type = 'literal';
212
205
  this._literalClosingPos = 0;
213
206
  }
214
-
215
207
  break;
216
-
217
208
  case "'":
218
209
  if (!this._lineMode) {
219
210
  // Try to find a literal without escape sequences
220
- if (match = this._simpleApostropheString.exec(input)) value = match[1]; // Try to find a literal wrapped in three pairs of quotes
211
+ if (match = this._simpleApostropheString.exec(input)) value = match[1];
212
+ // Try to find a literal wrapped in three pairs of quotes
221
213
  else {
222
214
  ({
223
215
  value,
@@ -225,26 +217,22 @@ class N3Lexer {
225
217
  } = this._parseLiteral(input));
226
218
  if (value === null) return reportSyntaxError(this);
227
219
  }
228
-
229
220
  if (match !== null || matchLength !== 0) {
230
221
  type = 'literal';
231
222
  this._literalClosingPos = 0;
232
223
  }
233
224
  }
234
-
235
225
  break;
236
-
237
226
  case '?':
238
227
  // Try to find a variable
239
228
  if (this._n3Mode && (match = this._variable.exec(input))) type = 'var', value = match[0];
240
229
  break;
241
-
242
230
  case '@':
243
231
  // Try to find a language code
244
- if (this._previousMarker === 'literal' && (match = this._langcode.exec(input))) type = 'langcode', value = match[1]; // Try to find a keyword
232
+ if (this._previousMarker === 'literal' && (match = this._langcode.exec(input))) type = 'langcode', value = match[1];
233
+ // Try to find a keyword
245
234
  else if (match = this._keyword.exec(input)) type = match[0];
246
235
  break;
247
-
248
236
  case '.':
249
237
  // Try to find a dot as punctuation
250
238
  if (input.length === 1 ? inputFinished : input[1] < '0' || input[1] > '9') {
@@ -252,7 +240,6 @@ class N3Lexer {
252
240
  matchLength = 1;
253
241
  break;
254
242
  }
255
-
256
243
  // Fall through to numerical case (could be a decimal dot)
257
244
 
258
245
  case '0':
@@ -274,9 +261,7 @@ class N3Lexer {
274
261
  type = 'literal', value = match[0];
275
262
  prefix = typeof match[1] === 'string' ? xsd.double : typeof match[2] === 'string' ? xsd.decimal : xsd.integer;
276
263
  }
277
-
278
264
  break;
279
-
280
265
  case 'B':
281
266
  case 'b':
282
267
  case 'p':
@@ -286,30 +271,24 @@ class N3Lexer {
286
271
  // Try to find a SPARQL-style keyword
287
272
  if (match = this._sparqlKeyword.exec(input)) type = match[0].toUpperCase();else inconclusive = true;
288
273
  break;
289
-
290
274
  case 'f':
291
275
  case 't':
292
276
  // Try to match a boolean
293
277
  if (match = this._boolean.exec(input)) type = 'literal', value = match[0], prefix = xsd.boolean;else inconclusive = true;
294
278
  break;
295
-
296
279
  case 'a':
297
280
  // Try to find an abbreviated predicate
298
281
  if (match = this._shortPredicates.exec(input)) type = 'abbreviation', value = 'a';else inconclusive = true;
299
282
  break;
300
-
301
283
  case '=':
302
284
  // Try to find an implication arrow or equals sign
303
285
  if (this._n3Mode && input.length > 1) {
304
286
  type = 'abbreviation';
305
287
  if (input[1] !== '>') matchLength = 1, value = '=';else matchLength = 2, value = '>';
306
288
  }
307
-
308
289
  break;
309
-
310
290
  case '!':
311
291
  if (!this._n3Mode) break;
312
-
313
292
  case ',':
314
293
  case ';':
315
294
  case '[':
@@ -321,71 +300,66 @@ class N3Lexer {
321
300
  matchLength = 1;
322
301
  type = firstChar;
323
302
  }
324
-
325
303
  break;
326
-
327
304
  case '{':
328
305
  // We need at least 2 tokens lookahead to distinguish "{|" and "{ "
329
306
  if (!this._lineMode && input.length >= 2) {
330
307
  // Try to find a quoted triple annotation start
331
308
  if (input[1] === '|') type = '{|', matchLength = 2;else type = firstChar, matchLength = 1;
332
309
  }
333
-
334
310
  break;
335
-
336
311
  case '|':
337
312
  // We need 2 tokens lookahead to parse "|}"
338
313
  // Try to find a quoted triple annotation end
339
314
  if (input.length >= 2 && input[1] === '}') type = '|}', matchLength = 2;
340
315
  break;
341
-
342
316
  default:
343
317
  inconclusive = true;
344
- } // Some first characters do not allow an immediate decision, so inspect more
345
-
318
+ }
346
319
 
320
+ // Some first characters do not allow an immediate decision, so inspect more
347
321
  if (inconclusive) {
348
322
  // Try to find a prefix
349
- if ((this._previousMarker === '@prefix' || this._previousMarker === 'PREFIX') && (match = this._prefix.exec(input))) type = 'prefix', value = match[1] || ''; // Try to find a prefixed name. Since it can contain (but not end with) a dot,
323
+ if ((this._previousMarker === '@prefix' || this._previousMarker === 'PREFIX') && (match = this._prefix.exec(input))) type = 'prefix', value = match[1] || '';
324
+ // Try to find a prefixed name. Since it can contain (but not end with) a dot,
350
325
  // we always need a non-dot character before deciding it is a prefixed name.
351
326
  // Therefore, try inserting a space if we're at the end of the input.
352
327
  else if ((match = this._prefixed.exec(input)) || inputFinished && (match = this._prefixed.exec(`${input} `))) type = 'prefixed', prefix = match[1] || '', value = this._unescape(match[2]);
353
- } // A type token is special: it can only be emitted after an IRI or prefixed name is read
354
-
328
+ }
355
329
 
330
+ // A type token is special: it can only be emitted after an IRI or prefixed name is read
356
331
  if (this._previousMarker === '^^') {
357
332
  switch (type) {
358
333
  case 'prefixed':
359
334
  type = 'type';
360
335
  break;
361
-
362
336
  case 'IRI':
363
337
  type = 'typeIRI';
364
338
  break;
365
-
366
339
  default:
367
340
  type = '';
368
341
  }
369
- } // What if nothing of the above was found?
370
-
342
+ }
371
343
 
344
+ // What if nothing of the above was found?
372
345
  if (!type) {
373
346
  // We could be in streaming mode, and then we just wait for more input to arrive.
374
347
  // Otherwise, a syntax error has occurred in the input.
375
348
  // One exception: error on an unaccounted linebreak (= not inside a triple-quoted literal).
376
349
  if (inputFinished || !/^'''|^"""/.test(input) && /\n|\r/.test(input)) return reportSyntaxError(this);else return this._input = input;
377
- } // Emit the parsed token
378
-
350
+ }
379
351
 
352
+ // Emit the parsed token
380
353
  const length = matchLength || match[0].length;
381
354
  const token = emitToken(type, value, prefix, line, length);
382
355
  this.previousToken = token;
383
- this._previousMarker = type; // Advance to next part to tokenize
356
+ this._previousMarker = type;
384
357
 
358
+ // Advance to next part to tokenize
385
359
  input = input.substr(length, input.length);
386
- } // Emits the token through the callback
387
-
360
+ }
388
361
 
362
+ // Emits the token through the callback
389
363
  function emitToken(type, value, prefix, line, length) {
390
364
  const start = input ? currentLineLength - input.length : currentLineLength;
391
365
  const end = start + length;
@@ -399,59 +373,56 @@ class N3Lexer {
399
373
  };
400
374
  callback(null, token);
401
375
  return token;
402
- } // Signals the syntax error through the callback
403
-
404
-
376
+ }
377
+ // Signals the syntax error through the callback
405
378
  function reportSyntaxError(self) {
406
379
  callback(self._syntaxError(/^\S*/.exec(input)[0]));
407
380
  }
408
- } // ### `_unescape` replaces N3 escape codes by their corresponding characters
409
-
381
+ }
410
382
 
383
+ // ### `_unescape` replaces N3 escape codes by their corresponding characters
411
384
  _unescape(item) {
412
385
  let invalid = false;
413
386
  const replaced = item.replace(escapeSequence, (sequence, unicode4, unicode8, escapedChar) => {
414
387
  // 4-digit unicode character
415
- if (typeof unicode4 === 'string') return String.fromCharCode(Number.parseInt(unicode4, 16)); // 8-digit unicode character
416
-
388
+ if (typeof unicode4 === 'string') return String.fromCharCode(Number.parseInt(unicode4, 16));
389
+ // 8-digit unicode character
417
390
  if (typeof unicode8 === 'string') {
418
391
  let charCode = Number.parseInt(unicode8, 16);
419
392
  return charCode <= 0xFFFF ? String.fromCharCode(Number.parseInt(unicode8, 16)) : String.fromCharCode(0xD800 + ((charCode -= 0x10000) >> 10), 0xDC00 + (charCode & 0x3FF));
420
- } // fixed escape sequence
421
-
422
-
423
- if (escapedChar in escapeReplacements) return escapeReplacements[escapedChar]; // invalid escape sequence
424
-
393
+ }
394
+ // fixed escape sequence
395
+ if (escapedChar in escapeReplacements) return escapeReplacements[escapedChar];
396
+ // invalid escape sequence
425
397
  invalid = true;
426
398
  return '';
427
399
  });
428
400
  return invalid ? null : replaced;
429
- } // ### `_parseLiteral` parses a literal into an unescaped value
430
-
401
+ }
431
402
 
403
+ // ### `_parseLiteral` parses a literal into an unescaped value
432
404
  _parseLiteral(input) {
433
405
  // Ensure we have enough lookahead to identify triple-quoted strings
434
406
  if (input.length >= 3) {
435
407
  // Identify the opening quote(s)
436
408
  const opening = input.match(/^(?:"""|"|'''|'|)/)[0];
437
- const openingLength = opening.length; // Find the next candidate closing quotes
409
+ const openingLength = opening.length;
438
410
 
411
+ // Find the next candidate closing quotes
439
412
  let closingPos = Math.max(this._literalClosingPos, openingLength);
440
-
441
413
  while ((closingPos = input.indexOf(opening, closingPos)) > 0) {
442
414
  // Count backslashes right before the closing quotes
443
415
  let backslashCount = 0;
416
+ while (input[closingPos - backslashCount - 1] === '\\') backslashCount++;
444
417
 
445
- while (input[closingPos - backslashCount - 1] === '\\') backslashCount++; // An even number of backslashes (in particular 0)
418
+ // An even number of backslashes (in particular 0)
446
419
  // means these are actual, non-escaped closing quotes
447
-
448
-
449
420
  if (backslashCount % 2 === 0) {
450
421
  // Extract and unescape the value
451
422
  const raw = input.substring(openingLength, closingPos);
452
423
  const lines = raw.split(/\r\n|\r|\n/).length - 1;
453
- const matchLength = closingPos + openingLength; // Only triple-quoted strings can be multi-line
454
-
424
+ const matchLength = closingPos + openingLength;
425
+ // Only triple-quoted strings can be multi-line
455
426
  if (openingLength === 1 && lines !== 0 || openingLength === 3 && this._lineMode) break;
456
427
  this._line += lines;
457
428
  return {
@@ -459,20 +430,17 @@ class N3Lexer {
459
430
  matchLength
460
431
  };
461
432
  }
462
-
463
433
  closingPos++;
464
434
  }
465
-
466
435
  this._literalClosingPos = input.length - openingLength + 1;
467
436
  }
468
-
469
437
  return {
470
438
  value: '',
471
439
  matchLength: 0
472
440
  };
473
- } // ### `_syntaxError` creates a syntax error for the given issue
474
-
441
+ }
475
442
 
443
+ // ### `_syntaxError` creates a syntax error for the given issue
476
444
  _syntaxError(issue) {
477
445
  this._input = null;
478
446
  const err = new Error(`Unexpected "${issue}" on line ${this._line}.`);
@@ -482,65 +450,64 @@ class N3Lexer {
482
450
  previousToken: this.previousToken
483
451
  };
484
452
  return err;
485
- } // ### Strips off any starting UTF BOM mark.
486
-
453
+ }
487
454
 
455
+ // ### Strips off any starting UTF BOM mark.
488
456
  _readStartingBom(input) {
489
457
  return input.startsWith('\ufeff') ? input.substr(1) : input;
490
- } // ## Public methods
491
- // ### `tokenize` starts the transformation of an N3 document into an array of tokens.
492
- // The input can be a string or a stream.
458
+ }
493
459
 
460
+ // ## Public methods
494
461
 
462
+ // ### `tokenize` starts the transformation of an N3 document into an array of tokens.
463
+ // The input can be a string or a stream.
495
464
  tokenize(input, callback) {
496
- this._line = 1; // If the input is a string, continuously emit tokens through the callback until the end
465
+ this._line = 1;
497
466
 
467
+ // If the input is a string, continuously emit tokens through the callback until the end
498
468
  if (typeof input === 'string') {
499
- this._input = this._readStartingBom(input); // If a callback was passed, asynchronously call it
500
-
501
- if (typeof callback === 'function') (0, _queueMicrotask.default)(() => this._tokenizeToEnd(callback, true)); // If no callback was passed, tokenize synchronously and return
469
+ this._input = this._readStartingBom(input);
470
+ // If a callback was passed, asynchronously call it
471
+ if (typeof callback === 'function') (0, _queueMicrotask.default)(() => this._tokenizeToEnd(callback, true));
472
+ // If no callback was passed, tokenize synchronously and return
502
473
  else {
503
474
  const tokens = [];
504
475
  let error;
505
-
506
476
  this._tokenizeToEnd((e, t) => e ? error = e : tokens.push(t), true);
507
-
508
477
  if (error) throw error;
509
478
  return tokens;
510
479
  }
511
- } // Otherwise, the input must be a stream
480
+ }
481
+ // Otherwise, the input must be a stream
512
482
  else {
513
483
  this._pendingBuffer = null;
514
- if (typeof input.setEncoding === 'function') input.setEncoding('utf8'); // Adds the data chunk to the buffer and parses as far as possible
515
-
484
+ if (typeof input.setEncoding === 'function') input.setEncoding('utf8');
485
+ // Adds the data chunk to the buffer and parses as far as possible
516
486
  input.on('data', data => {
517
487
  if (this._input !== null && data.length !== 0) {
518
488
  // Prepend any previous pending writes
519
489
  if (this._pendingBuffer) {
520
490
  data = Buffer.concat([this._pendingBuffer, data]);
521
491
  this._pendingBuffer = null;
522
- } // Hold if the buffer ends in an incomplete unicode sequence
523
-
524
-
492
+ }
493
+ // Hold if the buffer ends in an incomplete unicode sequence
525
494
  if (data[data.length - 1] & 0x80) {
526
495
  this._pendingBuffer = data;
527
- } // Otherwise, tokenize as far as possible
496
+ }
497
+ // Otherwise, tokenize as far as possible
528
498
  else {
529
499
  // Only read a BOM at the start
530
500
  if (typeof this._input === 'undefined') this._input = this._readStartingBom(typeof data === 'string' ? data : data.toString());else this._input += data;
531
-
532
501
  this._tokenizeToEnd(callback, false);
533
502
  }
534
503
  }
535
- }); // Parses until the end
536
-
504
+ });
505
+ // Parses until the end
537
506
  input.on('end', () => {
538
507
  if (typeof this._input === 'string') this._tokenizeToEnd(callback, true);
539
508
  });
540
509
  input.on('error', callback);
541
510
  }
542
511
  }
543
-
544
512
  }
545
-
546
513
  exports.default = N3Lexer;