@cjser/parse5 8.0.1-cjser.2 → 8.1.0-cjser.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/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/parser/index.d.ts +12 -7
- package/dist/parser/index.js +50 -21
- package/dist/tokenizer/index.d.ts +34 -7
- package/dist/tokenizer/index.js +263 -67
- package/dist/tokenizer/preprocessor.d.ts +3 -0
- package/dist/tokenizer/preprocessor.js +14 -5
- package/dist/tree-adapters/interface.d.ts +17 -0
- package/dist-cjser/index.cjs +312 -104
- package/package.json +9 -5
package/dist/tokenizer/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Preprocessor } from './preprocessor.js';
|
|
2
2
|
import { CODE_POINTS as $, SEQUENCES as $$, REPLACEMENT_CHARACTER, isSurrogate, isUndefinedCodePoint, isControlCodePoint, } from '../common/unicode.js';
|
|
3
3
|
import { TokenType, getTokenAttr, } from '../common/token.js';
|
|
4
|
-
import {
|
|
4
|
+
import { HtmlEntityDecoder, DecodingMode } from '@cjser/entities/decode';
|
|
5
5
|
import { ERR } from '../common/error-codes.js';
|
|
6
6
|
import { TAG_ID, getTagID } from '../common/html.js';
|
|
7
7
|
//States
|
|
@@ -113,7 +113,7 @@ function toAsciiLower(cp) {
|
|
|
113
113
|
return cp + 32;
|
|
114
114
|
}
|
|
115
115
|
function isWhitespace(cp) {
|
|
116
|
-
return cp === $.SPACE || cp === $.LINE_FEED || cp === $.TABULATION || cp === $.FORM_FEED;
|
|
116
|
+
return (cp === $.SPACE || cp === $.LINE_FEED || cp === $.TABULATION || cp === $.FORM_FEED || cp === $.CARRIAGE_RETURN);
|
|
117
117
|
}
|
|
118
118
|
function isScriptDataDoubleEscapeSequenceEnd(cp) {
|
|
119
119
|
return isWhitespace(cp) || cp === $.SOLIDUS || cp === $.GREATER_THAN_SIGN;
|
|
@@ -160,13 +160,27 @@ export class Tokenizer {
|
|
|
160
160
|
this.currentCharacterToken = null;
|
|
161
161
|
this.currentToken = null;
|
|
162
162
|
this.currentAttr = { name: '', value: '' };
|
|
163
|
+
this.currentAttrLocation = null;
|
|
164
|
+
/**
|
|
165
|
+
* `[start, end)` of `preprocessor.html` still to be appended to the attribute value, comment data or character
|
|
166
|
+
* token being built (`_flushRun`): input that is used as is is appended as one slice, not a code point at a time.
|
|
167
|
+
*/
|
|
168
|
+
this.runStart = 0;
|
|
169
|
+
this.runEnd = 0;
|
|
163
170
|
this.preprocessor = new Preprocessor(handler);
|
|
164
171
|
this.currentLocation = this.getCurrentLocation(-1);
|
|
165
|
-
this.entityDecoder = new
|
|
172
|
+
this.entityDecoder = new HtmlEntityDecoder((cp, consumed) => {
|
|
166
173
|
// Note: Set `pos` _before_ flushing, as flushing might drop
|
|
167
174
|
// the current chunk and invalidate `entityStartPos`.
|
|
168
175
|
this.preprocessor.pos = this.entityStartPos + consumed - 1;
|
|
169
|
-
this.
|
|
176
|
+
if (!this._isCharacterReferenceInAttribute()) {
|
|
177
|
+
this._ensureCharacterToken(isWhitespace(cp)
|
|
178
|
+
? TokenType.WHITESPACE_CHARACTER
|
|
179
|
+
: cp === $.NULL
|
|
180
|
+
? TokenType.NULL_CHARACTER
|
|
181
|
+
: TokenType.CHARACTER);
|
|
182
|
+
}
|
|
183
|
+
this._extendRunWith(String.fromCodePoint(cp), 0);
|
|
170
184
|
}, handler.onParseError
|
|
171
185
|
? {
|
|
172
186
|
missingSemicolonAfterCharacterReference: () => {
|
|
@@ -216,6 +230,99 @@ export class Tokenizer {
|
|
|
216
230
|
this.inLoop = false;
|
|
217
231
|
}
|
|
218
232
|
//API
|
|
233
|
+
/** Emit buffered character tokens without completing the current token or emitting EOF. */
|
|
234
|
+
flushCharacters() {
|
|
235
|
+
var _a;
|
|
236
|
+
if (this.inLoop) {
|
|
237
|
+
throw new Error('Cannot flush characters from a tokenizer callback');
|
|
238
|
+
}
|
|
239
|
+
const location = (_a = this.currentCharacterToken) === null || _a === void 0 ? void 0 : _a.location;
|
|
240
|
+
let nextLocation = null;
|
|
241
|
+
if (location) {
|
|
242
|
+
nextLocation = this.getCharacterTokenEndLocation(location);
|
|
243
|
+
this.currentLocation = nextLocation;
|
|
244
|
+
}
|
|
245
|
+
this.inLoop = true;
|
|
246
|
+
try {
|
|
247
|
+
this._emitCurrentCharacterToken(nextLocation);
|
|
248
|
+
}
|
|
249
|
+
finally {
|
|
250
|
+
this.inLoop = false;
|
|
251
|
+
}
|
|
252
|
+
this._runParsingLoop();
|
|
253
|
+
}
|
|
254
|
+
getCharacterTokenEndLocation(location) {
|
|
255
|
+
const endOffset = this.getCharacterTokenEndOffset();
|
|
256
|
+
const html = this.preprocessor.html.slice(location.startOffset - this.preprocessor.droppedBufferSize, endOffset - this.preprocessor.droppedBufferSize);
|
|
257
|
+
let line = location.startLine;
|
|
258
|
+
let lastLineBreak = -1;
|
|
259
|
+
for (let i = html.indexOf('\n'); i !== -1; i = html.indexOf('\n', i + 1)) {
|
|
260
|
+
line++;
|
|
261
|
+
lastLineBreak = i;
|
|
262
|
+
}
|
|
263
|
+
for (let i = html.indexOf('\r'); i !== -1; i = html.indexOf('\r', i + 1)) {
|
|
264
|
+
// Count CRLF as one line break by counting its LF only.
|
|
265
|
+
if (html.charCodeAt(i + 1) !== $.LINE_FEED) {
|
|
266
|
+
line++;
|
|
267
|
+
lastLineBreak = Math.max(lastLineBreak, i);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return {
|
|
271
|
+
startLine: line,
|
|
272
|
+
startCol: lastLineBreak === -1 ? location.startCol + html.length : html.length - lastLineBreak,
|
|
273
|
+
startOffset: endOffset,
|
|
274
|
+
endLine: -1,
|
|
275
|
+
endCol: -1,
|
|
276
|
+
endOffset: -1,
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
// Return the input boundary before any unfinished token or buffered delimiter.
|
|
280
|
+
getCharacterTokenEndOffset() {
|
|
281
|
+
var _a;
|
|
282
|
+
const end = this.preprocessor.droppedBufferSize + this.preprocessor.pos + 1;
|
|
283
|
+
const tokenLocation = (_a = this.currentToken) === null || _a === void 0 ? void 0 : _a.location;
|
|
284
|
+
switch (this.state) {
|
|
285
|
+
case State.TAG_OPEN:
|
|
286
|
+
case State.RCDATA_LESS_THAN_SIGN:
|
|
287
|
+
case State.RAWTEXT_LESS_THAN_SIGN:
|
|
288
|
+
case State.SCRIPT_DATA_LESS_THAN_SIGN:
|
|
289
|
+
case State.SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN:
|
|
290
|
+
case State.CDATA_SECTION_BRACKET: {
|
|
291
|
+
return end - 1;
|
|
292
|
+
}
|
|
293
|
+
case State.END_TAG_OPEN:
|
|
294
|
+
case State.MARKUP_DECLARATION_OPEN:
|
|
295
|
+
case State.RCDATA_END_TAG_OPEN:
|
|
296
|
+
case State.RCDATA_END_TAG_NAME:
|
|
297
|
+
case State.RAWTEXT_END_TAG_OPEN:
|
|
298
|
+
case State.RAWTEXT_END_TAG_NAME:
|
|
299
|
+
case State.SCRIPT_DATA_END_TAG_OPEN:
|
|
300
|
+
case State.SCRIPT_DATA_END_TAG_NAME:
|
|
301
|
+
case State.SCRIPT_DATA_ESCAPED_END_TAG_OPEN:
|
|
302
|
+
case State.SCRIPT_DATA_ESCAPED_END_TAG_NAME:
|
|
303
|
+
case State.CDATA_SECTION_END: {
|
|
304
|
+
return end - 2;
|
|
305
|
+
}
|
|
306
|
+
case State.CHARACTER_REFERENCE: {
|
|
307
|
+
return this._isCharacterReferenceInAttribute() && tokenLocation
|
|
308
|
+
? tokenLocation.startOffset
|
|
309
|
+
: this.preprocessor.droppedBufferSize + this.entityStartPos;
|
|
310
|
+
}
|
|
311
|
+
case State.DOCTYPE:
|
|
312
|
+
case State.BEFORE_DOCTYPE_NAME: {
|
|
313
|
+
return this.currentLocation.startOffset;
|
|
314
|
+
}
|
|
315
|
+
default: {
|
|
316
|
+
if (tokenLocation &&
|
|
317
|
+
(this.state === State.TAG_NAME ||
|
|
318
|
+
(this.state >= State.BEFORE_ATTRIBUTE_NAME && this.state <= State.BOGUS_COMMENT) ||
|
|
319
|
+
(this.state >= State.COMMENT_START && this.state <= State.BOGUS_DOCTYPE))) {
|
|
320
|
+
return tokenLocation.startOffset;
|
|
321
|
+
}
|
|
322
|
+
return end;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
219
326
|
pause() {
|
|
220
327
|
this.paused = true;
|
|
221
328
|
}
|
|
@@ -276,6 +383,7 @@ export class Tokenizer {
|
|
|
276
383
|
}
|
|
277
384
|
//Token creation
|
|
278
385
|
_createStartTagToken() {
|
|
386
|
+
this._flushRun('');
|
|
279
387
|
this.currentToken = {
|
|
280
388
|
type: TokenType.START_TAG,
|
|
281
389
|
tagName: '',
|
|
@@ -287,6 +395,7 @@ export class Tokenizer {
|
|
|
287
395
|
};
|
|
288
396
|
}
|
|
289
397
|
_createEndTagToken() {
|
|
398
|
+
this._flushRun('');
|
|
290
399
|
this.currentToken = {
|
|
291
400
|
type: TokenType.END_TAG,
|
|
292
401
|
tagName: '',
|
|
@@ -298,6 +407,7 @@ export class Tokenizer {
|
|
|
298
407
|
};
|
|
299
408
|
}
|
|
300
409
|
_createCommentToken(offset) {
|
|
410
|
+
this._flushRun('');
|
|
301
411
|
this.currentToken = {
|
|
302
412
|
type: TokenType.COMMENT,
|
|
303
413
|
data: '',
|
|
@@ -305,6 +415,7 @@ export class Tokenizer {
|
|
|
305
415
|
};
|
|
306
416
|
}
|
|
307
417
|
_createDoctypeToken(initialName) {
|
|
418
|
+
this._flushRun('');
|
|
308
419
|
this.currentToken = {
|
|
309
420
|
type: TokenType.DOCTYPE,
|
|
310
421
|
name: initialName,
|
|
@@ -314,20 +425,28 @@ export class Tokenizer {
|
|
|
314
425
|
location: this.currentLocation,
|
|
315
426
|
};
|
|
316
427
|
}
|
|
317
|
-
_createCharacterToken(type
|
|
428
|
+
_createCharacterToken(type) {
|
|
429
|
+
if (this.currentLocation) {
|
|
430
|
+
const start = this.currentLocation.startOffset - this.preprocessor.droppedBufferSize;
|
|
431
|
+
// A flushed CR already advanced the line; exclude its ignored LF from the next token's range.
|
|
432
|
+
if (this.preprocessor.html[start] === '\n' && this.preprocessor.html[start - 1] === '\r') {
|
|
433
|
+
this.currentLocation.startOffset++;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
318
436
|
this.currentCharacterToken = {
|
|
319
437
|
type,
|
|
320
|
-
chars,
|
|
438
|
+
chars: '',
|
|
321
439
|
location: this.currentLocation,
|
|
322
440
|
};
|
|
323
441
|
}
|
|
324
442
|
//Tag attributes
|
|
325
443
|
_createAttr(attrNameFirstCh) {
|
|
444
|
+
this._flushRun('');
|
|
326
445
|
this.currentAttr = {
|
|
327
446
|
name: attrNameFirstCh,
|
|
328
447
|
value: '',
|
|
329
448
|
};
|
|
330
|
-
this.
|
|
449
|
+
this.currentAttrLocation = this.getCurrentLocation(0);
|
|
331
450
|
}
|
|
332
451
|
_leaveAttrName() {
|
|
333
452
|
var _a;
|
|
@@ -335,9 +454,9 @@ export class Tokenizer {
|
|
|
335
454
|
const token = this.currentToken;
|
|
336
455
|
if (getTokenAttr(token, this.currentAttr.name) === null) {
|
|
337
456
|
token.attrs.push(this.currentAttr);
|
|
338
|
-
if (token.location && this.
|
|
457
|
+
if (token.location && this.currentAttrLocation) {
|
|
339
458
|
const attrLocations = ((_a = (_b = token.location).attrs) !== null && _a !== void 0 ? _a : (_b.attrs = Object.create(null)));
|
|
340
|
-
attrLocations[this.currentAttr.name] = this.
|
|
459
|
+
attrLocations[this.currentAttr.name] = this.currentAttrLocation;
|
|
341
460
|
// Set end location
|
|
342
461
|
this._leaveAttrValue();
|
|
343
462
|
}
|
|
@@ -347,11 +466,71 @@ export class Tokenizer {
|
|
|
347
466
|
}
|
|
348
467
|
}
|
|
349
468
|
_leaveAttrValue() {
|
|
350
|
-
if (this.
|
|
351
|
-
this.
|
|
352
|
-
this.
|
|
353
|
-
this.
|
|
469
|
+
if (this.currentAttrLocation) {
|
|
470
|
+
this.currentAttrLocation.endLine = this.preprocessor.line;
|
|
471
|
+
this.currentAttrLocation.endCol = this.preprocessor.col;
|
|
472
|
+
this.currentAttrLocation.endOffset = this.preprocessor.offset;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Append the pending run and `text` to the attribute value, comment data or character token being built.
|
|
477
|
+
* The run is a string of its own: V8 copies a slice of fewer than 13 characters but lets a longer one share
|
|
478
|
+
* the input's buffer, which would keep that buffer alive for as long as any attribute value or text cut from
|
|
479
|
+
* it is; a concatenation is flattened into a buffer of its own when it is sliced.
|
|
480
|
+
*/
|
|
481
|
+
_flushRun(text) {
|
|
482
|
+
if (this.runEnd === this.runStart && text.length === 0) {
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
const slice = this.preprocessor.html.slice(this.runStart, this.runEnd);
|
|
486
|
+
const run = (slice.length < 13 ? slice : ` ${slice}`.slice(1)) + text;
|
|
487
|
+
const token = this.currentToken;
|
|
488
|
+
this.runStart = this.runEnd;
|
|
489
|
+
if (token === null) {
|
|
490
|
+
this.currentCharacterToken.chars += run;
|
|
491
|
+
}
|
|
492
|
+
else if (token.type === TokenType.COMMENT) {
|
|
493
|
+
token.data += run;
|
|
494
|
+
}
|
|
495
|
+
else {
|
|
496
|
+
this.currentAttr.value += run;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
/** Extend the pending run by the current input code point, read as `cp`, or flush it and start a new one. */
|
|
500
|
+
_extendRun(cp) {
|
|
501
|
+
const { preprocessor } = this;
|
|
502
|
+
//NOTE: a CR is read as LF, which is then not in the input.
|
|
503
|
+
if (cp === $.LINE_FEED && preprocessor.html.charCodeAt(preprocessor.pos) !== $.LINE_FEED) {
|
|
504
|
+
this._flushRun('\n');
|
|
505
|
+
this.runStart = preprocessor.pos + 1;
|
|
506
|
+
}
|
|
507
|
+
else {
|
|
508
|
+
const start = preprocessor.pos - Number(cp > 65535);
|
|
509
|
+
if (start !== this.runEnd) {
|
|
510
|
+
this._flushRun('');
|
|
511
|
+
this.runStart = start;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
this.runEnd = preprocessor.pos + 1;
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Extend the pending run by `text`, the input that ends `cpOffset` code points after the current one, or flush
|
|
518
|
+
* the run and append `text` where the input differs (a NUL replacement, a decoded reference, a dropped chunk).
|
|
519
|
+
*/
|
|
520
|
+
_extendRunWith(text, cpOffset) {
|
|
521
|
+
const { preprocessor } = this;
|
|
522
|
+
const start = preprocessor.codePointStart + 1 + cpOffset - text.length;
|
|
523
|
+
if (start >= 0 && preprocessor.html.startsWith(text, start)) {
|
|
524
|
+
if (start !== this.runEnd) {
|
|
525
|
+
this._flushRun('');
|
|
526
|
+
this.runStart = start;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
else {
|
|
530
|
+
this._flushRun(text);
|
|
531
|
+
this.runStart = start + text.length;
|
|
354
532
|
}
|
|
533
|
+
this.runEnd = start + text.length;
|
|
355
534
|
}
|
|
356
535
|
//Token emission
|
|
357
536
|
prepareToken(ct) {
|
|
@@ -394,6 +573,7 @@ export class Tokenizer {
|
|
|
394
573
|
this.preprocessor.dropParsedChunk();
|
|
395
574
|
}
|
|
396
575
|
_emitCurrentCharacterToken(nextLocation) {
|
|
576
|
+
this._flushRun('');
|
|
397
577
|
if (this.currentCharacterToken) {
|
|
398
578
|
//NOTE: if we have a pending character token, make it's end location equal to the
|
|
399
579
|
//current token's start location.
|
|
@@ -439,34 +619,48 @@ export class Tokenizer {
|
|
|
439
619
|
//1)TokenType.NULL_CHARACTER - \u0000-character sequences (e.g. '\u0000\u0000\u0000')
|
|
440
620
|
//2)TokenType.WHITESPACE_CHARACTER - any whitespace/new-line character sequences (e.g. '\n \r\t \f')
|
|
441
621
|
//3)TokenType.CHARACTER - any character sequence which don't belong to groups 1 and 2 (e.g. 'abcdef1234@@#$%^')
|
|
442
|
-
|
|
622
|
+
/** Make the current character token one of `type`, emitting the current one if it has another type. */
|
|
623
|
+
_ensureCharacterToken(type) {
|
|
443
624
|
if (this.currentCharacterToken) {
|
|
444
625
|
if (this.currentCharacterToken.type === type) {
|
|
445
|
-
this.currentCharacterToken.chars += ch;
|
|
446
626
|
return;
|
|
447
627
|
}
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
this.preprocessor.dropParsedChunk();
|
|
452
|
-
}
|
|
628
|
+
this.currentLocation = this.getCurrentLocation(0);
|
|
629
|
+
this._emitCurrentCharacterToken(this.currentLocation);
|
|
630
|
+
this.preprocessor.dropParsedChunk();
|
|
453
631
|
}
|
|
454
|
-
this._createCharacterToken(type
|
|
632
|
+
this._createCharacterToken(type);
|
|
455
633
|
}
|
|
634
|
+
/** Emit the current input code point, read as `cp`. */
|
|
456
635
|
_emitCodePoint(cp) {
|
|
457
636
|
const type = isWhitespace(cp)
|
|
458
637
|
? TokenType.WHITESPACE_CHARACTER
|
|
459
638
|
: cp === $.NULL
|
|
460
639
|
? TokenType.NULL_CHARACTER
|
|
461
640
|
: TokenType.CHARACTER;
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
641
|
+
const token = this.currentCharacterToken;
|
|
642
|
+
if (token === null || token.type !== type) {
|
|
643
|
+
this._ensureCharacterToken(type);
|
|
644
|
+
}
|
|
645
|
+
this._extendRun(cp);
|
|
465
646
|
}
|
|
466
647
|
//NOTE: used when we emit characters explicitly.
|
|
467
648
|
//This is always for non-whitespace and non-null characters, which allows us to avoid additional checks.
|
|
468
|
-
|
|
469
|
-
|
|
649
|
+
// Negative `cpOffset` values locate text emitted before the current input character.
|
|
650
|
+
_emitChars(ch, cpOffset = 0) {
|
|
651
|
+
if (this.options.sourceCodeLocationInfo &&
|
|
652
|
+
cpOffset !== 0 &&
|
|
653
|
+
this.currentCharacterToken &&
|
|
654
|
+
this.currentCharacterToken.type !== TokenType.CHARACTER) {
|
|
655
|
+
this.currentLocation = this.getCurrentLocation(ch.length - 1 - cpOffset);
|
|
656
|
+
this._emitCurrentCharacterToken(this.currentLocation);
|
|
657
|
+
// Keep source characters that precede the lookahead available for a subsequent flush.
|
|
658
|
+
this._createCharacterToken(TokenType.CHARACTER);
|
|
659
|
+
}
|
|
660
|
+
else {
|
|
661
|
+
this._ensureCharacterToken(TokenType.CHARACTER);
|
|
662
|
+
}
|
|
663
|
+
this._extendRunWith(ch, cpOffset);
|
|
470
664
|
}
|
|
471
665
|
// Character reference helpers
|
|
472
666
|
_startCharacterReference() {
|
|
@@ -482,7 +676,7 @@ export class Tokenizer {
|
|
|
482
676
|
}
|
|
483
677
|
_flushCodePointConsumedAsCharacterReference(cp) {
|
|
484
678
|
if (this._isCharacterReferenceInAttribute()) {
|
|
485
|
-
this.
|
|
679
|
+
this._extendRun(cp);
|
|
486
680
|
}
|
|
487
681
|
else {
|
|
488
682
|
this._emitCodePoint(cp);
|
|
@@ -930,13 +1124,13 @@ export class Tokenizer {
|
|
|
930
1124
|
}
|
|
931
1125
|
case $.EOF: {
|
|
932
1126
|
this._err(ERR.eofBeforeTagName);
|
|
933
|
-
this._emitChars('<');
|
|
1127
|
+
this._emitChars('<', -1);
|
|
934
1128
|
this._emitEOFToken();
|
|
935
1129
|
break;
|
|
936
1130
|
}
|
|
937
1131
|
default: {
|
|
938
1132
|
this._err(ERR.invalidFirstCharacterOfTagName);
|
|
939
|
-
this._emitChars('<');
|
|
1133
|
+
this._emitChars('<', -1);
|
|
940
1134
|
this.state = State.DATA;
|
|
941
1135
|
this._stateData(cp);
|
|
942
1136
|
}
|
|
@@ -959,7 +1153,7 @@ export class Tokenizer {
|
|
|
959
1153
|
}
|
|
960
1154
|
case $.EOF: {
|
|
961
1155
|
this._err(ERR.eofBeforeTagName);
|
|
962
|
-
this._emitChars('</');
|
|
1156
|
+
this._emitChars('</', -1);
|
|
963
1157
|
this._emitEOFToken();
|
|
964
1158
|
break;
|
|
965
1159
|
}
|
|
@@ -1014,7 +1208,7 @@ export class Tokenizer {
|
|
|
1014
1208
|
this.state = State.RCDATA_END_TAG_OPEN;
|
|
1015
1209
|
}
|
|
1016
1210
|
else {
|
|
1017
|
-
this._emitChars('<');
|
|
1211
|
+
this._emitChars('<', -1);
|
|
1018
1212
|
this.state = State.RCDATA;
|
|
1019
1213
|
this._stateRcdata(cp);
|
|
1020
1214
|
}
|
|
@@ -1027,7 +1221,7 @@ export class Tokenizer {
|
|
|
1027
1221
|
this._stateRcdataEndTagName(cp);
|
|
1028
1222
|
}
|
|
1029
1223
|
else {
|
|
1030
|
-
this._emitChars('</');
|
|
1224
|
+
this._emitChars('</', -1);
|
|
1031
1225
|
this.state = State.RCDATA;
|
|
1032
1226
|
this._stateRcdata(cp);
|
|
1033
1227
|
}
|
|
@@ -1061,6 +1255,8 @@ export class Tokenizer {
|
|
|
1061
1255
|
return false;
|
|
1062
1256
|
}
|
|
1063
1257
|
default: {
|
|
1258
|
+
//NOTE: the end tag is text after all, so no token is being built.
|
|
1259
|
+
this.currentToken = null;
|
|
1064
1260
|
return !this._ensureHibernation();
|
|
1065
1261
|
}
|
|
1066
1262
|
}
|
|
@@ -1069,7 +1265,7 @@ export class Tokenizer {
|
|
|
1069
1265
|
//------------------------------------------------------------------
|
|
1070
1266
|
_stateRcdataEndTagName(cp) {
|
|
1071
1267
|
if (this.handleSpecialEndTag(cp)) {
|
|
1072
|
-
this._emitChars('</');
|
|
1268
|
+
this._emitChars('</', -1);
|
|
1073
1269
|
this.state = State.RCDATA;
|
|
1074
1270
|
this._stateRcdata(cp);
|
|
1075
1271
|
}
|
|
@@ -1081,7 +1277,7 @@ export class Tokenizer {
|
|
|
1081
1277
|
this.state = State.RAWTEXT_END_TAG_OPEN;
|
|
1082
1278
|
}
|
|
1083
1279
|
else {
|
|
1084
|
-
this._emitChars('<');
|
|
1280
|
+
this._emitChars('<', -1);
|
|
1085
1281
|
this.state = State.RAWTEXT;
|
|
1086
1282
|
this._stateRawtext(cp);
|
|
1087
1283
|
}
|
|
@@ -1094,7 +1290,7 @@ export class Tokenizer {
|
|
|
1094
1290
|
this._stateRawtextEndTagName(cp);
|
|
1095
1291
|
}
|
|
1096
1292
|
else {
|
|
1097
|
-
this._emitChars('</');
|
|
1293
|
+
this._emitChars('</', -1);
|
|
1098
1294
|
this.state = State.RAWTEXT;
|
|
1099
1295
|
this._stateRawtext(cp);
|
|
1100
1296
|
}
|
|
@@ -1103,7 +1299,7 @@ export class Tokenizer {
|
|
|
1103
1299
|
//------------------------------------------------------------------
|
|
1104
1300
|
_stateRawtextEndTagName(cp) {
|
|
1105
1301
|
if (this.handleSpecialEndTag(cp)) {
|
|
1106
|
-
this._emitChars('</');
|
|
1302
|
+
this._emitChars('</', -1);
|
|
1107
1303
|
this.state = State.RAWTEXT;
|
|
1108
1304
|
this._stateRawtext(cp);
|
|
1109
1305
|
}
|
|
@@ -1122,7 +1318,7 @@ export class Tokenizer {
|
|
|
1122
1318
|
break;
|
|
1123
1319
|
}
|
|
1124
1320
|
default: {
|
|
1125
|
-
this._emitChars('<');
|
|
1321
|
+
this._emitChars('<', -1);
|
|
1126
1322
|
this.state = State.SCRIPT_DATA;
|
|
1127
1323
|
this._stateScriptData(cp);
|
|
1128
1324
|
}
|
|
@@ -1136,7 +1332,7 @@ export class Tokenizer {
|
|
|
1136
1332
|
this._stateScriptDataEndTagName(cp);
|
|
1137
1333
|
}
|
|
1138
1334
|
else {
|
|
1139
|
-
this._emitChars('</');
|
|
1335
|
+
this._emitChars('</', -1);
|
|
1140
1336
|
this.state = State.SCRIPT_DATA;
|
|
1141
1337
|
this._stateScriptData(cp);
|
|
1142
1338
|
}
|
|
@@ -1145,7 +1341,7 @@ export class Tokenizer {
|
|
|
1145
1341
|
//------------------------------------------------------------------
|
|
1146
1342
|
_stateScriptDataEndTagName(cp) {
|
|
1147
1343
|
if (this.handleSpecialEndTag(cp)) {
|
|
1148
|
-
this._emitChars('</');
|
|
1344
|
+
this._emitChars('</', -1);
|
|
1149
1345
|
this.state = State.SCRIPT_DATA;
|
|
1150
1346
|
this._stateScriptData(cp);
|
|
1151
1347
|
}
|
|
@@ -1273,12 +1469,12 @@ export class Tokenizer {
|
|
|
1273
1469
|
this.state = State.SCRIPT_DATA_ESCAPED_END_TAG_OPEN;
|
|
1274
1470
|
}
|
|
1275
1471
|
else if (isAsciiLetter(cp)) {
|
|
1276
|
-
this._emitChars('<');
|
|
1472
|
+
this._emitChars('<', -1);
|
|
1277
1473
|
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPE_START;
|
|
1278
1474
|
this._stateScriptDataDoubleEscapeStart(cp);
|
|
1279
1475
|
}
|
|
1280
1476
|
else {
|
|
1281
|
-
this._emitChars('<');
|
|
1477
|
+
this._emitChars('<', -1);
|
|
1282
1478
|
this.state = State.SCRIPT_DATA_ESCAPED;
|
|
1283
1479
|
this._stateScriptDataEscaped(cp);
|
|
1284
1480
|
}
|
|
@@ -1291,7 +1487,7 @@ export class Tokenizer {
|
|
|
1291
1487
|
this._stateScriptDataEscapedEndTagName(cp);
|
|
1292
1488
|
}
|
|
1293
1489
|
else {
|
|
1294
|
-
this._emitChars('</');
|
|
1490
|
+
this._emitChars('</', -1);
|
|
1295
1491
|
this.state = State.SCRIPT_DATA_ESCAPED;
|
|
1296
1492
|
this._stateScriptDataEscaped(cp);
|
|
1297
1493
|
}
|
|
@@ -1300,7 +1496,7 @@ export class Tokenizer {
|
|
|
1300
1496
|
//------------------------------------------------------------------
|
|
1301
1497
|
_stateScriptDataEscapedEndTagName(cp) {
|
|
1302
1498
|
if (this.handleSpecialEndTag(cp)) {
|
|
1303
|
-
this._emitChars('</');
|
|
1499
|
+
this._emitChars('</', -1);
|
|
1304
1500
|
this.state = State.SCRIPT_DATA_ESCAPED;
|
|
1305
1501
|
this._stateScriptDataEscaped(cp);
|
|
1306
1502
|
}
|
|
@@ -1594,7 +1790,7 @@ export class Tokenizer {
|
|
|
1594
1790
|
}
|
|
1595
1791
|
case $.NULL: {
|
|
1596
1792
|
this._err(ERR.unexpectedNullCharacter);
|
|
1597
|
-
this.
|
|
1793
|
+
this._extendRunWith(REPLACEMENT_CHARACTER, 0);
|
|
1598
1794
|
break;
|
|
1599
1795
|
}
|
|
1600
1796
|
case $.EOF: {
|
|
@@ -1603,7 +1799,7 @@ export class Tokenizer {
|
|
|
1603
1799
|
break;
|
|
1604
1800
|
}
|
|
1605
1801
|
default: {
|
|
1606
|
-
this.
|
|
1802
|
+
this._extendRun(cp);
|
|
1607
1803
|
}
|
|
1608
1804
|
}
|
|
1609
1805
|
}
|
|
@@ -1621,7 +1817,7 @@ export class Tokenizer {
|
|
|
1621
1817
|
}
|
|
1622
1818
|
case $.NULL: {
|
|
1623
1819
|
this._err(ERR.unexpectedNullCharacter);
|
|
1624
|
-
this.
|
|
1820
|
+
this._extendRunWith(REPLACEMENT_CHARACTER, 0);
|
|
1625
1821
|
break;
|
|
1626
1822
|
}
|
|
1627
1823
|
case $.EOF: {
|
|
@@ -1630,7 +1826,7 @@ export class Tokenizer {
|
|
|
1630
1826
|
break;
|
|
1631
1827
|
}
|
|
1632
1828
|
default: {
|
|
1633
|
-
this.
|
|
1829
|
+
this._extendRun(cp);
|
|
1634
1830
|
}
|
|
1635
1831
|
}
|
|
1636
1832
|
}
|
|
@@ -1658,7 +1854,7 @@ export class Tokenizer {
|
|
|
1658
1854
|
}
|
|
1659
1855
|
case $.NULL: {
|
|
1660
1856
|
this._err(ERR.unexpectedNullCharacter);
|
|
1661
|
-
this.
|
|
1857
|
+
this._extendRunWith(REPLACEMENT_CHARACTER, 0);
|
|
1662
1858
|
break;
|
|
1663
1859
|
}
|
|
1664
1860
|
case $.QUOTATION_MARK:
|
|
@@ -1667,7 +1863,7 @@ export class Tokenizer {
|
|
|
1667
1863
|
case $.EQUALS_SIGN:
|
|
1668
1864
|
case $.GRAVE_ACCENT: {
|
|
1669
1865
|
this._err(ERR.unexpectedCharacterInUnquotedAttributeValue);
|
|
1670
|
-
this.
|
|
1866
|
+
this._extendRun(cp);
|
|
1671
1867
|
break;
|
|
1672
1868
|
}
|
|
1673
1869
|
case $.EOF: {
|
|
@@ -1676,7 +1872,7 @@ export class Tokenizer {
|
|
|
1676
1872
|
break;
|
|
1677
1873
|
}
|
|
1678
1874
|
default: {
|
|
1679
|
-
this.
|
|
1875
|
+
this._extendRun(cp);
|
|
1680
1876
|
}
|
|
1681
1877
|
}
|
|
1682
1878
|
}
|
|
@@ -1710,6 +1906,7 @@ export class Tokenizer {
|
|
|
1710
1906
|
}
|
|
1711
1907
|
default: {
|
|
1712
1908
|
this._err(ERR.missingWhitespaceBetweenAttributes);
|
|
1909
|
+
this._leaveAttrValue();
|
|
1713
1910
|
this.state = State.BEFORE_ATTRIBUTE_NAME;
|
|
1714
1911
|
this._stateBeforeAttributeName(cp);
|
|
1715
1912
|
}
|
|
@@ -1755,11 +1952,11 @@ export class Tokenizer {
|
|
|
1755
1952
|
}
|
|
1756
1953
|
case $.NULL: {
|
|
1757
1954
|
this._err(ERR.unexpectedNullCharacter);
|
|
1758
|
-
|
|
1955
|
+
this._extendRunWith(REPLACEMENT_CHARACTER, 0);
|
|
1759
1956
|
break;
|
|
1760
1957
|
}
|
|
1761
1958
|
default: {
|
|
1762
|
-
|
|
1959
|
+
this._extendRun(cp);
|
|
1763
1960
|
}
|
|
1764
1961
|
}
|
|
1765
1962
|
}
|
|
@@ -1838,7 +2035,7 @@ export class Tokenizer {
|
|
|
1838
2035
|
break;
|
|
1839
2036
|
}
|
|
1840
2037
|
default: {
|
|
1841
|
-
|
|
2038
|
+
this._extendRunWith('-', -1);
|
|
1842
2039
|
this.state = State.COMMENT;
|
|
1843
2040
|
this._stateComment(cp);
|
|
1844
2041
|
}
|
|
@@ -1854,13 +2051,13 @@ export class Tokenizer {
|
|
|
1854
2051
|
break;
|
|
1855
2052
|
}
|
|
1856
2053
|
case $.LESS_THAN_SIGN: {
|
|
1857
|
-
|
|
2054
|
+
this._extendRunWith('<', 0);
|
|
1858
2055
|
this.state = State.COMMENT_LESS_THAN_SIGN;
|
|
1859
2056
|
break;
|
|
1860
2057
|
}
|
|
1861
2058
|
case $.NULL: {
|
|
1862
2059
|
this._err(ERR.unexpectedNullCharacter);
|
|
1863
|
-
|
|
2060
|
+
this._extendRunWith(REPLACEMENT_CHARACTER, 0);
|
|
1864
2061
|
break;
|
|
1865
2062
|
}
|
|
1866
2063
|
case $.EOF: {
|
|
@@ -1870,22 +2067,21 @@ export class Tokenizer {
|
|
|
1870
2067
|
break;
|
|
1871
2068
|
}
|
|
1872
2069
|
default: {
|
|
1873
|
-
|
|
2070
|
+
this._extendRun(cp);
|
|
1874
2071
|
}
|
|
1875
2072
|
}
|
|
1876
2073
|
}
|
|
1877
2074
|
// Comment less-than sign state
|
|
1878
2075
|
//------------------------------------------------------------------
|
|
1879
2076
|
_stateCommentLessThanSign(cp) {
|
|
1880
|
-
const token = this.currentToken;
|
|
1881
2077
|
switch (cp) {
|
|
1882
2078
|
case $.EXCLAMATION_MARK: {
|
|
1883
|
-
|
|
2079
|
+
this._extendRunWith('!', 0);
|
|
1884
2080
|
this.state = State.COMMENT_LESS_THAN_SIGN_BANG;
|
|
1885
2081
|
break;
|
|
1886
2082
|
}
|
|
1887
2083
|
case $.LESS_THAN_SIGN: {
|
|
1888
|
-
|
|
2084
|
+
this._extendRunWith('<', 0);
|
|
1889
2085
|
break;
|
|
1890
2086
|
}
|
|
1891
2087
|
default: {
|
|
@@ -1941,7 +2137,7 @@ export class Tokenizer {
|
|
|
1941
2137
|
break;
|
|
1942
2138
|
}
|
|
1943
2139
|
default: {
|
|
1944
|
-
|
|
2140
|
+
this._extendRunWith('-', -1);
|
|
1945
2141
|
this.state = State.COMMENT;
|
|
1946
2142
|
this._stateComment(cp);
|
|
1947
2143
|
}
|
|
@@ -1962,7 +2158,7 @@ export class Tokenizer {
|
|
|
1962
2158
|
break;
|
|
1963
2159
|
}
|
|
1964
2160
|
case $.HYPHEN_MINUS: {
|
|
1965
|
-
|
|
2161
|
+
this._extendRunWith('-', -2);
|
|
1966
2162
|
break;
|
|
1967
2163
|
}
|
|
1968
2164
|
case $.EOF: {
|
|
@@ -1972,7 +2168,7 @@ export class Tokenizer {
|
|
|
1972
2168
|
break;
|
|
1973
2169
|
}
|
|
1974
2170
|
default: {
|
|
1975
|
-
|
|
2171
|
+
this._extendRunWith('--', -1);
|
|
1976
2172
|
this.state = State.COMMENT;
|
|
1977
2173
|
this._stateComment(cp);
|
|
1978
2174
|
}
|
|
@@ -1984,7 +2180,7 @@ export class Tokenizer {
|
|
|
1984
2180
|
const token = this.currentToken;
|
|
1985
2181
|
switch (cp) {
|
|
1986
2182
|
case $.HYPHEN_MINUS: {
|
|
1987
|
-
|
|
2183
|
+
this._extendRunWith('--!', -1);
|
|
1988
2184
|
this.state = State.COMMENT_END_DASH;
|
|
1989
2185
|
break;
|
|
1990
2186
|
}
|
|
@@ -2001,7 +2197,7 @@ export class Tokenizer {
|
|
|
2001
2197
|
break;
|
|
2002
2198
|
}
|
|
2003
2199
|
default: {
|
|
2004
|
-
|
|
2200
|
+
this._extendRunWith('--!', -1);
|
|
2005
2201
|
this.state = State.COMMENT;
|
|
2006
2202
|
this._stateComment(cp);
|
|
2007
2203
|
}
|
|
@@ -2638,7 +2834,7 @@ export class Tokenizer {
|
|
|
2638
2834
|
this.state = State.CDATA_SECTION_END;
|
|
2639
2835
|
}
|
|
2640
2836
|
else {
|
|
2641
|
-
this._emitChars(']');
|
|
2837
|
+
this._emitChars(']', -1);
|
|
2642
2838
|
this.state = State.CDATA_SECTION;
|
|
2643
2839
|
this._stateCdataSection(cp);
|
|
2644
2840
|
}
|
|
@@ -2652,11 +2848,11 @@ export class Tokenizer {
|
|
|
2652
2848
|
break;
|
|
2653
2849
|
}
|
|
2654
2850
|
case $.RIGHT_SQUARE_BRACKET: {
|
|
2655
|
-
this._emitChars(']');
|
|
2851
|
+
this._emitChars(']', -2);
|
|
2656
2852
|
break;
|
|
2657
2853
|
}
|
|
2658
2854
|
default: {
|
|
2659
|
-
this._emitChars(']]');
|
|
2855
|
+
this._emitChars(']]', -1);
|
|
2660
2856
|
this.state = State.CDATA_SECTION;
|
|
2661
2857
|
this._stateCdataSection(cp);
|
|
2662
2858
|
}
|