parse5 3.0.3 → 5.1.0

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.
Files changed (43) hide show
  1. package/README.md +14 -16
  2. package/lib/common/doctype.js +125 -108
  3. package/lib/common/error-codes.js +65 -0
  4. package/lib/common/foreign-content.js +265 -0
  5. package/lib/common/html.js +102 -102
  6. package/lib/common/unicode.js +81 -19
  7. package/lib/extensions/error-reporting/mixin-base.js +43 -0
  8. package/lib/extensions/error-reporting/parser-mixin.js +52 -0
  9. package/lib/extensions/error-reporting/preprocessor-mixin.js +24 -0
  10. package/lib/extensions/error-reporting/tokenizer-mixin.js +17 -0
  11. package/lib/extensions/location-info/open-element-stack-mixin.js +35 -0
  12. package/lib/extensions/location-info/parser-mixin.js +222 -0
  13. package/lib/extensions/location-info/tokenizer-mixin.js +146 -0
  14. package/lib/extensions/position-tracking/preprocessor-mixin.js +64 -0
  15. package/lib/index.js +6 -21
  16. package/lib/parser/formatting-element-list.js +181 -0
  17. package/lib/parser/index.js +1469 -1332
  18. package/lib/parser/open-element-stack.js +482 -0
  19. package/lib/serializer/index.js +136 -122
  20. package/lib/tokenizer/index.js +1856 -1804
  21. package/lib/tokenizer/{named_entity_data.js → named-entity-data.js} +1 -1
  22. package/lib/tokenizer/preprocessor.js +115 -103
  23. package/lib/tree-adapters/default.js +217 -0
  24. package/lib/utils/{merge_options.js → merge-options.js} +2 -2
  25. package/lib/utils/mixin.js +33 -12
  26. package/package.json +32 -61
  27. package/LICENSE +0 -19
  28. package/lib/common/foreign_content.js +0 -260
  29. package/lib/extensions/location_info/open_element_stack_mixin.js +0 -34
  30. package/lib/extensions/location_info/parser_mixin.js +0 -213
  31. package/lib/extensions/location_info/tokenizer_mixin.js +0 -117
  32. package/lib/extensions/position_tracking/preprocessor_mixin.js +0 -72
  33. package/lib/index.d.ts +0 -1077
  34. package/lib/parser/formatting_element_list.js +0 -167
  35. package/lib/parser/open_element_stack.js +0 -395
  36. package/lib/parser/parser_stream.js +0 -76
  37. package/lib/parser/plain_text_conversion_stream.js +0 -20
  38. package/lib/sax/dev_null_stream.js +0 -14
  39. package/lib/sax/index.js +0 -118
  40. package/lib/sax/parser_feedback_simulator.js +0 -153
  41. package/lib/serializer/serializer_stream.js +0 -28
  42. package/lib/tree_adapters/default.js +0 -209
  43. package/lib/tree_adapters/htmlparser2.js +0 -338
@@ -1,95 +1,132 @@
1
1
  'use strict';
2
2
 
3
- var Preprocessor = require('./preprocessor'),
4
- UNICODE = require('../common/unicode'),
5
- neTree = require('./named_entity_data');
3
+ const Preprocessor = require('./preprocessor');
4
+ const unicode = require('../common/unicode');
5
+ const neTree = require('./named-entity-data');
6
+ const ERR = require('../common/error-codes');
6
7
 
7
8
  //Aliases
8
- var $ = UNICODE.CODE_POINTS,
9
- $$ = UNICODE.CODE_POINT_SEQUENCES;
10
-
11
- //Replacement code points for numeric entities
12
- var NUMERIC_ENTITY_REPLACEMENTS = {
13
- 0x00: 0xFFFD, 0x0D: 0x000D, 0x80: 0x20AC, 0x81: 0x0081, 0x82: 0x201A, 0x83: 0x0192, 0x84: 0x201E,
14
- 0x85: 0x2026, 0x86: 0x2020, 0x87: 0x2021, 0x88: 0x02C6, 0x89: 0x2030, 0x8A: 0x0160, 0x8B: 0x2039,
15
- 0x8C: 0x0152, 0x8D: 0x008D, 0x8E: 0x017D, 0x8F: 0x008F, 0x90: 0x0090, 0x91: 0x2018, 0x92: 0x2019,
16
- 0x93: 0x201C, 0x94: 0x201D, 0x95: 0x2022, 0x96: 0x2013, 0x97: 0x2014, 0x98: 0x02DC, 0x99: 0x2122,
17
- 0x9A: 0x0161, 0x9B: 0x203A, 0x9C: 0x0153, 0x9D: 0x009D, 0x9E: 0x017E, 0x9F: 0x0178
9
+ const $ = unicode.CODE_POINTS;
10
+ const $$ = unicode.CODE_POINT_SEQUENCES;
11
+
12
+ //C1 Unicode control character reference replacements
13
+ const C1_CONTROLS_REFERENCE_REPLACEMENTS = {
14
+ 0x80: 0x20ac,
15
+ 0x82: 0x201a,
16
+ 0x83: 0x0192,
17
+ 0x84: 0x201e,
18
+ 0x85: 0x2026,
19
+ 0x86: 0x2020,
20
+ 0x87: 0x2021,
21
+ 0x88: 0x02c6,
22
+ 0x89: 0x2030,
23
+ 0x8a: 0x0160,
24
+ 0x8b: 0x2039,
25
+ 0x8c: 0x0152,
26
+ 0x8e: 0x017d,
27
+ 0x91: 0x2018,
28
+ 0x92: 0x2019,
29
+ 0x93: 0x201c,
30
+ 0x94: 0x201d,
31
+ 0x95: 0x2022,
32
+ 0x96: 0x2013,
33
+ 0x97: 0x2014,
34
+ 0x98: 0x02dc,
35
+ 0x99: 0x2122,
36
+ 0x9a: 0x0161,
37
+ 0x9b: 0x203a,
38
+ 0x9c: 0x0153,
39
+ 0x9e: 0x017e,
40
+ 0x9f: 0x0178
18
41
  };
19
42
 
20
43
  // Named entity tree flags
21
- var HAS_DATA_FLAG = 1 << 0;
22
- var DATA_DUPLET_FLAG = 1 << 1;
23
- var HAS_BRANCHES_FLAG = 1 << 2;
24
- var MAX_BRANCH_MARKER_VALUE = HAS_DATA_FLAG | DATA_DUPLET_FLAG | HAS_BRANCHES_FLAG;
25
-
44
+ const HAS_DATA_FLAG = 1 << 0;
45
+ const DATA_DUPLET_FLAG = 1 << 1;
46
+ const HAS_BRANCHES_FLAG = 1 << 2;
47
+ const MAX_BRANCH_MARKER_VALUE = HAS_DATA_FLAG | DATA_DUPLET_FLAG | HAS_BRANCHES_FLAG;
26
48
 
27
49
  //States
28
- var DATA_STATE = 'DATA_STATE',
29
- CHARACTER_REFERENCE_IN_DATA_STATE = 'CHARACTER_REFERENCE_IN_DATA_STATE',
30
- RCDATA_STATE = 'RCDATA_STATE',
31
- CHARACTER_REFERENCE_IN_RCDATA_STATE = 'CHARACTER_REFERENCE_IN_RCDATA_STATE',
32
- RAWTEXT_STATE = 'RAWTEXT_STATE',
33
- SCRIPT_DATA_STATE = 'SCRIPT_DATA_STATE',
34
- PLAINTEXT_STATE = 'PLAINTEXT_STATE',
35
- TAG_OPEN_STATE = 'TAG_OPEN_STATE',
36
- END_TAG_OPEN_STATE = 'END_TAG_OPEN_STATE',
37
- TAG_NAME_STATE = 'TAG_NAME_STATE',
38
- RCDATA_LESS_THAN_SIGN_STATE = 'RCDATA_LESS_THAN_SIGN_STATE',
39
- RCDATA_END_TAG_OPEN_STATE = 'RCDATA_END_TAG_OPEN_STATE',
40
- RCDATA_END_TAG_NAME_STATE = 'RCDATA_END_TAG_NAME_STATE',
41
- RAWTEXT_LESS_THAN_SIGN_STATE = 'RAWTEXT_LESS_THAN_SIGN_STATE',
42
- RAWTEXT_END_TAG_OPEN_STATE = 'RAWTEXT_END_TAG_OPEN_STATE',
43
- RAWTEXT_END_TAG_NAME_STATE = 'RAWTEXT_END_TAG_NAME_STATE',
44
- SCRIPT_DATA_LESS_THAN_SIGN_STATE = 'SCRIPT_DATA_LESS_THAN_SIGN_STATE',
45
- SCRIPT_DATA_END_TAG_OPEN_STATE = 'SCRIPT_DATA_END_TAG_OPEN_STATE',
46
- SCRIPT_DATA_END_TAG_NAME_STATE = 'SCRIPT_DATA_END_TAG_NAME_STATE',
47
- SCRIPT_DATA_ESCAPE_START_STATE = 'SCRIPT_DATA_ESCAPE_START_STATE',
48
- SCRIPT_DATA_ESCAPE_START_DASH_STATE = 'SCRIPT_DATA_ESCAPE_START_DASH_STATE',
49
- SCRIPT_DATA_ESCAPED_STATE = 'SCRIPT_DATA_ESCAPED_STATE',
50
- SCRIPT_DATA_ESCAPED_DASH_STATE = 'SCRIPT_DATA_ESCAPED_DASH_STATE',
51
- SCRIPT_DATA_ESCAPED_DASH_DASH_STATE = 'SCRIPT_DATA_ESCAPED_DASH_DASH_STATE',
52
- SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN_STATE = 'SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN_STATE',
53
- SCRIPT_DATA_ESCAPED_END_TAG_OPEN_STATE = 'SCRIPT_DATA_ESCAPED_END_TAG_OPEN_STATE',
54
- SCRIPT_DATA_ESCAPED_END_TAG_NAME_STATE = 'SCRIPT_DATA_ESCAPED_END_TAG_NAME_STATE',
55
- SCRIPT_DATA_DOUBLE_ESCAPE_START_STATE = 'SCRIPT_DATA_DOUBLE_ESCAPE_START_STATE',
56
- SCRIPT_DATA_DOUBLE_ESCAPED_STATE = 'SCRIPT_DATA_DOUBLE_ESCAPED_STATE',
57
- SCRIPT_DATA_DOUBLE_ESCAPED_DASH_STATE = 'SCRIPT_DATA_DOUBLE_ESCAPED_DASH_STATE',
58
- SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH_STATE = 'SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH_STATE',
59
- SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN_STATE = 'SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN_STATE',
60
- SCRIPT_DATA_DOUBLE_ESCAPE_END_STATE = 'SCRIPT_DATA_DOUBLE_ESCAPE_END_STATE',
61
- BEFORE_ATTRIBUTE_NAME_STATE = 'BEFORE_ATTRIBUTE_NAME_STATE',
62
- ATTRIBUTE_NAME_STATE = 'ATTRIBUTE_NAME_STATE',
63
- AFTER_ATTRIBUTE_NAME_STATE = 'AFTER_ATTRIBUTE_NAME_STATE',
64
- BEFORE_ATTRIBUTE_VALUE_STATE = 'BEFORE_ATTRIBUTE_VALUE_STATE',
65
- ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE = 'ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE',
66
- ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE = 'ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE',
67
- ATTRIBUTE_VALUE_UNQUOTED_STATE = 'ATTRIBUTE_VALUE_UNQUOTED_STATE',
68
- CHARACTER_REFERENCE_IN_ATTRIBUTE_VALUE_STATE = 'CHARACTER_REFERENCE_IN_ATTRIBUTE_VALUE_STATE',
69
- AFTER_ATTRIBUTE_VALUE_QUOTED_STATE = 'AFTER_ATTRIBUTE_VALUE_QUOTED_STATE',
70
- SELF_CLOSING_START_TAG_STATE = 'SELF_CLOSING_START_TAG_STATE',
71
- BOGUS_COMMENT_STATE = 'BOGUS_COMMENT_STATE',
72
- BOGUS_COMMENT_STATE_CONTINUATION = 'BOGUS_COMMENT_STATE_CONTINUATION',
73
- MARKUP_DECLARATION_OPEN_STATE = 'MARKUP_DECLARATION_OPEN_STATE',
74
- COMMENT_START_STATE = 'COMMENT_START_STATE',
75
- COMMENT_START_DASH_STATE = 'COMMENT_START_DASH_STATE',
76
- COMMENT_STATE = 'COMMENT_STATE',
77
- COMMENT_END_DASH_STATE = 'COMMENT_END_DASH_STATE',
78
- COMMENT_END_STATE = 'COMMENT_END_STATE',
79
- COMMENT_END_BANG_STATE = 'COMMENT_END_BANG_STATE',
80
- DOCTYPE_STATE = 'DOCTYPE_STATE',
81
- DOCTYPE_NAME_STATE = 'DOCTYPE_NAME_STATE',
82
- AFTER_DOCTYPE_NAME_STATE = 'AFTER_DOCTYPE_NAME_STATE',
83
- BEFORE_DOCTYPE_PUBLIC_IDENTIFIER_STATE = 'BEFORE_DOCTYPE_PUBLIC_IDENTIFIER_STATE',
84
- DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED_STATE = 'DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED_STATE',
85
- DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED_STATE = 'DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED_STATE',
86
- BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS_STATE = 'BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS_STATE',
87
- BEFORE_DOCTYPE_SYSTEM_IDENTIFIER_STATE = 'BEFORE_DOCTYPE_SYSTEM_IDENTIFIER_STATE',
88
- DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE = 'DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE',
89
- DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE = 'DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE',
90
- AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE = 'AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE',
91
- BOGUS_DOCTYPE_STATE = 'BOGUS_DOCTYPE_STATE',
92
- CDATA_SECTION_STATE = 'CDATA_SECTION_STATE';
50
+ const DATA_STATE = 'DATA_STATE';
51
+ const RCDATA_STATE = 'RCDATA_STATE';
52
+ const RAWTEXT_STATE = 'RAWTEXT_STATE';
53
+ const SCRIPT_DATA_STATE = 'SCRIPT_DATA_STATE';
54
+ const PLAINTEXT_STATE = 'PLAINTEXT_STATE';
55
+ const TAG_OPEN_STATE = 'TAG_OPEN_STATE';
56
+ const END_TAG_OPEN_STATE = 'END_TAG_OPEN_STATE';
57
+ const TAG_NAME_STATE = 'TAG_NAME_STATE';
58
+ const RCDATA_LESS_THAN_SIGN_STATE = 'RCDATA_LESS_THAN_SIGN_STATE';
59
+ const RCDATA_END_TAG_OPEN_STATE = 'RCDATA_END_TAG_OPEN_STATE';
60
+ const RCDATA_END_TAG_NAME_STATE = 'RCDATA_END_TAG_NAME_STATE';
61
+ const RAWTEXT_LESS_THAN_SIGN_STATE = 'RAWTEXT_LESS_THAN_SIGN_STATE';
62
+ const RAWTEXT_END_TAG_OPEN_STATE = 'RAWTEXT_END_TAG_OPEN_STATE';
63
+ const RAWTEXT_END_TAG_NAME_STATE = 'RAWTEXT_END_TAG_NAME_STATE';
64
+ const SCRIPT_DATA_LESS_THAN_SIGN_STATE = 'SCRIPT_DATA_LESS_THAN_SIGN_STATE';
65
+ const SCRIPT_DATA_END_TAG_OPEN_STATE = 'SCRIPT_DATA_END_TAG_OPEN_STATE';
66
+ const SCRIPT_DATA_END_TAG_NAME_STATE = 'SCRIPT_DATA_END_TAG_NAME_STATE';
67
+ const SCRIPT_DATA_ESCAPE_START_STATE = 'SCRIPT_DATA_ESCAPE_START_STATE';
68
+ const SCRIPT_DATA_ESCAPE_START_DASH_STATE = 'SCRIPT_DATA_ESCAPE_START_DASH_STATE';
69
+ const SCRIPT_DATA_ESCAPED_STATE = 'SCRIPT_DATA_ESCAPED_STATE';
70
+ const SCRIPT_DATA_ESCAPED_DASH_STATE = 'SCRIPT_DATA_ESCAPED_DASH_STATE';
71
+ const SCRIPT_DATA_ESCAPED_DASH_DASH_STATE = 'SCRIPT_DATA_ESCAPED_DASH_DASH_STATE';
72
+ const SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN_STATE = 'SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN_STATE';
73
+ const SCRIPT_DATA_ESCAPED_END_TAG_OPEN_STATE = 'SCRIPT_DATA_ESCAPED_END_TAG_OPEN_STATE';
74
+ const SCRIPT_DATA_ESCAPED_END_TAG_NAME_STATE = 'SCRIPT_DATA_ESCAPED_END_TAG_NAME_STATE';
75
+ const SCRIPT_DATA_DOUBLE_ESCAPE_START_STATE = 'SCRIPT_DATA_DOUBLE_ESCAPE_START_STATE';
76
+ const SCRIPT_DATA_DOUBLE_ESCAPED_STATE = 'SCRIPT_DATA_DOUBLE_ESCAPED_STATE';
77
+ const SCRIPT_DATA_DOUBLE_ESCAPED_DASH_STATE = 'SCRIPT_DATA_DOUBLE_ESCAPED_DASH_STATE';
78
+ const SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH_STATE = 'SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH_STATE';
79
+ const SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN_STATE = 'SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN_STATE';
80
+ const SCRIPT_DATA_DOUBLE_ESCAPE_END_STATE = 'SCRIPT_DATA_DOUBLE_ESCAPE_END_STATE';
81
+ const BEFORE_ATTRIBUTE_NAME_STATE = 'BEFORE_ATTRIBUTE_NAME_STATE';
82
+ const ATTRIBUTE_NAME_STATE = 'ATTRIBUTE_NAME_STATE';
83
+ const AFTER_ATTRIBUTE_NAME_STATE = 'AFTER_ATTRIBUTE_NAME_STATE';
84
+ const BEFORE_ATTRIBUTE_VALUE_STATE = 'BEFORE_ATTRIBUTE_VALUE_STATE';
85
+ const ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE = 'ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE';
86
+ const ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE = 'ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE';
87
+ const ATTRIBUTE_VALUE_UNQUOTED_STATE = 'ATTRIBUTE_VALUE_UNQUOTED_STATE';
88
+ const AFTER_ATTRIBUTE_VALUE_QUOTED_STATE = 'AFTER_ATTRIBUTE_VALUE_QUOTED_STATE';
89
+ const SELF_CLOSING_START_TAG_STATE = 'SELF_CLOSING_START_TAG_STATE';
90
+ const BOGUS_COMMENT_STATE = 'BOGUS_COMMENT_STATE';
91
+ const MARKUP_DECLARATION_OPEN_STATE = 'MARKUP_DECLARATION_OPEN_STATE';
92
+ const COMMENT_START_STATE = 'COMMENT_START_STATE';
93
+ const COMMENT_START_DASH_STATE = 'COMMENT_START_DASH_STATE';
94
+ const COMMENT_STATE = 'COMMENT_STATE';
95
+ const COMMENT_LESS_THAN_SIGN_STATE = 'COMMENT_LESS_THAN_SIGN_STATE';
96
+ const COMMENT_LESS_THAN_SIGN_BANG_STATE = 'COMMENT_LESS_THAN_SIGN_BANG_STATE';
97
+ const COMMENT_LESS_THAN_SIGN_BANG_DASH_STATE = 'COMMENT_LESS_THAN_SIGN_BANG_DASH_STATE';
98
+ const COMMENT_LESS_THAN_SIGN_BANG_DASH_DASH_STATE = 'COMMENT_LESS_THAN_SIGN_BANG_DASH_DASH_STATE';
99
+ const COMMENT_END_DASH_STATE = 'COMMENT_END_DASH_STATE';
100
+ const COMMENT_END_STATE = 'COMMENT_END_STATE';
101
+ const COMMENT_END_BANG_STATE = 'COMMENT_END_BANG_STATE';
102
+ const DOCTYPE_STATE = 'DOCTYPE_STATE';
103
+ const BEFORE_DOCTYPE_NAME_STATE = 'BEFORE_DOCTYPE_NAME_STATE';
104
+ const DOCTYPE_NAME_STATE = 'DOCTYPE_NAME_STATE';
105
+ const AFTER_DOCTYPE_NAME_STATE = 'AFTER_DOCTYPE_NAME_STATE';
106
+ const AFTER_DOCTYPE_PUBLIC_KEYWORD_STATE = 'AFTER_DOCTYPE_PUBLIC_KEYWORD_STATE';
107
+ const BEFORE_DOCTYPE_PUBLIC_IDENTIFIER_STATE = 'BEFORE_DOCTYPE_PUBLIC_IDENTIFIER_STATE';
108
+ const DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED_STATE = 'DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED_STATE';
109
+ const DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED_STATE = 'DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED_STATE';
110
+ const AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE = 'AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE';
111
+ const BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS_STATE = 'BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS_STATE';
112
+ const AFTER_DOCTYPE_SYSTEM_KEYWORD_STATE = 'AFTER_DOCTYPE_SYSTEM_KEYWORD_STATE';
113
+ const BEFORE_DOCTYPE_SYSTEM_IDENTIFIER_STATE = 'BEFORE_DOCTYPE_SYSTEM_IDENTIFIER_STATE';
114
+ const DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE = 'DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE';
115
+ const DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE = 'DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE';
116
+ const AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE = 'AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE';
117
+ const BOGUS_DOCTYPE_STATE = 'BOGUS_DOCTYPE_STATE';
118
+ const CDATA_SECTION_STATE = 'CDATA_SECTION_STATE';
119
+ const CDATA_SECTION_BRACKET_STATE = 'CDATA_SECTION_BRACKET_STATE';
120
+ const CDATA_SECTION_END_STATE = 'CDATA_SECTION_END_STATE';
121
+ const CHARACTER_REFERENCE_STATE = 'CHARACTER_REFERENCE_STATE';
122
+ const NAMED_CHARACTER_REFERENCE_STATE = 'NAMED_CHARACTER_REFERENCE_STATE';
123
+ const AMBIGUOUS_AMPERSAND_STATE = 'AMBIGUOS_AMPERSAND_STATE';
124
+ const NUMERIC_CHARACTER_REFERENCE_STATE = 'NUMERIC_CHARACTER_REFERENCE_STATE';
125
+ const HEXADEMICAL_CHARACTER_REFERENCE_START_STATE = 'HEXADEMICAL_CHARACTER_REFERENCE_START_STATE';
126
+ const DECIMAL_CHARACTER_REFERENCE_START_STATE = 'DECIMAL_CHARACTER_REFERENCE_START_STATE';
127
+ const HEXADEMICAL_CHARACTER_REFERENCE_STATE = 'HEXADEMICAL_CHARACTER_REFERENCE_STATE';
128
+ const DECIMAL_CHARACTER_REFERENCE_STATE = 'DECIMAL_CHARACTER_REFERENCE_STATE';
129
+ const NUMERIC_CHARACTER_REFERENCE_END_STATE = 'NUMERIC_CHARACTER_REFERENCE_END_STATE';
93
130
 
94
131
  //Utils
95
132
 
@@ -120,13 +157,16 @@ function isAsciiAlphaNumeric(cp) {
120
157
  return isAsciiLetter(cp) || isAsciiDigit(cp);
121
158
  }
122
159
 
123
- function isDigit(cp, isHex) {
124
- return isAsciiDigit(cp) || isHex && (cp >= $.LATIN_CAPITAL_A && cp <= $.LATIN_CAPITAL_F ||
125
- cp >= $.LATIN_SMALL_A && cp <= $.LATIN_SMALL_F);
160
+ function isAsciiUpperHexDigit(cp) {
161
+ return cp >= $.LATIN_CAPITAL_A && cp <= $.LATIN_CAPITAL_F;
162
+ }
163
+
164
+ function isAsciiLowerHexDigit(cp) {
165
+ return cp >= $.LATIN_SMALL_A && cp <= $.LATIN_SMALL_F;
126
166
  }
127
167
 
128
- function isReservedCodePoint(cp) {
129
- return cp >= 0xD800 && cp <= 0xDFFF || cp > 0x10FFFF;
168
+ function isAsciiHexDigit(cp) {
169
+ return isAsciiDigit(cp) || isAsciiUpperHexDigit(cp) || isAsciiLowerHexDigit(cp);
130
170
  }
131
171
 
132
172
  function toAsciiLowerCodePoint(cp) {
@@ -137,11 +177,12 @@ function toAsciiLowerCodePoint(cp) {
137
177
  //So, we need to workaround this manually.
138
178
  //(see: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/fromCharCode#Getting_it_to_work_with_higher_values)
139
179
  function toChar(cp) {
140
- if (cp <= 0xFFFF)
180
+ if (cp <= 0xffff) {
141
181
  return String.fromCharCode(cp);
182
+ }
142
183
 
143
184
  cp -= 0x10000;
144
- return String.fromCharCode(cp >>> 10 & 0x3FF | 0xD800) + String.fromCharCode(0xDC00 | cp & 0x3FF);
185
+ return String.fromCharCode(((cp >>> 10) & 0x3ff) | 0xd800) + String.fromCharCode(0xdc00 | (cp & 0x3ff));
145
186
  }
146
187
 
147
188
  function toAsciiLowerChar(cp) {
@@ -149,1996 +190,2007 @@ function toAsciiLowerChar(cp) {
149
190
  }
150
191
 
151
192
  function findNamedEntityTreeBranch(nodeIx, cp) {
152
- var branchCount = neTree[++nodeIx],
153
- lo = ++nodeIx,
154
- hi = lo + branchCount - 1;
193
+ const branchCount = neTree[++nodeIx];
194
+ let lo = ++nodeIx;
195
+ let hi = lo + branchCount - 1;
155
196
 
156
197
  while (lo <= hi) {
157
- var mid = lo + hi >>> 1,
158
- midCp = neTree[mid];
198
+ const mid = (lo + hi) >>> 1;
199
+ const midCp = neTree[mid];
159
200
 
160
- if (midCp < cp)
201
+ if (midCp < cp) {
161
202
  lo = mid + 1;
162
-
163
- else if (midCp > cp)
203
+ } else if (midCp > cp) {
164
204
  hi = mid - 1;
165
-
166
- else
205
+ } else {
167
206
  return neTree[mid + branchCount];
207
+ }
168
208
  }
169
209
 
170
210
  return -1;
171
211
  }
172
212
 
173
-
174
213
  //Tokenizer
175
- var Tokenizer = module.exports = function () {
176
- this.preprocessor = new Preprocessor();
214
+ class Tokenizer {
215
+ constructor() {
216
+ this.preprocessor = new Preprocessor();
177
217
 
178
- this.tokenQueue = [];
218
+ this.tokenQueue = [];
179
219
 
180
- this.allowCDATA = false;
220
+ this.allowCDATA = false;
181
221
 
182
- this.state = DATA_STATE;
183
- this.returnState = '';
184
-
185
- this.tempBuff = [];
186
- this.additionalAllowedCp = void 0;
187
- this.lastStartTagName = '';
222
+ this.state = DATA_STATE;
223
+ this.returnState = '';
188
224
 
189
- this.consumedAfterSnapshot = -1;
190
- this.active = false;
225
+ this.charRefCode = -1;
226
+ this.tempBuff = [];
227
+ this.lastStartTagName = '';
191
228
 
192
- this.currentCharacterToken = null;
193
- this.currentToken = null;
194
- this.currentAttr = null;
195
- };
229
+ this.consumedAfterSnapshot = -1;
230
+ this.active = false;
196
231
 
197
- //Token types
198
- Tokenizer.CHARACTER_TOKEN = 'CHARACTER_TOKEN';
199
- Tokenizer.NULL_CHARACTER_TOKEN = 'NULL_CHARACTER_TOKEN';
200
- Tokenizer.WHITESPACE_CHARACTER_TOKEN = 'WHITESPACE_CHARACTER_TOKEN';
201
- Tokenizer.START_TAG_TOKEN = 'START_TAG_TOKEN';
202
- Tokenizer.END_TAG_TOKEN = 'END_TAG_TOKEN';
203
- Tokenizer.COMMENT_TOKEN = 'COMMENT_TOKEN';
204
- Tokenizer.DOCTYPE_TOKEN = 'DOCTYPE_TOKEN';
205
- Tokenizer.EOF_TOKEN = 'EOF_TOKEN';
206
- Tokenizer.HIBERNATION_TOKEN = 'HIBERNATION_TOKEN';
232
+ this.currentCharacterToken = null;
233
+ this.currentToken = null;
234
+ this.currentAttr = null;
235
+ }
207
236
 
208
- //Tokenizer initial states for different modes
209
- Tokenizer.MODE = {
210
- DATA: DATA_STATE,
211
- RCDATA: RCDATA_STATE,
212
- RAWTEXT: RAWTEXT_STATE,
213
- SCRIPT_DATA: SCRIPT_DATA_STATE,
214
- PLAINTEXT: PLAINTEXT_STATE
215
- };
237
+ //Errors
238
+ _err() {
239
+ // NOTE: err reporting is noop by default. Enabled by mixin.
240
+ }
216
241
 
217
- //Static
218
- Tokenizer.getTokenAttr = function (token, attrName) {
219
- for (var i = token.attrs.length - 1; i >= 0; i--) {
220
- if (token.attrs[i].name === attrName)
221
- return token.attrs[i].value;
242
+ _errOnNextCodePoint(err) {
243
+ this._consume();
244
+ this._err(err);
245
+ this._unconsume();
222
246
  }
223
247
 
224
- return null;
225
- };
248
+ //API
249
+ getNextToken() {
250
+ while (!this.tokenQueue.length && this.active) {
251
+ this.consumedAfterSnapshot = 0;
226
252
 
227
- //API
228
- Tokenizer.prototype.getNextToken = function () {
229
- while (!this.tokenQueue.length && this.active) {
230
- this._hibernationSnapshot();
253
+ const cp = this._consume();
231
254
 
232
- var cp = this._consume();
255
+ if (!this._ensureHibernation()) {
256
+ this[this.state](cp);
257
+ }
258
+ }
233
259
 
234
- if (!this._ensureHibernation())
235
- this[this.state](cp);
260
+ return this.tokenQueue.shift();
236
261
  }
237
262
 
238
- return this.tokenQueue.shift();
239
- };
240
-
241
- Tokenizer.prototype.write = function (chunk, isLastChunk) {
242
- this.active = true;
243
- this.preprocessor.write(chunk, isLastChunk);
244
- };
263
+ write(chunk, isLastChunk) {
264
+ this.active = true;
265
+ this.preprocessor.write(chunk, isLastChunk);
266
+ }
245
267
 
246
- Tokenizer.prototype.insertHtmlAtCurrentPos = function (chunk) {
247
- this.active = true;
248
- this.preprocessor.insertHtmlAtCurrentPos(chunk);
249
- };
268
+ insertHtmlAtCurrentPos(chunk) {
269
+ this.active = true;
270
+ this.preprocessor.insertHtmlAtCurrentPos(chunk);
271
+ }
250
272
 
251
- //Hibernation
252
- Tokenizer.prototype._hibernationSnapshot = function () {
253
- this.consumedAfterSnapshot = 0;
254
- };
273
+ //Hibernation
274
+ _ensureHibernation() {
275
+ if (this.preprocessor.endOfChunkHit) {
276
+ for (; this.consumedAfterSnapshot > 0; this.consumedAfterSnapshot--) {
277
+ this.preprocessor.retreat();
278
+ }
255
279
 
256
- Tokenizer.prototype._ensureHibernation = function () {
257
- if (this.preprocessor.endOfChunkHit) {
258
- for (; this.consumedAfterSnapshot > 0; this.consumedAfterSnapshot--)
259
- this.preprocessor.retreat();
280
+ this.active = false;
281
+ this.tokenQueue.push({ type: Tokenizer.HIBERNATION_TOKEN });
260
282
 
261
- this.active = false;
262
- this.tokenQueue.push({type: Tokenizer.HIBERNATION_TOKEN});
283
+ return true;
284
+ }
263
285
 
264
- return true;
286
+ return false;
265
287
  }
266
288
 
267
- return false;
268
- };
289
+ //Consumption
290
+ _consume() {
291
+ this.consumedAfterSnapshot++;
292
+ return this.preprocessor.advance();
293
+ }
269
294
 
295
+ _unconsume() {
296
+ this.consumedAfterSnapshot--;
297
+ this.preprocessor.retreat();
298
+ }
270
299
 
271
- //Consumption
272
- Tokenizer.prototype._consume = function () {
273
- this.consumedAfterSnapshot++;
274
- return this.preprocessor.advance();
275
- };
300
+ _reconsumeInState(state) {
301
+ this.state = state;
302
+ this._unconsume();
303
+ }
276
304
 
277
- Tokenizer.prototype._unconsume = function () {
278
- this.consumedAfterSnapshot--;
279
- this.preprocessor.retreat();
280
- };
305
+ _consumeSequenceIfMatch(pattern, startCp, caseSensitive) {
306
+ let consumedCount = 0;
307
+ let isMatch = true;
308
+ const patternLength = pattern.length;
309
+ let patternPos = 0;
310
+ let cp = startCp;
311
+ let patternCp = void 0;
281
312
 
282
- Tokenizer.prototype._unconsumeSeveral = function (count) {
283
- while (count--)
284
- this._unconsume();
285
- };
313
+ for (; patternPos < patternLength; patternPos++) {
314
+ if (patternPos > 0) {
315
+ cp = this._consume();
316
+ consumedCount++;
317
+ }
286
318
 
287
- Tokenizer.prototype._reconsumeInState = function (state) {
288
- this.state = state;
289
- this._unconsume();
290
- };
319
+ if (cp === $.EOF) {
320
+ isMatch = false;
321
+ break;
322
+ }
291
323
 
292
- Tokenizer.prototype._consumeSubsequentIfMatch = function (pattern, startCp, caseSensitive) {
293
- var consumedCount = 0,
294
- isMatch = true,
295
- patternLength = pattern.length,
296
- patternPos = 0,
297
- cp = startCp,
298
- patternCp = void 0;
324
+ patternCp = pattern[patternPos];
299
325
 
300
- for (; patternPos < patternLength; patternPos++) {
301
- if (patternPos > 0) {
302
- cp = this._consume();
303
- consumedCount++;
326
+ if (cp !== patternCp && (caseSensitive || cp !== toAsciiLowerCodePoint(patternCp))) {
327
+ isMatch = false;
328
+ break;
329
+ }
304
330
  }
305
331
 
306
- if (cp === $.EOF) {
307
- isMatch = false;
308
- break;
332
+ if (!isMatch) {
333
+ while (consumedCount--) {
334
+ this._unconsume();
335
+ }
309
336
  }
310
337
 
311
- patternCp = pattern[patternPos];
338
+ return isMatch;
339
+ }
312
340
 
313
- if (cp !== patternCp && (caseSensitive || cp !== toAsciiLowerCodePoint(patternCp))) {
314
- isMatch = false;
315
- break;
341
+ //Temp buffer
342
+ _isTempBufferEqualToScriptString() {
343
+ if (this.tempBuff.length !== $$.SCRIPT_STRING.length) {
344
+ return false;
316
345
  }
317
- }
318
346
 
319
- if (!isMatch)
320
- this._unconsumeSeveral(consumedCount);
347
+ for (let i = 0; i < this.tempBuff.length; i++) {
348
+ if (this.tempBuff[i] !== $$.SCRIPT_STRING[i]) {
349
+ return false;
350
+ }
351
+ }
321
352
 
322
- return isMatch;
323
- };
353
+ return true;
354
+ }
324
355
 
325
- //Lookahead
326
- Tokenizer.prototype._lookahead = function () {
327
- var cp = this._consume();
356
+ //Token creation
357
+ _createStartTagToken() {
358
+ this.currentToken = {
359
+ type: Tokenizer.START_TAG_TOKEN,
360
+ tagName: '',
361
+ selfClosing: false,
362
+ ackSelfClosing: false,
363
+ attrs: []
364
+ };
365
+ }
328
366
 
329
- this._unconsume();
367
+ _createEndTagToken() {
368
+ this.currentToken = {
369
+ type: Tokenizer.END_TAG_TOKEN,
370
+ tagName: '',
371
+ selfClosing: false,
372
+ attrs: []
373
+ };
374
+ }
330
375
 
331
- return cp;
332
- };
376
+ _createCommentToken() {
377
+ this.currentToken = {
378
+ type: Tokenizer.COMMENT_TOKEN,
379
+ data: ''
380
+ };
381
+ }
333
382
 
334
- //Temp buffer
335
- Tokenizer.prototype.isTempBufferEqualToScriptString = function () {
336
- if (this.tempBuff.length !== $$.SCRIPT_STRING.length)
337
- return false;
383
+ _createDoctypeToken(initialName) {
384
+ this.currentToken = {
385
+ type: Tokenizer.DOCTYPE_TOKEN,
386
+ name: initialName,
387
+ forceQuirks: false,
388
+ publicId: null,
389
+ systemId: null
390
+ };
391
+ }
338
392
 
339
- for (var i = 0; i < this.tempBuff.length; i++) {
340
- if (this.tempBuff[i] !== $$.SCRIPT_STRING[i])
341
- return false;
393
+ _createCharacterToken(type, ch) {
394
+ this.currentCharacterToken = {
395
+ type: type,
396
+ chars: ch
397
+ };
342
398
  }
343
399
 
344
- return true;
345
- };
400
+ _createEOFToken() {
401
+ this.currentToken = { type: Tokenizer.EOF_TOKEN };
402
+ }
346
403
 
347
- //Token creation
348
- Tokenizer.prototype._createStartTagToken = function () {
349
- this.currentToken = {
350
- type: Tokenizer.START_TAG_TOKEN,
351
- tagName: '',
352
- selfClosing: false,
353
- attrs: []
354
- };
355
- };
404
+ //Tag attributes
405
+ _createAttr(attrNameFirstCh) {
406
+ this.currentAttr = {
407
+ name: attrNameFirstCh,
408
+ value: ''
409
+ };
410
+ }
356
411
 
357
- Tokenizer.prototype._createEndTagToken = function () {
358
- this.currentToken = {
359
- type: Tokenizer.END_TAG_TOKEN,
360
- tagName: '',
361
- attrs: []
362
- };
363
- };
412
+ _leaveAttrName(toState) {
413
+ if (Tokenizer.getTokenAttr(this.currentToken, this.currentAttr.name) === null) {
414
+ this.currentToken.attrs.push(this.currentAttr);
415
+ } else {
416
+ this._err(ERR.duplicateAttribute);
417
+ }
364
418
 
365
- Tokenizer.prototype._createCommentToken = function () {
366
- this.currentToken = {
367
- type: Tokenizer.COMMENT_TOKEN,
368
- data: ''
369
- };
370
- };
419
+ this.state = toState;
420
+ }
371
421
 
372
- Tokenizer.prototype._createDoctypeToken = function (initialName) {
373
- this.currentToken = {
374
- type: Tokenizer.DOCTYPE_TOKEN,
375
- name: initialName,
376
- forceQuirks: false,
377
- publicId: null,
378
- systemId: null
379
- };
380
- };
422
+ _leaveAttrValue(toState) {
423
+ this.state = toState;
424
+ }
381
425
 
382
- Tokenizer.prototype._createCharacterToken = function (type, ch) {
383
- this.currentCharacterToken = {
384
- type: type,
385
- chars: ch
386
- };
387
- };
426
+ //Token emission
427
+ _emitCurrentToken() {
428
+ this._emitCurrentCharacterToken();
388
429
 
389
- //Tag attributes
390
- Tokenizer.prototype._createAttr = function (attrNameFirstCh) {
391
- this.currentAttr = {
392
- name: attrNameFirstCh,
393
- value: ''
394
- };
395
- };
430
+ const ct = this.currentToken;
396
431
 
397
- Tokenizer.prototype._isDuplicateAttr = function () {
398
- return Tokenizer.getTokenAttr(this.currentToken, this.currentAttr.name) !== null;
399
- };
432
+ this.currentToken = null;
400
433
 
401
- Tokenizer.prototype._leaveAttrName = function (toState) {
402
- this.state = toState;
434
+ //NOTE: store emited start tag's tagName to determine is the following end tag token is appropriate.
435
+ if (ct.type === Tokenizer.START_TAG_TOKEN) {
436
+ this.lastStartTagName = ct.tagName;
437
+ } else if (ct.type === Tokenizer.END_TAG_TOKEN) {
438
+ if (ct.attrs.length > 0) {
439
+ this._err(ERR.endTagWithAttributes);
440
+ }
403
441
 
404
- if (!this._isDuplicateAttr())
405
- this.currentToken.attrs.push(this.currentAttr);
406
- };
442
+ if (ct.selfClosing) {
443
+ this._err(ERR.endTagWithTrailingSolidus);
444
+ }
445
+ }
407
446
 
408
- Tokenizer.prototype._leaveAttrValue = function (toState) {
409
- this.state = toState;
410
- };
447
+ this.tokenQueue.push(ct);
448
+ }
411
449
 
412
- //Appropriate end tag token
413
- //(see: http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#appropriate-end-tag-token)
414
- Tokenizer.prototype._isAppropriateEndTagToken = function () {
415
- return this.lastStartTagName === this.currentToken.tagName;
416
- };
450
+ _emitCurrentCharacterToken() {
451
+ if (this.currentCharacterToken) {
452
+ this.tokenQueue.push(this.currentCharacterToken);
453
+ this.currentCharacterToken = null;
454
+ }
455
+ }
417
456
 
418
- //Token emission
419
- Tokenizer.prototype._emitCurrentToken = function () {
420
- this._emitCurrentCharacterToken();
457
+ _emitEOFToken() {
458
+ this._createEOFToken();
459
+ this._emitCurrentToken();
460
+ }
421
461
 
422
- //NOTE: store emited start tag's tagName to determine is the following end tag token is appropriate.
423
- if (this.currentToken.type === Tokenizer.START_TAG_TOKEN)
424
- this.lastStartTagName = this.currentToken.tagName;
462
+ //Characters emission
425
463
 
426
- this.tokenQueue.push(this.currentToken);
427
- this.currentToken = null;
428
- };
464
+ //OPTIMIZATION: specification uses only one type of character tokens (one token per character).
465
+ //This causes a huge memory overhead and a lot of unnecessary parser loops. parse5 uses 3 groups of characters.
466
+ //If we have a sequence of characters that belong to the same group, parser can process it
467
+ //as a single solid character token.
468
+ //So, there are 3 types of character tokens in parse5:
469
+ //1)NULL_CHARACTER_TOKEN - \u0000-character sequences (e.g. '\u0000\u0000\u0000')
470
+ //2)WHITESPACE_CHARACTER_TOKEN - any whitespace/new-line character sequences (e.g. '\n \r\t \f')
471
+ //3)CHARACTER_TOKEN - any character sequence which don't belong to groups 1 and 2 (e.g. 'abcdef1234@@#$%^')
472
+ _appendCharToCurrentCharacterToken(type, ch) {
473
+ if (this.currentCharacterToken && this.currentCharacterToken.type !== type) {
474
+ this._emitCurrentCharacterToken();
475
+ }
429
476
 
430
- Tokenizer.prototype._emitCurrentCharacterToken = function () {
431
- if (this.currentCharacterToken) {
432
- this.tokenQueue.push(this.currentCharacterToken);
433
- this.currentCharacterToken = null;
477
+ if (this.currentCharacterToken) {
478
+ this.currentCharacterToken.chars += ch;
479
+ } else {
480
+ this._createCharacterToken(type, ch);
481
+ }
434
482
  }
435
- };
436
483
 
437
- Tokenizer.prototype._emitEOFToken = function () {
438
- this._emitCurrentCharacterToken();
439
- this.tokenQueue.push({type: Tokenizer.EOF_TOKEN});
440
- };
484
+ _emitCodePoint(cp) {
485
+ let type = Tokenizer.CHARACTER_TOKEN;
441
486
 
442
- //Characters emission
443
-
444
- //OPTIMIZATION: specification uses only one type of character tokens (one token per character).
445
- //This causes a huge memory overhead and a lot of unnecessary parser loops. parse5 uses 3 groups of characters.
446
- //If we have a sequence of characters that belong to the same group, parser can process it
447
- //as a single solid character token.
448
- //So, there are 3 types of character tokens in parse5:
449
- //1)NULL_CHARACTER_TOKEN - \u0000-character sequences (e.g. '\u0000\u0000\u0000')
450
- //2)WHITESPACE_CHARACTER_TOKEN - any whitespace/new-line character sequences (e.g. '\n \r\t \f')
451
- //3)CHARACTER_TOKEN - any character sequence which don't belong to groups 1 and 2 (e.g. 'abcdef1234@@#$%^')
452
- Tokenizer.prototype._appendCharToCurrentCharacterToken = function (type, ch) {
453
- if (this.currentCharacterToken && this.currentCharacterToken.type !== type)
454
- this._emitCurrentCharacterToken();
487
+ if (isWhitespace(cp)) {
488
+ type = Tokenizer.WHITESPACE_CHARACTER_TOKEN;
489
+ } else if (cp === $.NULL) {
490
+ type = Tokenizer.NULL_CHARACTER_TOKEN;
491
+ }
455
492
 
456
- if (this.currentCharacterToken)
457
- this.currentCharacterToken.chars += ch;
493
+ this._appendCharToCurrentCharacterToken(type, toChar(cp));
494
+ }
458
495
 
459
- else
460
- this._createCharacterToken(type, ch);
461
- };
496
+ _emitSeveralCodePoints(codePoints) {
497
+ for (let i = 0; i < codePoints.length; i++) {
498
+ this._emitCodePoint(codePoints[i]);
499
+ }
500
+ }
462
501
 
463
- Tokenizer.prototype._emitCodePoint = function (cp) {
464
- var type = Tokenizer.CHARACTER_TOKEN;
502
+ //NOTE: used then we emit character explicitly. This is always a non-whitespace and a non-null character.
503
+ //So we can avoid additional checks here.
504
+ _emitChars(ch) {
505
+ this._appendCharToCurrentCharacterToken(Tokenizer.CHARACTER_TOKEN, ch);
506
+ }
465
507
 
466
- if (isWhitespace(cp))
467
- type = Tokenizer.WHITESPACE_CHARACTER_TOKEN;
508
+ // Character reference helpers
509
+ _matchNamedCharacterReference(startCp) {
510
+ let result = null;
511
+ let excess = 1;
512
+ let i = findNamedEntityTreeBranch(0, startCp);
468
513
 
469
- else if (cp === $.NULL)
470
- type = Tokenizer.NULL_CHARACTER_TOKEN;
514
+ this.tempBuff.push(startCp);
471
515
 
472
- this._appendCharToCurrentCharacterToken(type, toChar(cp));
473
- };
516
+ while (i > -1) {
517
+ const current = neTree[i];
518
+ const inNode = current < MAX_BRANCH_MARKER_VALUE;
519
+ const nodeWithData = inNode && current & HAS_DATA_FLAG;
474
520
 
475
- Tokenizer.prototype._emitSeveralCodePoints = function (codePoints) {
476
- for (var i = 0; i < codePoints.length; i++)
477
- this._emitCodePoint(codePoints[i]);
478
- };
521
+ if (nodeWithData) {
522
+ //NOTE: we use greedy search, so we continue lookup at this point
523
+ result = current & DATA_DUPLET_FLAG ? [neTree[++i], neTree[++i]] : [neTree[++i]];
524
+ excess = 0;
525
+ }
479
526
 
480
- //NOTE: used then we emit character explicitly. This is always a non-whitespace and a non-null character.
481
- //So we can avoid additional checks here.
482
- Tokenizer.prototype._emitChar = function (ch) {
483
- this._appendCharToCurrentCharacterToken(Tokenizer.CHARACTER_TOKEN, ch);
484
- };
527
+ const cp = this._consume();
485
528
 
486
- //Character reference tokenization
487
- Tokenizer.prototype._consumeNumericEntity = function (isHex) {
488
- var digits = '',
489
- nextCp = void 0;
529
+ this.tempBuff.push(cp);
530
+ excess++;
490
531
 
491
- do {
492
- digits += toChar(this._consume());
493
- nextCp = this._lookahead();
494
- } while (nextCp !== $.EOF && isDigit(nextCp, isHex));
532
+ if (cp === $.EOF) {
533
+ break;
534
+ }
495
535
 
496
- if (this._lookahead() === $.SEMICOLON)
497
- this._consume();
536
+ if (inNode) {
537
+ i = current & HAS_BRANCHES_FLAG ? findNamedEntityTreeBranch(i, cp) : -1;
538
+ } else {
539
+ i = cp === current ? ++i : -1;
540
+ }
541
+ }
498
542
 
499
- var referencedCp = parseInt(digits, isHex ? 16 : 10),
500
- replacement = NUMERIC_ENTITY_REPLACEMENTS[referencedCp];
543
+ while (excess--) {
544
+ this.tempBuff.pop();
545
+ this._unconsume();
546
+ }
501
547
 
502
- if (replacement)
503
- return replacement;
548
+ return result;
549
+ }
504
550
 
505
- if (isReservedCodePoint(referencedCp))
506
- return $.REPLACEMENT_CHARACTER;
551
+ _isCharacterReferenceInAttribute() {
552
+ return (
553
+ this.returnState === ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE ||
554
+ this.returnState === ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE ||
555
+ this.returnState === ATTRIBUTE_VALUE_UNQUOTED_STATE
556
+ );
557
+ }
507
558
 
508
- return referencedCp;
509
- };
559
+ _isCharacterReferenceAttributeQuirk(withSemicolon) {
560
+ if (!withSemicolon && this._isCharacterReferenceInAttribute()) {
561
+ const nextCp = this._consume();
510
562
 
511
- // NOTE: for the details on this algorithm see
512
- // https://github.com/inikulin/parse5/tree/master/scripts/generate_named_entity_data/README.md
513
- Tokenizer.prototype._consumeNamedEntity = function (inAttr) {
514
- var referencedCodePoints = null,
515
- referenceSize = 0,
516
- cp = null,
517
- consumedCount = 0,
518
- semicolonTerminated = false;
563
+ this._unconsume();
519
564
 
520
- for (var i = 0; i > -1;) {
521
- var current = neTree[i],
522
- inNode = current < MAX_BRANCH_MARKER_VALUE,
523
- nodeWithData = inNode && current & HAS_DATA_FLAG;
565
+ return nextCp === $.EQUALS_SIGN || isAsciiAlphaNumeric(nextCp);
566
+ }
524
567
 
525
- if (nodeWithData) {
526
- referencedCodePoints = current & DATA_DUPLET_FLAG ? [neTree[++i], neTree[++i]] : [neTree[++i]];
527
- referenceSize = consumedCount;
568
+ return false;
569
+ }
528
570
 
529
- if (cp === $.SEMICOLON) {
530
- semicolonTerminated = true;
531
- break;
571
+ _flushCodePointsConsumedAsCharacterReference() {
572
+ if (this._isCharacterReferenceInAttribute()) {
573
+ for (let i = 0; i < this.tempBuff.length; i++) {
574
+ this.currentAttr.value += toChar(this.tempBuff[i]);
532
575
  }
576
+ } else {
577
+ this._emitSeveralCodePoints(this.tempBuff);
533
578
  }
534
579
 
535
- cp = this._consume();
536
- consumedCount++;
580
+ this.tempBuff = [];
581
+ }
537
582
 
538
- if (cp === $.EOF)
539
- break;
583
+ // State machine
540
584
 
541
- if (inNode)
542
- i = current & HAS_BRANCHES_FLAG ? findNamedEntityTreeBranch(i, cp) : -1;
585
+ // Data state
586
+ //------------------------------------------------------------------
587
+ [DATA_STATE](cp) {
588
+ this.preprocessor.dropParsedChunk();
543
589
 
544
- else
545
- i = cp === current ? ++i : -1;
590
+ if (cp === $.LESS_THAN_SIGN) {
591
+ this.state = TAG_OPEN_STATE;
592
+ } else if (cp === $.AMPERSAND) {
593
+ this.returnState = DATA_STATE;
594
+ this.state = CHARACTER_REFERENCE_STATE;
595
+ } else if (cp === $.NULL) {
596
+ this._err(ERR.unexpectedNullCharacter);
597
+ this._emitCodePoint(cp);
598
+ } else if (cp === $.EOF) {
599
+ this._emitEOFToken();
600
+ } else {
601
+ this._emitCodePoint(cp);
602
+ }
546
603
  }
547
604
 
605
+ // RCDATA state
606
+ //------------------------------------------------------------------
607
+ [RCDATA_STATE](cp) {
608
+ this.preprocessor.dropParsedChunk();
609
+
610
+ if (cp === $.AMPERSAND) {
611
+ this.returnState = RCDATA_STATE;
612
+ this.state = CHARACTER_REFERENCE_STATE;
613
+ } else if (cp === $.LESS_THAN_SIGN) {
614
+ this.state = RCDATA_LESS_THAN_SIGN_STATE;
615
+ } else if (cp === $.NULL) {
616
+ this._err(ERR.unexpectedNullCharacter);
617
+ this._emitChars(unicode.REPLACEMENT_CHARACTER);
618
+ } else if (cp === $.EOF) {
619
+ this._emitEOFToken();
620
+ } else {
621
+ this._emitCodePoint(cp);
622
+ }
623
+ }
548
624
 
549
- if (referencedCodePoints) {
550
- if (!semicolonTerminated) {
551
- //NOTE: unconsume excess (e.g. 'it' in '&notit')
552
- this._unconsumeSeveral(consumedCount - referenceSize);
553
-
554
- //NOTE: If the character reference is being consumed as part of an attribute and the next character
555
- //is either a U+003D EQUALS SIGN character (=) or an alphanumeric ASCII character, then, for historical
556
- //reasons, all the characters that were matched after the U+0026 AMPERSAND character (&) must be
557
- //unconsumed, and nothing is returned.
558
- //However, if this next character is in fact a U+003D EQUALS SIGN character (=), then this is a
559
- //parse error, because some legacy user agents will misinterpret the markup in those cases.
560
- //(see: http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#tokenizing-character-references)
561
- if (inAttr) {
562
- var nextCp = this._lookahead();
625
+ // RAWTEXT state
626
+ //------------------------------------------------------------------
627
+ [RAWTEXT_STATE](cp) {
628
+ this.preprocessor.dropParsedChunk();
563
629
 
564
- if (nextCp === $.EQUALS_SIGN || isAsciiAlphaNumeric(nextCp)) {
565
- this._unconsumeSeveral(referenceSize);
566
- return null;
567
- }
568
- }
630
+ if (cp === $.LESS_THAN_SIGN) {
631
+ this.state = RAWTEXT_LESS_THAN_SIGN_STATE;
632
+ } else if (cp === $.NULL) {
633
+ this._err(ERR.unexpectedNullCharacter);
634
+ this._emitChars(unicode.REPLACEMENT_CHARACTER);
635
+ } else if (cp === $.EOF) {
636
+ this._emitEOFToken();
637
+ } else {
638
+ this._emitCodePoint(cp);
569
639
  }
570
-
571
- return referencedCodePoints;
572
640
  }
573
641
 
574
- this._unconsumeSeveral(consumedCount);
575
-
576
- return null;
577
- };
642
+ // Script data state
643
+ //------------------------------------------------------------------
644
+ [SCRIPT_DATA_STATE](cp) {
645
+ this.preprocessor.dropParsedChunk();
578
646
 
579
- Tokenizer.prototype._consumeCharacterReference = function (startCp, inAttr) {
580
- if (isWhitespace(startCp) || startCp === $.GREATER_THAN_SIGN ||
581
- startCp === $.AMPERSAND || startCp === this.additionalAllowedCp || startCp === $.EOF) {
582
- //NOTE: not a character reference. No characters are consumed, and nothing is returned.
583
- this._unconsume();
584
- return null;
647
+ if (cp === $.LESS_THAN_SIGN) {
648
+ this.state = SCRIPT_DATA_LESS_THAN_SIGN_STATE;
649
+ } else if (cp === $.NULL) {
650
+ this._err(ERR.unexpectedNullCharacter);
651
+ this._emitChars(unicode.REPLACEMENT_CHARACTER);
652
+ } else if (cp === $.EOF) {
653
+ this._emitEOFToken();
654
+ } else {
655
+ this._emitCodePoint(cp);
656
+ }
585
657
  }
586
658
 
587
- if (startCp === $.NUMBER_SIGN) {
588
- //NOTE: we have a numeric entity candidate, now we should determine if it's hex or decimal
589
- var isHex = false,
590
- nextCp = this._lookahead();
659
+ // PLAINTEXT state
660
+ //------------------------------------------------------------------
661
+ [PLAINTEXT_STATE](cp) {
662
+ this.preprocessor.dropParsedChunk();
591
663
 
592
- if (nextCp === $.LATIN_SMALL_X || nextCp === $.LATIN_CAPITAL_X) {
593
- this._consume();
594
- isHex = true;
664
+ if (cp === $.NULL) {
665
+ this._err(ERR.unexpectedNullCharacter);
666
+ this._emitChars(unicode.REPLACEMENT_CHARACTER);
667
+ } else if (cp === $.EOF) {
668
+ this._emitEOFToken();
669
+ } else {
670
+ this._emitCodePoint(cp);
595
671
  }
672
+ }
596
673
 
597
- nextCp = this._lookahead();
598
-
599
- //NOTE: if we have at least one digit this is a numeric entity for sure, so we consume it
600
- if (nextCp !== $.EOF && isDigit(nextCp, isHex))
601
- return [this._consumeNumericEntity(isHex)];
674
+ // Tag open state
675
+ //------------------------------------------------------------------
676
+ [TAG_OPEN_STATE](cp) {
677
+ if (cp === $.EXCLAMATION_MARK) {
678
+ this.state = MARKUP_DECLARATION_OPEN_STATE;
679
+ } else if (cp === $.SOLIDUS) {
680
+ this.state = END_TAG_OPEN_STATE;
681
+ } else if (isAsciiLetter(cp)) {
682
+ this._createStartTagToken();
683
+ this._reconsumeInState(TAG_NAME_STATE);
684
+ } else if (cp === $.QUESTION_MARK) {
685
+ this._err(ERR.unexpectedQuestionMarkInsteadOfTagName);
686
+ this._createCommentToken();
687
+ this._reconsumeInState(BOGUS_COMMENT_STATE);
688
+ } else if (cp === $.EOF) {
689
+ this._err(ERR.eofBeforeTagName);
690
+ this._emitChars('<');
691
+ this._emitEOFToken();
692
+ } else {
693
+ this._err(ERR.invalidFirstCharacterOfTagName);
694
+ this._emitChars('<');
695
+ this._reconsumeInState(DATA_STATE);
696
+ }
697
+ }
602
698
 
603
- //NOTE: otherwise this is a bogus number entity and a parse error. Unconsume the number sign
604
- //and the 'x'-character if appropriate.
605
- this._unconsumeSeveral(isHex ? 2 : 1);
606
- return null;
699
+ // End tag open state
700
+ //------------------------------------------------------------------
701
+ [END_TAG_OPEN_STATE](cp) {
702
+ if (isAsciiLetter(cp)) {
703
+ this._createEndTagToken();
704
+ this._reconsumeInState(TAG_NAME_STATE);
705
+ } else if (cp === $.GREATER_THAN_SIGN) {
706
+ this._err(ERR.missingEndTagName);
707
+ this.state = DATA_STATE;
708
+ } else if (cp === $.EOF) {
709
+ this._err(ERR.eofBeforeTagName);
710
+ this._emitChars('</');
711
+ this._emitEOFToken();
712
+ } else {
713
+ this._err(ERR.invalidFirstCharacterOfTagName);
714
+ this._createCommentToken();
715
+ this._reconsumeInState(BOGUS_COMMENT_STATE);
716
+ }
607
717
  }
608
718
 
609
- this._unconsume();
719
+ // Tag name state
720
+ //------------------------------------------------------------------
721
+ [TAG_NAME_STATE](cp) {
722
+ if (isWhitespace(cp)) {
723
+ this.state = BEFORE_ATTRIBUTE_NAME_STATE;
724
+ } else if (cp === $.SOLIDUS) {
725
+ this.state = SELF_CLOSING_START_TAG_STATE;
726
+ } else if (cp === $.GREATER_THAN_SIGN) {
727
+ this.state = DATA_STATE;
728
+ this._emitCurrentToken();
729
+ } else if (isAsciiUpper(cp)) {
730
+ this.currentToken.tagName += toAsciiLowerChar(cp);
731
+ } else if (cp === $.NULL) {
732
+ this._err(ERR.unexpectedNullCharacter);
733
+ this.currentToken.tagName += unicode.REPLACEMENT_CHARACTER;
734
+ } else if (cp === $.EOF) {
735
+ this._err(ERR.eofInTag);
736
+ this._emitEOFToken();
737
+ } else {
738
+ this.currentToken.tagName += toChar(cp);
739
+ }
740
+ }
610
741
 
611
- return this._consumeNamedEntity(inAttr);
612
- };
742
+ // RCDATA less-than sign state
743
+ //------------------------------------------------------------------
744
+ [RCDATA_LESS_THAN_SIGN_STATE](cp) {
745
+ if (cp === $.SOLIDUS) {
746
+ this.tempBuff = [];
747
+ this.state = RCDATA_END_TAG_OPEN_STATE;
748
+ } else {
749
+ this._emitChars('<');
750
+ this._reconsumeInState(RCDATA_STATE);
751
+ }
752
+ }
613
753
 
614
- //State machine
615
- var _ = Tokenizer.prototype;
754
+ // RCDATA end tag open state
755
+ //------------------------------------------------------------------
756
+ [RCDATA_END_TAG_OPEN_STATE](cp) {
757
+ if (isAsciiLetter(cp)) {
758
+ this._createEndTagToken();
759
+ this._reconsumeInState(RCDATA_END_TAG_NAME_STATE);
760
+ } else {
761
+ this._emitChars('</');
762
+ this._reconsumeInState(RCDATA_STATE);
763
+ }
764
+ }
616
765
 
617
- //12.2.4.1 Data state
618
- //------------------------------------------------------------------
619
- _[DATA_STATE] = function dataState(cp) {
620
- this.preprocessor.dropParsedChunk();
766
+ // RCDATA end tag name state
767
+ //------------------------------------------------------------------
768
+ [RCDATA_END_TAG_NAME_STATE](cp) {
769
+ if (isAsciiUpper(cp)) {
770
+ this.currentToken.tagName += toAsciiLowerChar(cp);
771
+ this.tempBuff.push(cp);
772
+ } else if (isAsciiLower(cp)) {
773
+ this.currentToken.tagName += toChar(cp);
774
+ this.tempBuff.push(cp);
775
+ } else {
776
+ if (this.lastStartTagName === this.currentToken.tagName) {
777
+ if (isWhitespace(cp)) {
778
+ this.state = BEFORE_ATTRIBUTE_NAME_STATE;
779
+ return;
780
+ }
621
781
 
622
- if (cp === $.AMPERSAND)
623
- this.state = CHARACTER_REFERENCE_IN_DATA_STATE;
782
+ if (cp === $.SOLIDUS) {
783
+ this.state = SELF_CLOSING_START_TAG_STATE;
784
+ return;
785
+ }
624
786
 
625
- else if (cp === $.LESS_THAN_SIGN)
626
- this.state = TAG_OPEN_STATE;
787
+ if (cp === $.GREATER_THAN_SIGN) {
788
+ this.state = DATA_STATE;
789
+ this._emitCurrentToken();
790
+ return;
791
+ }
792
+ }
627
793
 
628
- else if (cp === $.NULL)
629
- this._emitCodePoint(cp);
794
+ this._emitChars('</');
795
+ this._emitSeveralCodePoints(this.tempBuff);
796
+ this._reconsumeInState(RCDATA_STATE);
797
+ }
798
+ }
630
799
 
631
- else if (cp === $.EOF)
632
- this._emitEOFToken();
800
+ // RAWTEXT less-than sign state
801
+ //------------------------------------------------------------------
802
+ [RAWTEXT_LESS_THAN_SIGN_STATE](cp) {
803
+ if (cp === $.SOLIDUS) {
804
+ this.tempBuff = [];
805
+ this.state = RAWTEXT_END_TAG_OPEN_STATE;
806
+ } else {
807
+ this._emitChars('<');
808
+ this._reconsumeInState(RAWTEXT_STATE);
809
+ }
810
+ }
633
811
 
634
- else
635
- this._emitCodePoint(cp);
636
- };
812
+ // RAWTEXT end tag open state
813
+ //------------------------------------------------------------------
814
+ [RAWTEXT_END_TAG_OPEN_STATE](cp) {
815
+ if (isAsciiLetter(cp)) {
816
+ this._createEndTagToken();
817
+ this._reconsumeInState(RAWTEXT_END_TAG_NAME_STATE);
818
+ } else {
819
+ this._emitChars('</');
820
+ this._reconsumeInState(RAWTEXT_STATE);
821
+ }
822
+ }
637
823
 
824
+ // RAWTEXT end tag name state
825
+ //------------------------------------------------------------------
826
+ [RAWTEXT_END_TAG_NAME_STATE](cp) {
827
+ if (isAsciiUpper(cp)) {
828
+ this.currentToken.tagName += toAsciiLowerChar(cp);
829
+ this.tempBuff.push(cp);
830
+ } else if (isAsciiLower(cp)) {
831
+ this.currentToken.tagName += toChar(cp);
832
+ this.tempBuff.push(cp);
833
+ } else {
834
+ if (this.lastStartTagName === this.currentToken.tagName) {
835
+ if (isWhitespace(cp)) {
836
+ this.state = BEFORE_ATTRIBUTE_NAME_STATE;
837
+ return;
838
+ }
638
839
 
639
- //12.2.4.2 Character reference in data state
640
- //------------------------------------------------------------------
641
- _[CHARACTER_REFERENCE_IN_DATA_STATE] = function characterReferenceInDataState(cp) {
642
- this.additionalAllowedCp = void 0;
840
+ if (cp === $.SOLIDUS) {
841
+ this.state = SELF_CLOSING_START_TAG_STATE;
842
+ return;
843
+ }
643
844
 
644
- var referencedCodePoints = this._consumeCharacterReference(cp, false);
845
+ if (cp === $.GREATER_THAN_SIGN) {
846
+ this._emitCurrentToken();
847
+ this.state = DATA_STATE;
848
+ return;
849
+ }
850
+ }
645
851
 
646
- if (!this._ensureHibernation()) {
647
- if (referencedCodePoints)
648
- this._emitSeveralCodePoints(referencedCodePoints);
852
+ this._emitChars('</');
853
+ this._emitSeveralCodePoints(this.tempBuff);
854
+ this._reconsumeInState(RAWTEXT_STATE);
855
+ }
856
+ }
649
857
 
650
- else
651
- this._emitChar('&');
858
+ // Script data less-than sign state
859
+ //------------------------------------------------------------------
860
+ [SCRIPT_DATA_LESS_THAN_SIGN_STATE](cp) {
861
+ if (cp === $.SOLIDUS) {
862
+ this.tempBuff = [];
863
+ this.state = SCRIPT_DATA_END_TAG_OPEN_STATE;
864
+ } else if (cp === $.EXCLAMATION_MARK) {
865
+ this.state = SCRIPT_DATA_ESCAPE_START_STATE;
866
+ this._emitChars('<!');
867
+ } else {
868
+ this._emitChars('<');
869
+ this._reconsumeInState(SCRIPT_DATA_STATE);
870
+ }
871
+ }
652
872
 
653
- this.state = DATA_STATE;
873
+ // Script data end tag open state
874
+ //------------------------------------------------------------------
875
+ [SCRIPT_DATA_END_TAG_OPEN_STATE](cp) {
876
+ if (isAsciiLetter(cp)) {
877
+ this._createEndTagToken();
878
+ this._reconsumeInState(SCRIPT_DATA_END_TAG_NAME_STATE);
879
+ } else {
880
+ this._emitChars('</');
881
+ this._reconsumeInState(SCRIPT_DATA_STATE);
882
+ }
654
883
  }
655
- };
656
884
 
885
+ // Script data end tag name state
886
+ //------------------------------------------------------------------
887
+ [SCRIPT_DATA_END_TAG_NAME_STATE](cp) {
888
+ if (isAsciiUpper(cp)) {
889
+ this.currentToken.tagName += toAsciiLowerChar(cp);
890
+ this.tempBuff.push(cp);
891
+ } else if (isAsciiLower(cp)) {
892
+ this.currentToken.tagName += toChar(cp);
893
+ this.tempBuff.push(cp);
894
+ } else {
895
+ if (this.lastStartTagName === this.currentToken.tagName) {
896
+ if (isWhitespace(cp)) {
897
+ this.state = BEFORE_ATTRIBUTE_NAME_STATE;
898
+ return;
899
+ } else if (cp === $.SOLIDUS) {
900
+ this.state = SELF_CLOSING_START_TAG_STATE;
901
+ return;
902
+ } else if (cp === $.GREATER_THAN_SIGN) {
903
+ this._emitCurrentToken();
904
+ this.state = DATA_STATE;
905
+ return;
906
+ }
907
+ }
657
908
 
658
- //12.2.4.3 RCDATA state
659
- //------------------------------------------------------------------
660
- _[RCDATA_STATE] = function rcdataState(cp) {
661
- this.preprocessor.dropParsedChunk();
909
+ this._emitChars('</');
910
+ this._emitSeveralCodePoints(this.tempBuff);
911
+ this._reconsumeInState(SCRIPT_DATA_STATE);
912
+ }
913
+ }
662
914
 
663
- if (cp === $.AMPERSAND)
664
- this.state = CHARACTER_REFERENCE_IN_RCDATA_STATE;
915
+ // Script data escape start state
916
+ //------------------------------------------------------------------
917
+ [SCRIPT_DATA_ESCAPE_START_STATE](cp) {
918
+ if (cp === $.HYPHEN_MINUS) {
919
+ this.state = SCRIPT_DATA_ESCAPE_START_DASH_STATE;
920
+ this._emitChars('-');
921
+ } else {
922
+ this._reconsumeInState(SCRIPT_DATA_STATE);
923
+ }
924
+ }
665
925
 
666
- else if (cp === $.LESS_THAN_SIGN)
667
- this.state = RCDATA_LESS_THAN_SIGN_STATE;
926
+ // Script data escape start dash state
927
+ //------------------------------------------------------------------
928
+ [SCRIPT_DATA_ESCAPE_START_DASH_STATE](cp) {
929
+ if (cp === $.HYPHEN_MINUS) {
930
+ this.state = SCRIPT_DATA_ESCAPED_DASH_DASH_STATE;
931
+ this._emitChars('-');
932
+ } else {
933
+ this._reconsumeInState(SCRIPT_DATA_STATE);
934
+ }
935
+ }
668
936
 
669
- else if (cp === $.NULL)
670
- this._emitChar(UNICODE.REPLACEMENT_CHARACTER);
937
+ // Script data escaped state
938
+ //------------------------------------------------------------------
939
+ [SCRIPT_DATA_ESCAPED_STATE](cp) {
940
+ if (cp === $.HYPHEN_MINUS) {
941
+ this.state = SCRIPT_DATA_ESCAPED_DASH_STATE;
942
+ this._emitChars('-');
943
+ } else if (cp === $.LESS_THAN_SIGN) {
944
+ this.state = SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN_STATE;
945
+ } else if (cp === $.NULL) {
946
+ this._err(ERR.unexpectedNullCharacter);
947
+ this._emitChars(unicode.REPLACEMENT_CHARACTER);
948
+ } else if (cp === $.EOF) {
949
+ this._err(ERR.eofInScriptHtmlCommentLikeText);
950
+ this._emitEOFToken();
951
+ } else {
952
+ this._emitCodePoint(cp);
953
+ }
954
+ }
671
955
 
672
- else if (cp === $.EOF)
673
- this._emitEOFToken();
956
+ // Script data escaped dash state
957
+ //------------------------------------------------------------------
958
+ [SCRIPT_DATA_ESCAPED_DASH_STATE](cp) {
959
+ if (cp === $.HYPHEN_MINUS) {
960
+ this.state = SCRIPT_DATA_ESCAPED_DASH_DASH_STATE;
961
+ this._emitChars('-');
962
+ } else if (cp === $.LESS_THAN_SIGN) {
963
+ this.state = SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN_STATE;
964
+ } else if (cp === $.NULL) {
965
+ this._err(ERR.unexpectedNullCharacter);
966
+ this.state = SCRIPT_DATA_ESCAPED_STATE;
967
+ this._emitChars(unicode.REPLACEMENT_CHARACTER);
968
+ } else if (cp === $.EOF) {
969
+ this._err(ERR.eofInScriptHtmlCommentLikeText);
970
+ this._emitEOFToken();
971
+ } else {
972
+ this.state = SCRIPT_DATA_ESCAPED_STATE;
973
+ this._emitCodePoint(cp);
974
+ }
975
+ }
674
976
 
675
- else
676
- this._emitCodePoint(cp);
677
- };
977
+ // Script data escaped dash dash state
978
+ //------------------------------------------------------------------
979
+ [SCRIPT_DATA_ESCAPED_DASH_DASH_STATE](cp) {
980
+ if (cp === $.HYPHEN_MINUS) {
981
+ this._emitChars('-');
982
+ } else if (cp === $.LESS_THAN_SIGN) {
983
+ this.state = SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN_STATE;
984
+ } else if (cp === $.GREATER_THAN_SIGN) {
985
+ this.state = SCRIPT_DATA_STATE;
986
+ this._emitChars('>');
987
+ } else if (cp === $.NULL) {
988
+ this._err(ERR.unexpectedNullCharacter);
989
+ this.state = SCRIPT_DATA_ESCAPED_STATE;
990
+ this._emitChars(unicode.REPLACEMENT_CHARACTER);
991
+ } else if (cp === $.EOF) {
992
+ this._err(ERR.eofInScriptHtmlCommentLikeText);
993
+ this._emitEOFToken();
994
+ } else {
995
+ this.state = SCRIPT_DATA_ESCAPED_STATE;
996
+ this._emitCodePoint(cp);
997
+ }
998
+ }
678
999
 
1000
+ // Script data escaped less-than sign state
1001
+ //------------------------------------------------------------------
1002
+ [SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN_STATE](cp) {
1003
+ if (cp === $.SOLIDUS) {
1004
+ this.tempBuff = [];
1005
+ this.state = SCRIPT_DATA_ESCAPED_END_TAG_OPEN_STATE;
1006
+ } else if (isAsciiLetter(cp)) {
1007
+ this.tempBuff = [];
1008
+ this._emitChars('<');
1009
+ this._reconsumeInState(SCRIPT_DATA_DOUBLE_ESCAPE_START_STATE);
1010
+ } else {
1011
+ this._emitChars('<');
1012
+ this._reconsumeInState(SCRIPT_DATA_ESCAPED_STATE);
1013
+ }
1014
+ }
679
1015
 
680
- //12.2.4.4 Character reference in RCDATA state
681
- //------------------------------------------------------------------
682
- _[CHARACTER_REFERENCE_IN_RCDATA_STATE] = function characterReferenceInRcdataState(cp) {
683
- this.additionalAllowedCp = void 0;
1016
+ // Script data escaped end tag open state
1017
+ //------------------------------------------------------------------
1018
+ [SCRIPT_DATA_ESCAPED_END_TAG_OPEN_STATE](cp) {
1019
+ if (isAsciiLetter(cp)) {
1020
+ this._createEndTagToken();
1021
+ this._reconsumeInState(SCRIPT_DATA_ESCAPED_END_TAG_NAME_STATE);
1022
+ } else {
1023
+ this._emitChars('</');
1024
+ this._reconsumeInState(SCRIPT_DATA_ESCAPED_STATE);
1025
+ }
1026
+ }
684
1027
 
685
- var referencedCodePoints = this._consumeCharacterReference(cp, false);
1028
+ // Script data escaped end tag name state
1029
+ //------------------------------------------------------------------
1030
+ [SCRIPT_DATA_ESCAPED_END_TAG_NAME_STATE](cp) {
1031
+ if (isAsciiUpper(cp)) {
1032
+ this.currentToken.tagName += toAsciiLowerChar(cp);
1033
+ this.tempBuff.push(cp);
1034
+ } else if (isAsciiLower(cp)) {
1035
+ this.currentToken.tagName += toChar(cp);
1036
+ this.tempBuff.push(cp);
1037
+ } else {
1038
+ if (this.lastStartTagName === this.currentToken.tagName) {
1039
+ if (isWhitespace(cp)) {
1040
+ this.state = BEFORE_ATTRIBUTE_NAME_STATE;
1041
+ return;
1042
+ }
686
1043
 
687
- if (!this._ensureHibernation()) {
688
- if (referencedCodePoints)
689
- this._emitSeveralCodePoints(referencedCodePoints);
1044
+ if (cp === $.SOLIDUS) {
1045
+ this.state = SELF_CLOSING_START_TAG_STATE;
1046
+ return;
1047
+ }
690
1048
 
691
- else
692
- this._emitChar('&');
1049
+ if (cp === $.GREATER_THAN_SIGN) {
1050
+ this._emitCurrentToken();
1051
+ this.state = DATA_STATE;
1052
+ return;
1053
+ }
1054
+ }
693
1055
 
694
- this.state = RCDATA_STATE;
1056
+ this._emitChars('</');
1057
+ this._emitSeveralCodePoints(this.tempBuff);
1058
+ this._reconsumeInState(SCRIPT_DATA_ESCAPED_STATE);
1059
+ }
695
1060
  }
696
- };
697
1061
 
1062
+ // Script data double escape start state
1063
+ //------------------------------------------------------------------
1064
+ [SCRIPT_DATA_DOUBLE_ESCAPE_START_STATE](cp) {
1065
+ if (isWhitespace(cp) || cp === $.SOLIDUS || cp === $.GREATER_THAN_SIGN) {
1066
+ this.state = this._isTempBufferEqualToScriptString()
1067
+ ? SCRIPT_DATA_DOUBLE_ESCAPED_STATE
1068
+ : SCRIPT_DATA_ESCAPED_STATE;
1069
+ this._emitCodePoint(cp);
1070
+ } else if (isAsciiUpper(cp)) {
1071
+ this.tempBuff.push(toAsciiLowerCodePoint(cp));
1072
+ this._emitCodePoint(cp);
1073
+ } else if (isAsciiLower(cp)) {
1074
+ this.tempBuff.push(cp);
1075
+ this._emitCodePoint(cp);
1076
+ } else {
1077
+ this._reconsumeInState(SCRIPT_DATA_ESCAPED_STATE);
1078
+ }
1079
+ }
698
1080
 
699
- //12.2.4.5 RAWTEXT state
700
- //------------------------------------------------------------------
701
- _[RAWTEXT_STATE] = function rawtextState(cp) {
702
- this.preprocessor.dropParsedChunk();
703
-
704
- if (cp === $.LESS_THAN_SIGN)
705
- this.state = RAWTEXT_LESS_THAN_SIGN_STATE;
1081
+ // Script data double escaped state
1082
+ //------------------------------------------------------------------
1083
+ [SCRIPT_DATA_DOUBLE_ESCAPED_STATE](cp) {
1084
+ if (cp === $.HYPHEN_MINUS) {
1085
+ this.state = SCRIPT_DATA_DOUBLE_ESCAPED_DASH_STATE;
1086
+ this._emitChars('-');
1087
+ } else if (cp === $.LESS_THAN_SIGN) {
1088
+ this.state = SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN_STATE;
1089
+ this._emitChars('<');
1090
+ } else if (cp === $.NULL) {
1091
+ this._err(ERR.unexpectedNullCharacter);
1092
+ this._emitChars(unicode.REPLACEMENT_CHARACTER);
1093
+ } else if (cp === $.EOF) {
1094
+ this._err(ERR.eofInScriptHtmlCommentLikeText);
1095
+ this._emitEOFToken();
1096
+ } else {
1097
+ this._emitCodePoint(cp);
1098
+ }
1099
+ }
706
1100
 
707
- else if (cp === $.NULL)
708
- this._emitChar(UNICODE.REPLACEMENT_CHARACTER);
1101
+ // Script data double escaped dash state
1102
+ //------------------------------------------------------------------
1103
+ [SCRIPT_DATA_DOUBLE_ESCAPED_DASH_STATE](cp) {
1104
+ if (cp === $.HYPHEN_MINUS) {
1105
+ this.state = SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH_STATE;
1106
+ this._emitChars('-');
1107
+ } else if (cp === $.LESS_THAN_SIGN) {
1108
+ this.state = SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN_STATE;
1109
+ this._emitChars('<');
1110
+ } else if (cp === $.NULL) {
1111
+ this._err(ERR.unexpectedNullCharacter);
1112
+ this.state = SCRIPT_DATA_DOUBLE_ESCAPED_STATE;
1113
+ this._emitChars(unicode.REPLACEMENT_CHARACTER);
1114
+ } else if (cp === $.EOF) {
1115
+ this._err(ERR.eofInScriptHtmlCommentLikeText);
1116
+ this._emitEOFToken();
1117
+ } else {
1118
+ this.state = SCRIPT_DATA_DOUBLE_ESCAPED_STATE;
1119
+ this._emitCodePoint(cp);
1120
+ }
1121
+ }
709
1122
 
710
- else if (cp === $.EOF)
711
- this._emitEOFToken();
1123
+ // Script data double escaped dash dash state
1124
+ //------------------------------------------------------------------
1125
+ [SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH_STATE](cp) {
1126
+ if (cp === $.HYPHEN_MINUS) {
1127
+ this._emitChars('-');
1128
+ } else if (cp === $.LESS_THAN_SIGN) {
1129
+ this.state = SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN_STATE;
1130
+ this._emitChars('<');
1131
+ } else if (cp === $.GREATER_THAN_SIGN) {
1132
+ this.state = SCRIPT_DATA_STATE;
1133
+ this._emitChars('>');
1134
+ } else if (cp === $.NULL) {
1135
+ this._err(ERR.unexpectedNullCharacter);
1136
+ this.state = SCRIPT_DATA_DOUBLE_ESCAPED_STATE;
1137
+ this._emitChars(unicode.REPLACEMENT_CHARACTER);
1138
+ } else if (cp === $.EOF) {
1139
+ this._err(ERR.eofInScriptHtmlCommentLikeText);
1140
+ this._emitEOFToken();
1141
+ } else {
1142
+ this.state = SCRIPT_DATA_DOUBLE_ESCAPED_STATE;
1143
+ this._emitCodePoint(cp);
1144
+ }
1145
+ }
712
1146
 
713
- else
714
- this._emitCodePoint(cp);
715
- };
1147
+ // Script data double escaped less-than sign state
1148
+ //------------------------------------------------------------------
1149
+ [SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN_STATE](cp) {
1150
+ if (cp === $.SOLIDUS) {
1151
+ this.tempBuff = [];
1152
+ this.state = SCRIPT_DATA_DOUBLE_ESCAPE_END_STATE;
1153
+ this._emitChars('/');
1154
+ } else {
1155
+ this._reconsumeInState(SCRIPT_DATA_DOUBLE_ESCAPED_STATE);
1156
+ }
1157
+ }
716
1158
 
1159
+ // Script data double escape end state
1160
+ //------------------------------------------------------------------
1161
+ [SCRIPT_DATA_DOUBLE_ESCAPE_END_STATE](cp) {
1162
+ if (isWhitespace(cp) || cp === $.SOLIDUS || cp === $.GREATER_THAN_SIGN) {
1163
+ this.state = this._isTempBufferEqualToScriptString()
1164
+ ? SCRIPT_DATA_ESCAPED_STATE
1165
+ : SCRIPT_DATA_DOUBLE_ESCAPED_STATE;
717
1166
 
718
- //12.2.4.6 Script data state
719
- //------------------------------------------------------------------
720
- _[SCRIPT_DATA_STATE] = function scriptDataState(cp) {
721
- this.preprocessor.dropParsedChunk();
1167
+ this._emitCodePoint(cp);
1168
+ } else if (isAsciiUpper(cp)) {
1169
+ this.tempBuff.push(toAsciiLowerCodePoint(cp));
1170
+ this._emitCodePoint(cp);
1171
+ } else if (isAsciiLower(cp)) {
1172
+ this.tempBuff.push(cp);
1173
+ this._emitCodePoint(cp);
1174
+ } else {
1175
+ this._reconsumeInState(SCRIPT_DATA_DOUBLE_ESCAPED_STATE);
1176
+ }
1177
+ }
722
1178
 
723
- if (cp === $.LESS_THAN_SIGN)
724
- this.state = SCRIPT_DATA_LESS_THAN_SIGN_STATE;
1179
+ // Before attribute name state
1180
+ //------------------------------------------------------------------
1181
+ [BEFORE_ATTRIBUTE_NAME_STATE](cp) {
1182
+ if (isWhitespace(cp)) {
1183
+ return;
1184
+ }
725
1185
 
726
- else if (cp === $.NULL)
727
- this._emitChar(UNICODE.REPLACEMENT_CHARACTER);
1186
+ if (cp === $.SOLIDUS || cp === $.GREATER_THAN_SIGN || cp === $.EOF) {
1187
+ this._reconsumeInState(AFTER_ATTRIBUTE_NAME_STATE);
1188
+ } else if (cp === $.EQUALS_SIGN) {
1189
+ this._err(ERR.unexpectedEqualsSignBeforeAttributeName);
1190
+ this._createAttr('=');
1191
+ this.state = ATTRIBUTE_NAME_STATE;
1192
+ } else {
1193
+ this._createAttr('');
1194
+ this._reconsumeInState(ATTRIBUTE_NAME_STATE);
1195
+ }
1196
+ }
728
1197
 
729
- else if (cp === $.EOF)
730
- this._emitEOFToken();
731
-
732
- else
733
- this._emitCodePoint(cp);
734
- };
735
-
736
-
737
- //12.2.4.7 PLAINTEXT state
738
- //------------------------------------------------------------------
739
- _[PLAINTEXT_STATE] = function plaintextState(cp) {
740
- this.preprocessor.dropParsedChunk();
741
-
742
- if (cp === $.NULL)
743
- this._emitChar(UNICODE.REPLACEMENT_CHARACTER);
744
-
745
- else if (cp === $.EOF)
746
- this._emitEOFToken();
747
-
748
- else
749
- this._emitCodePoint(cp);
750
- };
751
-
752
-
753
- //12.2.4.8 Tag open state
754
- //------------------------------------------------------------------
755
- _[TAG_OPEN_STATE] = function tagOpenState(cp) {
756
- if (cp === $.EXCLAMATION_MARK)
757
- this.state = MARKUP_DECLARATION_OPEN_STATE;
758
-
759
- else if (cp === $.SOLIDUS)
760
- this.state = END_TAG_OPEN_STATE;
761
-
762
- else if (isAsciiLetter(cp)) {
763
- this._createStartTagToken();
764
- this._reconsumeInState(TAG_NAME_STATE);
765
- }
766
-
767
- else if (cp === $.QUESTION_MARK)
768
- this._reconsumeInState(BOGUS_COMMENT_STATE);
769
-
770
- else {
771
- this._emitChar('<');
772
- this._reconsumeInState(DATA_STATE);
773
- }
774
- };
775
-
776
-
777
- //12.2.4.9 End tag open state
778
- //------------------------------------------------------------------
779
- _[END_TAG_OPEN_STATE] = function endTagOpenState(cp) {
780
- if (isAsciiLetter(cp)) {
781
- this._createEndTagToken();
782
- this._reconsumeInState(TAG_NAME_STATE);
1198
+ // Attribute name state
1199
+ //------------------------------------------------------------------
1200
+ [ATTRIBUTE_NAME_STATE](cp) {
1201
+ if (isWhitespace(cp) || cp === $.SOLIDUS || cp === $.GREATER_THAN_SIGN || cp === $.EOF) {
1202
+ this._leaveAttrName(AFTER_ATTRIBUTE_NAME_STATE);
1203
+ this._unconsume();
1204
+ } else if (cp === $.EQUALS_SIGN) {
1205
+ this._leaveAttrName(BEFORE_ATTRIBUTE_VALUE_STATE);
1206
+ } else if (isAsciiUpper(cp)) {
1207
+ this.currentAttr.name += toAsciiLowerChar(cp);
1208
+ } else if (cp === $.QUOTATION_MARK || cp === $.APOSTROPHE || cp === $.LESS_THAN_SIGN) {
1209
+ this._err(ERR.unexpectedCharacterInAttributeName);
1210
+ this.currentAttr.name += toChar(cp);
1211
+ } else if (cp === $.NULL) {
1212
+ this._err(ERR.unexpectedNullCharacter);
1213
+ this.currentAttr.name += unicode.REPLACEMENT_CHARACTER;
1214
+ } else {
1215
+ this.currentAttr.name += toChar(cp);
1216
+ }
783
1217
  }
784
1218
 
785
- else if (cp === $.GREATER_THAN_SIGN)
786
- this.state = DATA_STATE;
1219
+ // After attribute name state
1220
+ //------------------------------------------------------------------
1221
+ [AFTER_ATTRIBUTE_NAME_STATE](cp) {
1222
+ if (isWhitespace(cp)) {
1223
+ return;
1224
+ }
787
1225
 
788
- else if (cp === $.EOF) {
789
- this._reconsumeInState(DATA_STATE);
790
- this._emitChar('<');
791
- this._emitChar('/');
1226
+ if (cp === $.SOLIDUS) {
1227
+ this.state = SELF_CLOSING_START_TAG_STATE;
1228
+ } else if (cp === $.EQUALS_SIGN) {
1229
+ this.state = BEFORE_ATTRIBUTE_VALUE_STATE;
1230
+ } else if (cp === $.GREATER_THAN_SIGN) {
1231
+ this.state = DATA_STATE;
1232
+ this._emitCurrentToken();
1233
+ } else if (cp === $.EOF) {
1234
+ this._err(ERR.eofInTag);
1235
+ this._emitEOFToken();
1236
+ } else {
1237
+ this._createAttr('');
1238
+ this._reconsumeInState(ATTRIBUTE_NAME_STATE);
1239
+ }
792
1240
  }
793
1241
 
794
- else
795
- this._reconsumeInState(BOGUS_COMMENT_STATE);
796
- };
797
-
798
-
799
- //12.2.4.10 Tag name state
800
- //------------------------------------------------------------------
801
- _[TAG_NAME_STATE] = function tagNameState(cp) {
802
- if (isWhitespace(cp))
803
- this.state = BEFORE_ATTRIBUTE_NAME_STATE;
804
-
805
- else if (cp === $.SOLIDUS)
806
- this.state = SELF_CLOSING_START_TAG_STATE;
1242
+ // Before attribute value state
1243
+ //------------------------------------------------------------------
1244
+ [BEFORE_ATTRIBUTE_VALUE_STATE](cp) {
1245
+ if (isWhitespace(cp)) {
1246
+ return;
1247
+ }
807
1248
 
808
- else if (cp === $.GREATER_THAN_SIGN) {
809
- this.state = DATA_STATE;
810
- this._emitCurrentToken();
1249
+ if (cp === $.QUOTATION_MARK) {
1250
+ this.state = ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE;
1251
+ } else if (cp === $.APOSTROPHE) {
1252
+ this.state = ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE;
1253
+ } else if (cp === $.GREATER_THAN_SIGN) {
1254
+ this._err(ERR.missingAttributeValue);
1255
+ this.state = DATA_STATE;
1256
+ this._emitCurrentToken();
1257
+ } else {
1258
+ this._reconsumeInState(ATTRIBUTE_VALUE_UNQUOTED_STATE);
1259
+ }
811
1260
  }
812
1261
 
813
- else if (isAsciiUpper(cp))
814
- this.currentToken.tagName += toAsciiLowerChar(cp);
815
-
816
- else if (cp === $.NULL)
817
- this.currentToken.tagName += UNICODE.REPLACEMENT_CHARACTER;
818
-
819
- else if (cp === $.EOF)
820
- this._reconsumeInState(DATA_STATE);
821
-
822
- else
823
- this.currentToken.tagName += toChar(cp);
824
- };
825
-
826
-
827
- //12.2.4.11 RCDATA less-than sign state
828
- //------------------------------------------------------------------
829
- _[RCDATA_LESS_THAN_SIGN_STATE] = function rcdataLessThanSignState(cp) {
830
- if (cp === $.SOLIDUS) {
831
- this.tempBuff = [];
832
- this.state = RCDATA_END_TAG_OPEN_STATE;
1262
+ // Attribute value (double-quoted) state
1263
+ //------------------------------------------------------------------
1264
+ [ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE](cp) {
1265
+ if (cp === $.QUOTATION_MARK) {
1266
+ this.state = AFTER_ATTRIBUTE_VALUE_QUOTED_STATE;
1267
+ } else if (cp === $.AMPERSAND) {
1268
+ this.returnState = ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE;
1269
+ this.state = CHARACTER_REFERENCE_STATE;
1270
+ } else if (cp === $.NULL) {
1271
+ this._err(ERR.unexpectedNullCharacter);
1272
+ this.currentAttr.value += unicode.REPLACEMENT_CHARACTER;
1273
+ } else if (cp === $.EOF) {
1274
+ this._err(ERR.eofInTag);
1275
+ this._emitEOFToken();
1276
+ } else {
1277
+ this.currentAttr.value += toChar(cp);
1278
+ }
833
1279
  }
834
1280
 
835
- else {
836
- this._emitChar('<');
837
- this._reconsumeInState(RCDATA_STATE);
1281
+ // Attribute value (single-quoted) state
1282
+ //------------------------------------------------------------------
1283
+ [ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE](cp) {
1284
+ if (cp === $.APOSTROPHE) {
1285
+ this.state = AFTER_ATTRIBUTE_VALUE_QUOTED_STATE;
1286
+ } else if (cp === $.AMPERSAND) {
1287
+ this.returnState = ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE;
1288
+ this.state = CHARACTER_REFERENCE_STATE;
1289
+ } else if (cp === $.NULL) {
1290
+ this._err(ERR.unexpectedNullCharacter);
1291
+ this.currentAttr.value += unicode.REPLACEMENT_CHARACTER;
1292
+ } else if (cp === $.EOF) {
1293
+ this._err(ERR.eofInTag);
1294
+ this._emitEOFToken();
1295
+ } else {
1296
+ this.currentAttr.value += toChar(cp);
1297
+ }
838
1298
  }
839
- };
840
-
841
1299
 
842
- //12.2.4.12 RCDATA end tag open state
843
- //------------------------------------------------------------------
844
- _[RCDATA_END_TAG_OPEN_STATE] = function rcdataEndTagOpenState(cp) {
845
- if (isAsciiLetter(cp)) {
846
- this._createEndTagToken();
847
- this._reconsumeInState(RCDATA_END_TAG_NAME_STATE);
1300
+ // Attribute value (unquoted) state
1301
+ //------------------------------------------------------------------
1302
+ [ATTRIBUTE_VALUE_UNQUOTED_STATE](cp) {
1303
+ if (isWhitespace(cp)) {
1304
+ this._leaveAttrValue(BEFORE_ATTRIBUTE_NAME_STATE);
1305
+ } else if (cp === $.AMPERSAND) {
1306
+ this.returnState = ATTRIBUTE_VALUE_UNQUOTED_STATE;
1307
+ this.state = CHARACTER_REFERENCE_STATE;
1308
+ } else if (cp === $.GREATER_THAN_SIGN) {
1309
+ this._leaveAttrValue(DATA_STATE);
1310
+ this._emitCurrentToken();
1311
+ } else if (cp === $.NULL) {
1312
+ this._err(ERR.unexpectedNullCharacter);
1313
+ this.currentAttr.value += unicode.REPLACEMENT_CHARACTER;
1314
+ } else if (
1315
+ cp === $.QUOTATION_MARK ||
1316
+ cp === $.APOSTROPHE ||
1317
+ cp === $.LESS_THAN_SIGN ||
1318
+ cp === $.EQUALS_SIGN ||
1319
+ cp === $.GRAVE_ACCENT
1320
+ ) {
1321
+ this._err(ERR.unexpectedCharacterInUnquotedAttributeValue);
1322
+ this.currentAttr.value += toChar(cp);
1323
+ } else if (cp === $.EOF) {
1324
+ this._err(ERR.eofInTag);
1325
+ this._emitEOFToken();
1326
+ } else {
1327
+ this.currentAttr.value += toChar(cp);
1328
+ }
848
1329
  }
849
1330
 
850
- else {
851
- this._emitChar('<');
852
- this._emitChar('/');
853
- this._reconsumeInState(RCDATA_STATE);
1331
+ // After attribute value (quoted) state
1332
+ //------------------------------------------------------------------
1333
+ [AFTER_ATTRIBUTE_VALUE_QUOTED_STATE](cp) {
1334
+ if (isWhitespace(cp)) {
1335
+ this._leaveAttrValue(BEFORE_ATTRIBUTE_NAME_STATE);
1336
+ } else if (cp === $.SOLIDUS) {
1337
+ this._leaveAttrValue(SELF_CLOSING_START_TAG_STATE);
1338
+ } else if (cp === $.GREATER_THAN_SIGN) {
1339
+ this._leaveAttrValue(DATA_STATE);
1340
+ this._emitCurrentToken();
1341
+ } else if (cp === $.EOF) {
1342
+ this._err(ERR.eofInTag);
1343
+ this._emitEOFToken();
1344
+ } else {
1345
+ this._err(ERR.missingWhitespaceBetweenAttributes);
1346
+ this._reconsumeInState(BEFORE_ATTRIBUTE_NAME_STATE);
1347
+ }
854
1348
  }
855
- };
856
-
857
1349
 
858
- //12.2.4.13 RCDATA end tag name state
859
- //------------------------------------------------------------------
860
- _[RCDATA_END_TAG_NAME_STATE] = function rcdataEndTagNameState(cp) {
861
- if (isAsciiUpper(cp)) {
862
- this.currentToken.tagName += toAsciiLowerChar(cp);
863
- this.tempBuff.push(cp);
1350
+ // Self-closing start tag state
1351
+ //------------------------------------------------------------------
1352
+ [SELF_CLOSING_START_TAG_STATE](cp) {
1353
+ if (cp === $.GREATER_THAN_SIGN) {
1354
+ this.currentToken.selfClosing = true;
1355
+ this.state = DATA_STATE;
1356
+ this._emitCurrentToken();
1357
+ } else if (cp === $.EOF) {
1358
+ this._err(ERR.eofInTag);
1359
+ this._emitEOFToken();
1360
+ } else {
1361
+ this._err(ERR.unexpectedSolidusInTag);
1362
+ this._reconsumeInState(BEFORE_ATTRIBUTE_NAME_STATE);
1363
+ }
864
1364
  }
865
1365
 
866
- else if (isAsciiLower(cp)) {
867
- this.currentToken.tagName += toChar(cp);
868
- this.tempBuff.push(cp);
1366
+ // Bogus comment state
1367
+ //------------------------------------------------------------------
1368
+ [BOGUS_COMMENT_STATE](cp) {
1369
+ if (cp === $.GREATER_THAN_SIGN) {
1370
+ this.state = DATA_STATE;
1371
+ this._emitCurrentToken();
1372
+ } else if (cp === $.EOF) {
1373
+ this._emitCurrentToken();
1374
+ this._emitEOFToken();
1375
+ } else if (cp === $.NULL) {
1376
+ this._err(ERR.unexpectedNullCharacter);
1377
+ this.currentToken.data += unicode.REPLACEMENT_CHARACTER;
1378
+ } else {
1379
+ this.currentToken.data += toChar(cp);
1380
+ }
869
1381
  }
870
1382
 
871
- else {
872
- if (this._isAppropriateEndTagToken()) {
873
- if (isWhitespace(cp)) {
874
- this.state = BEFORE_ATTRIBUTE_NAME_STATE;
875
- return;
876
- }
877
-
878
- if (cp === $.SOLIDUS) {
879
- this.state = SELF_CLOSING_START_TAG_STATE;
880
- return;
881
- }
882
-
883
- if (cp === $.GREATER_THAN_SIGN) {
884
- this.state = DATA_STATE;
885
- this._emitCurrentToken();
886
- return;
1383
+ // Markup declaration open state
1384
+ //------------------------------------------------------------------
1385
+ [MARKUP_DECLARATION_OPEN_STATE](cp) {
1386
+ if (this._consumeSequenceIfMatch($$.DASH_DASH_STRING, cp, true)) {
1387
+ this._createCommentToken();
1388
+ this.state = COMMENT_START_STATE;
1389
+ } else if (this._consumeSequenceIfMatch($$.DOCTYPE_STRING, cp, false)) {
1390
+ this.state = DOCTYPE_STATE;
1391
+ } else if (this._consumeSequenceIfMatch($$.CDATA_START_STRING, cp, true)) {
1392
+ if (this.allowCDATA) {
1393
+ this.state = CDATA_SECTION_STATE;
1394
+ } else {
1395
+ this._err(ERR.cdataInHtmlContent);
1396
+ this._createCommentToken();
1397
+ this.currentToken.data = '[CDATA[';
1398
+ this.state = BOGUS_COMMENT_STATE;
887
1399
  }
888
1400
  }
889
1401
 
890
- this._emitChar('<');
891
- this._emitChar('/');
892
- this._emitSeveralCodePoints(this.tempBuff);
893
- this._reconsumeInState(RCDATA_STATE);
894
- }
895
- };
896
-
897
-
898
- //12.2.4.14 RAWTEXT less-than sign state
899
- //------------------------------------------------------------------
900
- _[RAWTEXT_LESS_THAN_SIGN_STATE] = function rawtextLessThanSignState(cp) {
901
- if (cp === $.SOLIDUS) {
902
- this.tempBuff = [];
903
- this.state = RAWTEXT_END_TAG_OPEN_STATE;
904
- }
905
-
906
- else {
907
- this._emitChar('<');
908
- this._reconsumeInState(RAWTEXT_STATE);
909
- }
910
- };
911
-
912
-
913
- //12.2.4.15 RAWTEXT end tag open state
914
- //------------------------------------------------------------------
915
- _[RAWTEXT_END_TAG_OPEN_STATE] = function rawtextEndTagOpenState(cp) {
916
- if (isAsciiLetter(cp)) {
917
- this._createEndTagToken();
918
- this._reconsumeInState(RAWTEXT_END_TAG_NAME_STATE);
919
- }
920
-
921
- else {
922
- this._emitChar('<');
923
- this._emitChar('/');
924
- this._reconsumeInState(RAWTEXT_STATE);
1402
+ //NOTE: sequence lookup can be abrupted by hibernation. In that case lookup
1403
+ //results are no longer valid and we will need to start over.
1404
+ else if (!this._ensureHibernation()) {
1405
+ this._err(ERR.incorrectlyOpenedComment);
1406
+ this._createCommentToken();
1407
+ this._reconsumeInState(BOGUS_COMMENT_STATE);
1408
+ }
925
1409
  }
926
- };
927
1410
 
928
-
929
- //12.2.4.16 RAWTEXT end tag name state
930
- //------------------------------------------------------------------
931
- _[RAWTEXT_END_TAG_NAME_STATE] = function rawtextEndTagNameState(cp) {
932
- if (isAsciiUpper(cp)) {
933
- this.currentToken.tagName += toAsciiLowerChar(cp);
934
- this.tempBuff.push(cp);
1411
+ // Comment start state
1412
+ //------------------------------------------------------------------
1413
+ [COMMENT_START_STATE](cp) {
1414
+ if (cp === $.HYPHEN_MINUS) {
1415
+ this.state = COMMENT_START_DASH_STATE;
1416
+ } else if (cp === $.GREATER_THAN_SIGN) {
1417
+ this._err(ERR.abruptClosingOfEmptyComment);
1418
+ this.state = DATA_STATE;
1419
+ this._emitCurrentToken();
1420
+ } else {
1421
+ this._reconsumeInState(COMMENT_STATE);
1422
+ }
935
1423
  }
936
1424
 
937
- else if (isAsciiLower(cp)) {
938
- this.currentToken.tagName += toChar(cp);
939
- this.tempBuff.push(cp);
1425
+ // Comment start dash state
1426
+ //------------------------------------------------------------------
1427
+ [COMMENT_START_DASH_STATE](cp) {
1428
+ if (cp === $.HYPHEN_MINUS) {
1429
+ this.state = COMMENT_END_STATE;
1430
+ } else if (cp === $.GREATER_THAN_SIGN) {
1431
+ this._err(ERR.abruptClosingOfEmptyComment);
1432
+ this.state = DATA_STATE;
1433
+ this._emitCurrentToken();
1434
+ } else if (cp === $.EOF) {
1435
+ this._err(ERR.eofInComment);
1436
+ this._emitCurrentToken();
1437
+ this._emitEOFToken();
1438
+ } else {
1439
+ this.currentToken.data += '-';
1440
+ this._reconsumeInState(COMMENT_STATE);
1441
+ }
940
1442
  }
941
1443
 
942
- else {
943
- if (this._isAppropriateEndTagToken()) {
944
- if (isWhitespace(cp)) {
945
- this.state = BEFORE_ATTRIBUTE_NAME_STATE;
946
- return;
947
- }
948
-
949
- if (cp === $.SOLIDUS) {
950
- this.state = SELF_CLOSING_START_TAG_STATE;
951
- return;
952
- }
953
-
954
- if (cp === $.GREATER_THAN_SIGN) {
955
- this._emitCurrentToken();
956
- this.state = DATA_STATE;
957
- return;
958
- }
1444
+ // Comment state
1445
+ //------------------------------------------------------------------
1446
+ [COMMENT_STATE](cp) {
1447
+ if (cp === $.HYPHEN_MINUS) {
1448
+ this.state = COMMENT_END_DASH_STATE;
1449
+ } else if (cp === $.LESS_THAN_SIGN) {
1450
+ this.currentToken.data += '<';
1451
+ this.state = COMMENT_LESS_THAN_SIGN_STATE;
1452
+ } else if (cp === $.NULL) {
1453
+ this._err(ERR.unexpectedNullCharacter);
1454
+ this.currentToken.data += unicode.REPLACEMENT_CHARACTER;
1455
+ } else if (cp === $.EOF) {
1456
+ this._err(ERR.eofInComment);
1457
+ this._emitCurrentToken();
1458
+ this._emitEOFToken();
1459
+ } else {
1460
+ this.currentToken.data += toChar(cp);
959
1461
  }
960
-
961
- this._emitChar('<');
962
- this._emitChar('/');
963
- this._emitSeveralCodePoints(this.tempBuff);
964
- this._reconsumeInState(RAWTEXT_STATE);
965
1462
  }
966
- };
967
1463
 
968
-
969
- //12.2.4.17 Script data less-than sign state
970
- //------------------------------------------------------------------
971
- _[SCRIPT_DATA_LESS_THAN_SIGN_STATE] = function scriptDataLessThanSignState(cp) {
972
- if (cp === $.SOLIDUS) {
973
- this.tempBuff = [];
974
- this.state = SCRIPT_DATA_END_TAG_OPEN_STATE;
1464
+ // Comment less-than sign state
1465
+ //------------------------------------------------------------------
1466
+ [COMMENT_LESS_THAN_SIGN_STATE](cp) {
1467
+ if (cp === $.EXCLAMATION_MARK) {
1468
+ this.currentToken.data += '!';
1469
+ this.state = COMMENT_LESS_THAN_SIGN_BANG_STATE;
1470
+ } else if (cp === $.LESS_THAN_SIGN) {
1471
+ this.currentToken.data += '!';
1472
+ } else {
1473
+ this._reconsumeInState(COMMENT_STATE);
1474
+ }
975
1475
  }
976
1476
 
977
- else if (cp === $.EXCLAMATION_MARK) {
978
- this.state = SCRIPT_DATA_ESCAPE_START_STATE;
979
- this._emitChar('<');
980
- this._emitChar('!');
1477
+ // Comment less-than sign bang state
1478
+ //------------------------------------------------------------------
1479
+ [COMMENT_LESS_THAN_SIGN_BANG_STATE](cp) {
1480
+ if (cp === $.HYPHEN_MINUS) {
1481
+ this.state = COMMENT_LESS_THAN_SIGN_BANG_DASH_STATE;
1482
+ } else {
1483
+ this._reconsumeInState(COMMENT_STATE);
1484
+ }
981
1485
  }
982
1486
 
983
- else {
984
- this._emitChar('<');
985
- this._reconsumeInState(SCRIPT_DATA_STATE);
1487
+ // Comment less-than sign bang dash state
1488
+ //------------------------------------------------------------------
1489
+ [COMMENT_LESS_THAN_SIGN_BANG_DASH_STATE](cp) {
1490
+ if (cp === $.HYPHEN_MINUS) {
1491
+ this.state = COMMENT_LESS_THAN_SIGN_BANG_DASH_DASH_STATE;
1492
+ } else {
1493
+ this._reconsumeInState(COMMENT_END_DASH_STATE);
1494
+ }
986
1495
  }
987
- };
988
1496
 
1497
+ // Comment less-than sign bang dash dash state
1498
+ //------------------------------------------------------------------
1499
+ [COMMENT_LESS_THAN_SIGN_BANG_DASH_DASH_STATE](cp) {
1500
+ if (cp !== $.GREATER_THAN_SIGN && cp !== $.EOF) {
1501
+ this._err(ERR.nestedComment);
1502
+ }
989
1503
 
990
- //12.2.4.18 Script data end tag open state
991
- //------------------------------------------------------------------
992
- _[SCRIPT_DATA_END_TAG_OPEN_STATE] = function scriptDataEndTagOpenState(cp) {
993
- if (isAsciiLetter(cp)) {
994
- this._createEndTagToken();
995
- this._reconsumeInState(SCRIPT_DATA_END_TAG_NAME_STATE);
996
- }
997
-
998
- else {
999
- this._emitChar('<');
1000
- this._emitChar('/');
1001
- this._reconsumeInState(SCRIPT_DATA_STATE);
1504
+ this._reconsumeInState(COMMENT_END_STATE);
1505
+ }
1506
+
1507
+ // Comment end dash state
1508
+ //------------------------------------------------------------------
1509
+ [COMMENT_END_DASH_STATE](cp) {
1510
+ if (cp === $.HYPHEN_MINUS) {
1511
+ this.state = COMMENT_END_STATE;
1512
+ } else if (cp === $.EOF) {
1513
+ this._err(ERR.eofInComment);
1514
+ this._emitCurrentToken();
1515
+ this._emitEOFToken();
1516
+ } else {
1517
+ this.currentToken.data += '-';
1518
+ this._reconsumeInState(COMMENT_STATE);
1519
+ }
1002
1520
  }
1003
- };
1004
-
1005
1521
 
1006
- //12.2.4.19 Script data end tag name state
1007
- //------------------------------------------------------------------
1008
- _[SCRIPT_DATA_END_TAG_NAME_STATE] = function scriptDataEndTagNameState(cp) {
1009
- if (isAsciiUpper(cp)) {
1010
- this.currentToken.tagName += toAsciiLowerChar(cp);
1011
- this.tempBuff.push(cp);
1522
+ // Comment end state
1523
+ //------------------------------------------------------------------
1524
+ [COMMENT_END_STATE](cp) {
1525
+ if (cp === $.GREATER_THAN_SIGN) {
1526
+ this.state = DATA_STATE;
1527
+ this._emitCurrentToken();
1528
+ } else if (cp === $.EXCLAMATION_MARK) {
1529
+ this.state = COMMENT_END_BANG_STATE;
1530
+ } else if (cp === $.HYPHEN_MINUS) {
1531
+ this.currentToken.data += '-';
1532
+ } else if (cp === $.EOF) {
1533
+ this._err(ERR.eofInComment);
1534
+ this._emitCurrentToken();
1535
+ this._emitEOFToken();
1536
+ } else {
1537
+ this.currentToken.data += '--';
1538
+ this._reconsumeInState(COMMENT_STATE);
1539
+ }
1012
1540
  }
1013
1541
 
1014
- else if (isAsciiLower(cp)) {
1015
- this.currentToken.tagName += toChar(cp);
1016
- this.tempBuff.push(cp);
1542
+ // Comment end bang state
1543
+ //------------------------------------------------------------------
1544
+ [COMMENT_END_BANG_STATE](cp) {
1545
+ if (cp === $.HYPHEN_MINUS) {
1546
+ this.currentToken.data += '--!';
1547
+ this.state = COMMENT_END_DASH_STATE;
1548
+ } else if (cp === $.GREATER_THAN_SIGN) {
1549
+ this._err(ERR.incorrectlyClosedComment);
1550
+ this.state = DATA_STATE;
1551
+ this._emitCurrentToken();
1552
+ } else if (cp === $.EOF) {
1553
+ this._err(ERR.eofInComment);
1554
+ this._emitCurrentToken();
1555
+ this._emitEOFToken();
1556
+ } else {
1557
+ this.currentToken.data += '--!';
1558
+ this._reconsumeInState(COMMENT_STATE);
1559
+ }
1017
1560
  }
1018
1561
 
1019
- else {
1020
- if (this._isAppropriateEndTagToken()) {
1021
- if (isWhitespace(cp)) {
1022
- this.state = BEFORE_ATTRIBUTE_NAME_STATE;
1023
- return;
1024
- }
1025
-
1026
- else if (cp === $.SOLIDUS) {
1027
- this.state = SELF_CLOSING_START_TAG_STATE;
1028
- return;
1029
- }
1030
-
1031
- else if (cp === $.GREATER_THAN_SIGN) {
1032
- this._emitCurrentToken();
1033
- this.state = DATA_STATE;
1034
- return;
1035
- }
1562
+ // DOCTYPE state
1563
+ //------------------------------------------------------------------
1564
+ [DOCTYPE_STATE](cp) {
1565
+ if (isWhitespace(cp)) {
1566
+ this.state = BEFORE_DOCTYPE_NAME_STATE;
1567
+ } else if (cp === $.GREATER_THAN_SIGN) {
1568
+ this._reconsumeInState(BEFORE_DOCTYPE_NAME_STATE);
1569
+ } else if (cp === $.EOF) {
1570
+ this._err(ERR.eofInDoctype);
1571
+ this._createDoctypeToken(null);
1572
+ this.currentToken.forceQuirks = true;
1573
+ this._emitCurrentToken();
1574
+ this._emitEOFToken();
1575
+ } else {
1576
+ this._err(ERR.missingWhitespaceBeforeDoctypeName);
1577
+ this._reconsumeInState(BEFORE_DOCTYPE_NAME_STATE);
1036
1578
  }
1037
-
1038
- this._emitChar('<');
1039
- this._emitChar('/');
1040
- this._emitSeveralCodePoints(this.tempBuff);
1041
- this._reconsumeInState(SCRIPT_DATA_STATE);
1042
1579
  }
1043
- };
1044
1580
 
1581
+ // Before DOCTYPE name state
1582
+ //------------------------------------------------------------------
1583
+ [BEFORE_DOCTYPE_NAME_STATE](cp) {
1584
+ if (isWhitespace(cp)) {
1585
+ return;
1586
+ }
1045
1587
 
1046
- //12.2.4.20 Script data escape start state
1047
- //------------------------------------------------------------------
1048
- _[SCRIPT_DATA_ESCAPE_START_STATE] = function scriptDataEscapeStartState(cp) {
1049
- if (cp === $.HYPHEN_MINUS) {
1050
- this.state = SCRIPT_DATA_ESCAPE_START_DASH_STATE;
1051
- this._emitChar('-');
1588
+ if (isAsciiUpper(cp)) {
1589
+ this._createDoctypeToken(toAsciiLowerChar(cp));
1590
+ this.state = DOCTYPE_NAME_STATE;
1591
+ } else if (cp === $.NULL) {
1592
+ this._err(ERR.unexpectedNullCharacter);
1593
+ this._createDoctypeToken(unicode.REPLACEMENT_CHARACTER);
1594
+ this.state = DOCTYPE_NAME_STATE;
1595
+ } else if (cp === $.GREATER_THAN_SIGN) {
1596
+ this._err(ERR.missingDoctypeName);
1597
+ this._createDoctypeToken(null);
1598
+ this.currentToken.forceQuirks = true;
1599
+ this._emitCurrentToken();
1600
+ this.state = DATA_STATE;
1601
+ } else if (cp === $.EOF) {
1602
+ this._err(ERR.eofInDoctype);
1603
+ this._createDoctypeToken(null);
1604
+ this.currentToken.forceQuirks = true;
1605
+ this._emitCurrentToken();
1606
+ this._emitEOFToken();
1607
+ } else {
1608
+ this._createDoctypeToken(toChar(cp));
1609
+ this.state = DOCTYPE_NAME_STATE;
1610
+ }
1052
1611
  }
1053
1612
 
1054
- else
1055
- this._reconsumeInState(SCRIPT_DATA_STATE);
1056
- };
1057
-
1058
-
1059
- //12.2.4.21 Script data escape start dash state
1060
- //------------------------------------------------------------------
1061
- _[SCRIPT_DATA_ESCAPE_START_DASH_STATE] = function scriptDataEscapeStartDashState(cp) {
1062
- if (cp === $.HYPHEN_MINUS) {
1063
- this.state = SCRIPT_DATA_ESCAPED_DASH_DASH_STATE;
1064
- this._emitChar('-');
1613
+ // DOCTYPE name state
1614
+ //------------------------------------------------------------------
1615
+ [DOCTYPE_NAME_STATE](cp) {
1616
+ if (isWhitespace(cp)) {
1617
+ this.state = AFTER_DOCTYPE_NAME_STATE;
1618
+ } else if (cp === $.GREATER_THAN_SIGN) {
1619
+ this.state = DATA_STATE;
1620
+ this._emitCurrentToken();
1621
+ } else if (isAsciiUpper(cp)) {
1622
+ this.currentToken.name += toAsciiLowerChar(cp);
1623
+ } else if (cp === $.NULL) {
1624
+ this._err(ERR.unexpectedNullCharacter);
1625
+ this.currentToken.name += unicode.REPLACEMENT_CHARACTER;
1626
+ } else if (cp === $.EOF) {
1627
+ this._err(ERR.eofInDoctype);
1628
+ this.currentToken.forceQuirks = true;
1629
+ this._emitCurrentToken();
1630
+ this._emitEOFToken();
1631
+ } else {
1632
+ this.currentToken.name += toChar(cp);
1633
+ }
1065
1634
  }
1066
1635
 
1067
- else
1068
- this._reconsumeInState(SCRIPT_DATA_STATE);
1069
- };
1070
-
1636
+ // After DOCTYPE name state
1637
+ //------------------------------------------------------------------
1638
+ [AFTER_DOCTYPE_NAME_STATE](cp) {
1639
+ if (isWhitespace(cp)) {
1640
+ return;
1641
+ }
1071
1642
 
1072
- //12.2.4.22 Script data escaped state
1073
- //------------------------------------------------------------------
1074
- _[SCRIPT_DATA_ESCAPED_STATE] = function scriptDataEscapedState(cp) {
1075
- if (cp === $.HYPHEN_MINUS) {
1076
- this.state = SCRIPT_DATA_ESCAPED_DASH_STATE;
1077
- this._emitChar('-');
1643
+ if (cp === $.GREATER_THAN_SIGN) {
1644
+ this.state = DATA_STATE;
1645
+ this._emitCurrentToken();
1646
+ } else if (cp === $.EOF) {
1647
+ this._err(ERR.eofInDoctype);
1648
+ this.currentToken.forceQuirks = true;
1649
+ this._emitCurrentToken();
1650
+ this._emitEOFToken();
1651
+ } else if (this._consumeSequenceIfMatch($$.PUBLIC_STRING, cp, false)) {
1652
+ this.state = AFTER_DOCTYPE_PUBLIC_KEYWORD_STATE;
1653
+ } else if (this._consumeSequenceIfMatch($$.SYSTEM_STRING, cp, false)) {
1654
+ this.state = AFTER_DOCTYPE_SYSTEM_KEYWORD_STATE;
1655
+ }
1656
+ //NOTE: sequence lookup can be abrupted by hibernation. In that case lookup
1657
+ //results are no longer valid and we will need to start over.
1658
+ else if (!this._ensureHibernation()) {
1659
+ this._err(ERR.invalidCharacterSequenceAfterDoctypeName);
1660
+ this.currentToken.forceQuirks = true;
1661
+ this._reconsumeInState(BOGUS_DOCTYPE_STATE);
1662
+ }
1078
1663
  }
1079
1664
 
1080
- else if (cp === $.LESS_THAN_SIGN)
1081
- this.state = SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN_STATE;
1082
-
1083
- else if (cp === $.NULL)
1084
- this._emitChar(UNICODE.REPLACEMENT_CHARACTER);
1085
-
1086
- else if (cp === $.EOF)
1087
- this._reconsumeInState(DATA_STATE);
1088
-
1089
- else
1090
- this._emitCodePoint(cp);
1091
- };
1092
-
1093
-
1094
- //12.2.4.23 Script data escaped dash state
1095
- //------------------------------------------------------------------
1096
- _[SCRIPT_DATA_ESCAPED_DASH_STATE] = function scriptDataEscapedDashState(cp) {
1097
- if (cp === $.HYPHEN_MINUS) {
1098
- this.state = SCRIPT_DATA_ESCAPED_DASH_DASH_STATE;
1099
- this._emitChar('-');
1665
+ // After DOCTYPE public keyword state
1666
+ //------------------------------------------------------------------
1667
+ [AFTER_DOCTYPE_PUBLIC_KEYWORD_STATE](cp) {
1668
+ if (isWhitespace(cp)) {
1669
+ this.state = BEFORE_DOCTYPE_PUBLIC_IDENTIFIER_STATE;
1670
+ } else if (cp === $.QUOTATION_MARK) {
1671
+ this._err(ERR.missingWhitespaceAfterDoctypePublicKeyword);
1672
+ this.currentToken.publicId = '';
1673
+ this.state = DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED_STATE;
1674
+ } else if (cp === $.APOSTROPHE) {
1675
+ this._err(ERR.missingWhitespaceAfterDoctypePublicKeyword);
1676
+ this.currentToken.publicId = '';
1677
+ this.state = DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED_STATE;
1678
+ } else if (cp === $.GREATER_THAN_SIGN) {
1679
+ this._err(ERR.missingDoctypePublicIdentifier);
1680
+ this.currentToken.forceQuirks = true;
1681
+ this.state = DATA_STATE;
1682
+ this._emitCurrentToken();
1683
+ } else if (cp === $.EOF) {
1684
+ this._err(ERR.eofInDoctype);
1685
+ this.currentToken.forceQuirks = true;
1686
+ this._emitCurrentToken();
1687
+ this._emitEOFToken();
1688
+ } else {
1689
+ this._err(ERR.missingQuoteBeforeDoctypePublicIdentifier);
1690
+ this.currentToken.forceQuirks = true;
1691
+ this._reconsumeInState(BOGUS_DOCTYPE_STATE);
1692
+ }
1100
1693
  }
1101
1694
 
1102
- else if (cp === $.LESS_THAN_SIGN)
1103
- this.state = SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN_STATE;
1695
+ // Before DOCTYPE public identifier state
1696
+ //------------------------------------------------------------------
1697
+ [BEFORE_DOCTYPE_PUBLIC_IDENTIFIER_STATE](cp) {
1698
+ if (isWhitespace(cp)) {
1699
+ return;
1700
+ }
1104
1701
 
1105
- else if (cp === $.NULL) {
1106
- this.state = SCRIPT_DATA_ESCAPED_STATE;
1107
- this._emitChar(UNICODE.REPLACEMENT_CHARACTER);
1702
+ if (cp === $.QUOTATION_MARK) {
1703
+ this.currentToken.publicId = '';
1704
+ this.state = DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED_STATE;
1705
+ } else if (cp === $.APOSTROPHE) {
1706
+ this.currentToken.publicId = '';
1707
+ this.state = DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED_STATE;
1708
+ } else if (cp === $.GREATER_THAN_SIGN) {
1709
+ this._err(ERR.missingDoctypePublicIdentifier);
1710
+ this.currentToken.forceQuirks = true;
1711
+ this.state = DATA_STATE;
1712
+ this._emitCurrentToken();
1713
+ } else if (cp === $.EOF) {
1714
+ this._err(ERR.eofInDoctype);
1715
+ this.currentToken.forceQuirks = true;
1716
+ this._emitCurrentToken();
1717
+ this._emitEOFToken();
1718
+ } else {
1719
+ this._err(ERR.missingQuoteBeforeDoctypePublicIdentifier);
1720
+ this.currentToken.forceQuirks = true;
1721
+ this._reconsumeInState(BOGUS_DOCTYPE_STATE);
1722
+ }
1108
1723
  }
1109
1724
 
1110
- else if (cp === $.EOF)
1111
- this._reconsumeInState(DATA_STATE);
1112
-
1113
- else {
1114
- this.state = SCRIPT_DATA_ESCAPED_STATE;
1115
- this._emitCodePoint(cp);
1725
+ // DOCTYPE public identifier (double-quoted) state
1726
+ //------------------------------------------------------------------
1727
+ [DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED_STATE](cp) {
1728
+ if (cp === $.QUOTATION_MARK) {
1729
+ this.state = AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE;
1730
+ } else if (cp === $.NULL) {
1731
+ this._err(ERR.unexpectedNullCharacter);
1732
+ this.currentToken.publicId += unicode.REPLACEMENT_CHARACTER;
1733
+ } else if (cp === $.GREATER_THAN_SIGN) {
1734
+ this._err(ERR.abruptDoctypePublicIdentifier);
1735
+ this.currentToken.forceQuirks = true;
1736
+ this._emitCurrentToken();
1737
+ this.state = DATA_STATE;
1738
+ } else if (cp === $.EOF) {
1739
+ this._err(ERR.eofInDoctype);
1740
+ this.currentToken.forceQuirks = true;
1741
+ this._emitCurrentToken();
1742
+ this._emitEOFToken();
1743
+ } else {
1744
+ this.currentToken.publicId += toChar(cp);
1745
+ }
1116
1746
  }
1117
- };
1118
1747
 
1119
-
1120
- //12.2.4.24 Script data escaped dash dash state
1121
- //------------------------------------------------------------------
1122
- _[SCRIPT_DATA_ESCAPED_DASH_DASH_STATE] = function scriptDataEscapedDashDashState(cp) {
1123
- if (cp === $.HYPHEN_MINUS)
1124
- this._emitChar('-');
1125
-
1126
- else if (cp === $.LESS_THAN_SIGN)
1127
- this.state = SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN_STATE;
1128
-
1129
- else if (cp === $.GREATER_THAN_SIGN) {
1130
- this.state = SCRIPT_DATA_STATE;
1131
- this._emitChar('>');
1748
+ // DOCTYPE public identifier (single-quoted) state
1749
+ //------------------------------------------------------------------
1750
+ [DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED_STATE](cp) {
1751
+ if (cp === $.APOSTROPHE) {
1752
+ this.state = AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE;
1753
+ } else if (cp === $.NULL) {
1754
+ this._err(ERR.unexpectedNullCharacter);
1755
+ this.currentToken.publicId += unicode.REPLACEMENT_CHARACTER;
1756
+ } else if (cp === $.GREATER_THAN_SIGN) {
1757
+ this._err(ERR.abruptDoctypePublicIdentifier);
1758
+ this.currentToken.forceQuirks = true;
1759
+ this._emitCurrentToken();
1760
+ this.state = DATA_STATE;
1761
+ } else if (cp === $.EOF) {
1762
+ this._err(ERR.eofInDoctype);
1763
+ this.currentToken.forceQuirks = true;
1764
+ this._emitCurrentToken();
1765
+ this._emitEOFToken();
1766
+ } else {
1767
+ this.currentToken.publicId += toChar(cp);
1768
+ }
1132
1769
  }
1133
1770
 
1134
- else if (cp === $.NULL) {
1135
- this.state = SCRIPT_DATA_ESCAPED_STATE;
1136
- this._emitChar(UNICODE.REPLACEMENT_CHARACTER);
1771
+ // After DOCTYPE public identifier state
1772
+ //------------------------------------------------------------------
1773
+ [AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE](cp) {
1774
+ if (isWhitespace(cp)) {
1775
+ this.state = BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS_STATE;
1776
+ } else if (cp === $.GREATER_THAN_SIGN) {
1777
+ this.state = DATA_STATE;
1778
+ this._emitCurrentToken();
1779
+ } else if (cp === $.QUOTATION_MARK) {
1780
+ this._err(ERR.missingWhitespaceBetweenDoctypePublicAndSystemIdentifiers);
1781
+ this.currentToken.systemId = '';
1782
+ this.state = DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE;
1783
+ } else if (cp === $.APOSTROPHE) {
1784
+ this._err(ERR.missingWhitespaceBetweenDoctypePublicAndSystemIdentifiers);
1785
+ this.currentToken.systemId = '';
1786
+ this.state = DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE;
1787
+ } else if (cp === $.EOF) {
1788
+ this._err(ERR.eofInDoctype);
1789
+ this.currentToken.forceQuirks = true;
1790
+ this._emitCurrentToken();
1791
+ this._emitEOFToken();
1792
+ } else {
1793
+ this._err(ERR.missingQuoteBeforeDoctypeSystemIdentifier);
1794
+ this.currentToken.forceQuirks = true;
1795
+ this._reconsumeInState(BOGUS_DOCTYPE_STATE);
1796
+ }
1137
1797
  }
1138
1798
 
1139
- else if (cp === $.EOF)
1140
- this._reconsumeInState(DATA_STATE);
1799
+ // Between DOCTYPE public and system identifiers state
1800
+ //------------------------------------------------------------------
1801
+ [BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS_STATE](cp) {
1802
+ if (isWhitespace(cp)) {
1803
+ return;
1804
+ }
1141
1805
 
1142
- else {
1143
- this.state = SCRIPT_DATA_ESCAPED_STATE;
1144
- this._emitCodePoint(cp);
1806
+ if (cp === $.GREATER_THAN_SIGN) {
1807
+ this._emitCurrentToken();
1808
+ this.state = DATA_STATE;
1809
+ } else if (cp === $.QUOTATION_MARK) {
1810
+ this.currentToken.systemId = '';
1811
+ this.state = DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE;
1812
+ } else if (cp === $.APOSTROPHE) {
1813
+ this.currentToken.systemId = '';
1814
+ this.state = DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE;
1815
+ } else if (cp === $.EOF) {
1816
+ this._err(ERR.eofInDoctype);
1817
+ this.currentToken.forceQuirks = true;
1818
+ this._emitCurrentToken();
1819
+ this._emitEOFToken();
1820
+ } else {
1821
+ this._err(ERR.missingQuoteBeforeDoctypeSystemIdentifier);
1822
+ this.currentToken.forceQuirks = true;
1823
+ this._reconsumeInState(BOGUS_DOCTYPE_STATE);
1824
+ }
1145
1825
  }
1146
- };
1147
1826
 
1148
-
1149
- //12.2.4.25 Script data escaped less-than sign state
1150
- //------------------------------------------------------------------
1151
- _[SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN_STATE] = function scriptDataEscapedLessThanSignState(cp) {
1152
- if (cp === $.SOLIDUS) {
1153
- this.tempBuff = [];
1154
- this.state = SCRIPT_DATA_ESCAPED_END_TAG_OPEN_STATE;
1827
+ // After DOCTYPE system keyword state
1828
+ //------------------------------------------------------------------
1829
+ [AFTER_DOCTYPE_SYSTEM_KEYWORD_STATE](cp) {
1830
+ if (isWhitespace(cp)) {
1831
+ this.state = BEFORE_DOCTYPE_SYSTEM_IDENTIFIER_STATE;
1832
+ } else if (cp === $.QUOTATION_MARK) {
1833
+ this._err(ERR.missingWhitespaceAfterDoctypeSystemKeyword);
1834
+ this.currentToken.systemId = '';
1835
+ this.state = DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE;
1836
+ } else if (cp === $.APOSTROPHE) {
1837
+ this._err(ERR.missingWhitespaceAfterDoctypeSystemKeyword);
1838
+ this.currentToken.systemId = '';
1839
+ this.state = DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE;
1840
+ } else if (cp === $.GREATER_THAN_SIGN) {
1841
+ this._err(ERR.missingDoctypeSystemIdentifier);
1842
+ this.currentToken.forceQuirks = true;
1843
+ this.state = DATA_STATE;
1844
+ this._emitCurrentToken();
1845
+ } else if (cp === $.EOF) {
1846
+ this._err(ERR.eofInDoctype);
1847
+ this.currentToken.forceQuirks = true;
1848
+ this._emitCurrentToken();
1849
+ this._emitEOFToken();
1850
+ } else {
1851
+ this._err(ERR.missingQuoteBeforeDoctypeSystemIdentifier);
1852
+ this.currentToken.forceQuirks = true;
1853
+ this._reconsumeInState(BOGUS_DOCTYPE_STATE);
1854
+ }
1155
1855
  }
1156
1856
 
1157
- else if (isAsciiLetter(cp)) {
1158
- this.tempBuff = [];
1159
- this._emitChar('<');
1160
- this._reconsumeInState(SCRIPT_DATA_DOUBLE_ESCAPE_START_STATE);
1161
- }
1857
+ // Before DOCTYPE system identifier state
1858
+ //------------------------------------------------------------------
1859
+ [BEFORE_DOCTYPE_SYSTEM_IDENTIFIER_STATE](cp) {
1860
+ if (isWhitespace(cp)) {
1861
+ return;
1862
+ }
1162
1863
 
1163
- else {
1164
- this._emitChar('<');
1165
- this._reconsumeInState(SCRIPT_DATA_ESCAPED_STATE);
1864
+ if (cp === $.QUOTATION_MARK) {
1865
+ this.currentToken.systemId = '';
1866
+ this.state = DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE;
1867
+ } else if (cp === $.APOSTROPHE) {
1868
+ this.currentToken.systemId = '';
1869
+ this.state = DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE;
1870
+ } else if (cp === $.GREATER_THAN_SIGN) {
1871
+ this._err(ERR.missingDoctypeSystemIdentifier);
1872
+ this.currentToken.forceQuirks = true;
1873
+ this.state = DATA_STATE;
1874
+ this._emitCurrentToken();
1875
+ } else if (cp === $.EOF) {
1876
+ this._err(ERR.eofInDoctype);
1877
+ this.currentToken.forceQuirks = true;
1878
+ this._emitCurrentToken();
1879
+ this._emitEOFToken();
1880
+ } else {
1881
+ this._err(ERR.missingQuoteBeforeDoctypeSystemIdentifier);
1882
+ this.currentToken.forceQuirks = true;
1883
+ this._reconsumeInState(BOGUS_DOCTYPE_STATE);
1884
+ }
1166
1885
  }
1167
- };
1168
1886
 
1169
-
1170
- //12.2.4.26 Script data escaped end tag open state
1171
- //------------------------------------------------------------------
1172
- _[SCRIPT_DATA_ESCAPED_END_TAG_OPEN_STATE] = function scriptDataEscapedEndTagOpenState(cp) {
1173
- if (isAsciiLetter(cp)) {
1174
- this._createEndTagToken();
1175
- this._reconsumeInState(SCRIPT_DATA_ESCAPED_END_TAG_NAME_STATE);
1887
+ // DOCTYPE system identifier (double-quoted) state
1888
+ //------------------------------------------------------------------
1889
+ [DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE](cp) {
1890
+ if (cp === $.QUOTATION_MARK) {
1891
+ this.state = AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE;
1892
+ } else if (cp === $.NULL) {
1893
+ this._err(ERR.unexpectedNullCharacter);
1894
+ this.currentToken.systemId += unicode.REPLACEMENT_CHARACTER;
1895
+ } else if (cp === $.GREATER_THAN_SIGN) {
1896
+ this._err(ERR.abruptDoctypeSystemIdentifier);
1897
+ this.currentToken.forceQuirks = true;
1898
+ this._emitCurrentToken();
1899
+ this.state = DATA_STATE;
1900
+ } else if (cp === $.EOF) {
1901
+ this._err(ERR.eofInDoctype);
1902
+ this.currentToken.forceQuirks = true;
1903
+ this._emitCurrentToken();
1904
+ this._emitEOFToken();
1905
+ } else {
1906
+ this.currentToken.systemId += toChar(cp);
1907
+ }
1176
1908
  }
1177
1909
 
1178
- else {
1179
- this._emitChar('<');
1180
- this._emitChar('/');
1181
- this._reconsumeInState(SCRIPT_DATA_ESCAPED_STATE);
1910
+ // DOCTYPE system identifier (single-quoted) state
1911
+ //------------------------------------------------------------------
1912
+ [DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE](cp) {
1913
+ if (cp === $.APOSTROPHE) {
1914
+ this.state = AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE;
1915
+ } else if (cp === $.NULL) {
1916
+ this._err(ERR.unexpectedNullCharacter);
1917
+ this.currentToken.systemId += unicode.REPLACEMENT_CHARACTER;
1918
+ } else if (cp === $.GREATER_THAN_SIGN) {
1919
+ this._err(ERR.abruptDoctypeSystemIdentifier);
1920
+ this.currentToken.forceQuirks = true;
1921
+ this._emitCurrentToken();
1922
+ this.state = DATA_STATE;
1923
+ } else if (cp === $.EOF) {
1924
+ this._err(ERR.eofInDoctype);
1925
+ this.currentToken.forceQuirks = true;
1926
+ this._emitCurrentToken();
1927
+ this._emitEOFToken();
1928
+ } else {
1929
+ this.currentToken.systemId += toChar(cp);
1930
+ }
1182
1931
  }
1183
- };
1184
1932
 
1933
+ // After DOCTYPE system identifier state
1934
+ //------------------------------------------------------------------
1935
+ [AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE](cp) {
1936
+ if (isWhitespace(cp)) {
1937
+ return;
1938
+ }
1185
1939
 
1186
- //12.2.4.27 Script data escaped end tag name state
1187
- //------------------------------------------------------------------
1188
- _[SCRIPT_DATA_ESCAPED_END_TAG_NAME_STATE] = function scriptDataEscapedEndTagNameState(cp) {
1189
- if (isAsciiUpper(cp)) {
1190
- this.currentToken.tagName += toAsciiLowerChar(cp);
1191
- this.tempBuff.push(cp);
1192
- }
1193
-
1194
- else if (isAsciiLower(cp)) {
1195
- this.currentToken.tagName += toChar(cp);
1196
- this.tempBuff.push(cp);
1940
+ if (cp === $.GREATER_THAN_SIGN) {
1941
+ this._emitCurrentToken();
1942
+ this.state = DATA_STATE;
1943
+ } else if (cp === $.EOF) {
1944
+ this._err(ERR.eofInDoctype);
1945
+ this.currentToken.forceQuirks = true;
1946
+ this._emitCurrentToken();
1947
+ this._emitEOFToken();
1948
+ } else {
1949
+ this._err(ERR.unexpectedCharacterAfterDoctypeSystemIdentifier);
1950
+ this._reconsumeInState(BOGUS_DOCTYPE_STATE);
1951
+ }
1197
1952
  }
1198
1953
 
1199
- else {
1200
- if (this._isAppropriateEndTagToken()) {
1201
- if (isWhitespace(cp)) {
1202
- this.state = BEFORE_ATTRIBUTE_NAME_STATE;
1203
- return;
1204
- }
1205
-
1206
- if (cp === $.SOLIDUS) {
1207
- this.state = SELF_CLOSING_START_TAG_STATE;
1208
- return;
1209
- }
1210
-
1211
- if (cp === $.GREATER_THAN_SIGN) {
1212
- this._emitCurrentToken();
1213
- this.state = DATA_STATE;
1214
- return;
1215
- }
1954
+ // Bogus DOCTYPE state
1955
+ //------------------------------------------------------------------
1956
+ [BOGUS_DOCTYPE_STATE](cp) {
1957
+ if (cp === $.GREATER_THAN_SIGN) {
1958
+ this._emitCurrentToken();
1959
+ this.state = DATA_STATE;
1960
+ } else if (cp === $.NULL) {
1961
+ this._err(ERR.unexpectedNullCharacter);
1962
+ } else if (cp === $.EOF) {
1963
+ this._emitCurrentToken();
1964
+ this._emitEOFToken();
1216
1965
  }
1217
-
1218
- this._emitChar('<');
1219
- this._emitChar('/');
1220
- this._emitSeveralCodePoints(this.tempBuff);
1221
- this._reconsumeInState(SCRIPT_DATA_ESCAPED_STATE);
1222
1966
  }
1223
- };
1224
-
1225
1967
 
1226
- //12.2.4.28 Script data double escape start state
1227
- //------------------------------------------------------------------
1228
- _[SCRIPT_DATA_DOUBLE_ESCAPE_START_STATE] = function scriptDataDoubleEscapeStartState(cp) {
1229
- if (isWhitespace(cp) || cp === $.SOLIDUS || cp === $.GREATER_THAN_SIGN) {
1230
- this.state = this.isTempBufferEqualToScriptString() ? SCRIPT_DATA_DOUBLE_ESCAPED_STATE : SCRIPT_DATA_ESCAPED_STATE;
1231
- this._emitCodePoint(cp);
1968
+ // CDATA section state
1969
+ //------------------------------------------------------------------
1970
+ [CDATA_SECTION_STATE](cp) {
1971
+ if (cp === $.RIGHT_SQUARE_BRACKET) {
1972
+ this.state = CDATA_SECTION_BRACKET_STATE;
1973
+ } else if (cp === $.EOF) {
1974
+ this._err(ERR.eofInCdata);
1975
+ this._emitEOFToken();
1976
+ } else {
1977
+ this._emitCodePoint(cp);
1978
+ }
1232
1979
  }
1233
1980
 
1234
- else if (isAsciiUpper(cp)) {
1235
- this.tempBuff.push(toAsciiLowerCodePoint(cp));
1236
- this._emitCodePoint(cp);
1981
+ // CDATA section bracket state
1982
+ //------------------------------------------------------------------
1983
+ [CDATA_SECTION_BRACKET_STATE](cp) {
1984
+ if (cp === $.RIGHT_SQUARE_BRACKET) {
1985
+ this.state = CDATA_SECTION_END_STATE;
1986
+ } else {
1987
+ this._emitChars(']');
1988
+ this._reconsumeInState(CDATA_SECTION_STATE);
1989
+ }
1237
1990
  }
1238
1991
 
1239
- else if (isAsciiLower(cp)) {
1240
- this.tempBuff.push(cp);
1241
- this._emitCodePoint(cp);
1992
+ // CDATA section end state
1993
+ //------------------------------------------------------------------
1994
+ [CDATA_SECTION_END_STATE](cp) {
1995
+ if (cp === $.GREATER_THAN_SIGN) {
1996
+ this.state = DATA_STATE;
1997
+ } else if (cp === $.RIGHT_SQUARE_BRACKET) {
1998
+ this._emitChars(']');
1999
+ } else {
2000
+ this._emitChars(']]');
2001
+ this._reconsumeInState(CDATA_SECTION_STATE);
2002
+ }
1242
2003
  }
1243
2004
 
1244
- else
1245
- this._reconsumeInState(SCRIPT_DATA_ESCAPED_STATE);
1246
- };
1247
-
2005
+ // Character reference state
2006
+ //------------------------------------------------------------------
2007
+ [CHARACTER_REFERENCE_STATE](cp) {
2008
+ this.tempBuff = [$.AMPERSAND];
1248
2009
 
1249
- //12.2.4.29 Script data double escaped state
1250
- //------------------------------------------------------------------
1251
- _[SCRIPT_DATA_DOUBLE_ESCAPED_STATE] = function scriptDataDoubleEscapedState(cp) {
1252
- if (cp === $.HYPHEN_MINUS) {
1253
- this.state = SCRIPT_DATA_DOUBLE_ESCAPED_DASH_STATE;
1254
- this._emitChar('-');
1255
- }
1256
-
1257
- else if (cp === $.LESS_THAN_SIGN) {
1258
- this.state = SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN_STATE;
1259
- this._emitChar('<');
2010
+ if (cp === $.NUMBER_SIGN) {
2011
+ this.tempBuff.push(cp);
2012
+ this.state = NUMERIC_CHARACTER_REFERENCE_STATE;
2013
+ } else if (isAsciiAlphaNumeric(cp)) {
2014
+ this._reconsumeInState(NAMED_CHARACTER_REFERENCE_STATE);
2015
+ } else {
2016
+ this._flushCodePointsConsumedAsCharacterReference();
2017
+ this._reconsumeInState(this.returnState);
2018
+ }
1260
2019
  }
1261
2020
 
1262
- else if (cp === $.NULL)
1263
- this._emitChar(UNICODE.REPLACEMENT_CHARACTER);
1264
-
1265
- else if (cp === $.EOF)
1266
- this._reconsumeInState(DATA_STATE);
1267
-
1268
- else
1269
- this._emitCodePoint(cp);
1270
- };
2021
+ // Named character reference state
2022
+ //------------------------------------------------------------------
2023
+ [NAMED_CHARACTER_REFERENCE_STATE](cp) {
2024
+ const matchResult = this._matchNamedCharacterReference(cp);
1271
2025
 
2026
+ //NOTE: matching can be abrupted by hibernation. In that case match
2027
+ //results are no longer valid and we will need to start over.
2028
+ if (this._ensureHibernation()) {
2029
+ this.tempBuff = [$.AMPERSAND];
2030
+ } else if (matchResult) {
2031
+ const withSemicolon = this.tempBuff[this.tempBuff.length - 1] === $.SEMICOLON;
1272
2032
 
1273
- //12.2.4.30 Script data double escaped dash state
1274
- //------------------------------------------------------------------
1275
- _[SCRIPT_DATA_DOUBLE_ESCAPED_DASH_STATE] = function scriptDataDoubleEscapedDashState(cp) {
1276
- if (cp === $.HYPHEN_MINUS) {
1277
- this.state = SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH_STATE;
1278
- this._emitChar('-');
1279
- }
2033
+ if (!this._isCharacterReferenceAttributeQuirk(withSemicolon)) {
2034
+ if (!withSemicolon) {
2035
+ this._errOnNextCodePoint(ERR.missingSemicolonAfterCharacterReference);
2036
+ }
1280
2037
 
1281
- else if (cp === $.LESS_THAN_SIGN) {
1282
- this.state = SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN_STATE;
1283
- this._emitChar('<');
1284
- }
2038
+ this.tempBuff = matchResult;
2039
+ }
1285
2040
 
1286
- else if (cp === $.NULL) {
1287
- this.state = SCRIPT_DATA_DOUBLE_ESCAPED_STATE;
1288
- this._emitChar(UNICODE.REPLACEMENT_CHARACTER);
2041
+ this._flushCodePointsConsumedAsCharacterReference();
2042
+ this.state = this.returnState;
2043
+ } else {
2044
+ this._flushCodePointsConsumedAsCharacterReference();
2045
+ this.state = AMBIGUOUS_AMPERSAND_STATE;
2046
+ }
1289
2047
  }
1290
2048
 
1291
- else if (cp === $.EOF)
1292
- this._reconsumeInState(DATA_STATE);
2049
+ // Ambiguos ampersand state
2050
+ //------------------------------------------------------------------
2051
+ [AMBIGUOUS_AMPERSAND_STATE](cp) {
2052
+ if (isAsciiAlphaNumeric(cp)) {
2053
+ if (this._isCharacterReferenceInAttribute()) {
2054
+ this.currentAttr.value += toChar(cp);
2055
+ } else {
2056
+ this._emitCodePoint(cp);
2057
+ }
2058
+ } else {
2059
+ if (cp === $.SEMICOLON) {
2060
+ this._err(ERR.unknownNamedCharacterReference);
2061
+ }
1293
2062
 
1294
- else {
1295
- this.state = SCRIPT_DATA_DOUBLE_ESCAPED_STATE;
1296
- this._emitCodePoint(cp);
2063
+ this._reconsumeInState(this.returnState);
2064
+ }
1297
2065
  }
1298
- };
1299
2066
 
2067
+ // Numeric character reference state
2068
+ //------------------------------------------------------------------
2069
+ [NUMERIC_CHARACTER_REFERENCE_STATE](cp) {
2070
+ this.charRefCode = 0;
1300
2071
 
1301
- //12.2.4.31 Script data double escaped dash dash state
1302
- //------------------------------------------------------------------
1303
- _[SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH_STATE] = function scriptDataDoubleEscapedDashDashState(cp) {
1304
- if (cp === $.HYPHEN_MINUS)
1305
- this._emitChar('-');
1306
-
1307
- else if (cp === $.LESS_THAN_SIGN) {
1308
- this.state = SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN_STATE;
1309
- this._emitChar('<');
2072
+ if (cp === $.LATIN_SMALL_X || cp === $.LATIN_CAPITAL_X) {
2073
+ this.tempBuff.push(cp);
2074
+ this.state = HEXADEMICAL_CHARACTER_REFERENCE_START_STATE;
2075
+ } else {
2076
+ this._reconsumeInState(DECIMAL_CHARACTER_REFERENCE_START_STATE);
2077
+ }
1310
2078
  }
1311
2079
 
1312
- else if (cp === $.GREATER_THAN_SIGN) {
1313
- this.state = SCRIPT_DATA_STATE;
1314
- this._emitChar('>');
2080
+ // Hexademical character reference start state
2081
+ //------------------------------------------------------------------
2082
+ [HEXADEMICAL_CHARACTER_REFERENCE_START_STATE](cp) {
2083
+ if (isAsciiHexDigit(cp)) {
2084
+ this._reconsumeInState(HEXADEMICAL_CHARACTER_REFERENCE_STATE);
2085
+ } else {
2086
+ this._err(ERR.absenceOfDigitsInNumericCharacterReference);
2087
+ this._flushCodePointsConsumedAsCharacterReference();
2088
+ this._reconsumeInState(this.returnState);
2089
+ }
1315
2090
  }
1316
2091
 
1317
- else if (cp === $.NULL) {
1318
- this.state = SCRIPT_DATA_DOUBLE_ESCAPED_STATE;
1319
- this._emitChar(UNICODE.REPLACEMENT_CHARACTER);
2092
+ // Decimal character reference start state
2093
+ //------------------------------------------------------------------
2094
+ [DECIMAL_CHARACTER_REFERENCE_START_STATE](cp) {
2095
+ if (isAsciiDigit(cp)) {
2096
+ this._reconsumeInState(DECIMAL_CHARACTER_REFERENCE_STATE);
2097
+ } else {
2098
+ this._err(ERR.absenceOfDigitsInNumericCharacterReference);
2099
+ this._flushCodePointsConsumedAsCharacterReference();
2100
+ this._reconsumeInState(this.returnState);
2101
+ }
1320
2102
  }
1321
2103
 
1322
- else if (cp === $.EOF)
1323
- this._reconsumeInState(DATA_STATE);
1324
-
1325
- else {
1326
- this.state = SCRIPT_DATA_DOUBLE_ESCAPED_STATE;
1327
- this._emitCodePoint(cp);
2104
+ // Hexademical character reference state
2105
+ //------------------------------------------------------------------
2106
+ [HEXADEMICAL_CHARACTER_REFERENCE_STATE](cp) {
2107
+ if (isAsciiUpperHexDigit(cp)) {
2108
+ this.charRefCode = this.charRefCode * 16 + cp - 0x37;
2109
+ } else if (isAsciiLowerHexDigit(cp)) {
2110
+ this.charRefCode = this.charRefCode * 16 + cp - 0x57;
2111
+ } else if (isAsciiDigit(cp)) {
2112
+ this.charRefCode = this.charRefCode * 16 + cp - 0x30;
2113
+ } else if (cp === $.SEMICOLON) {
2114
+ this.state = NUMERIC_CHARACTER_REFERENCE_END_STATE;
2115
+ } else {
2116
+ this._err(ERR.missingSemicolonAfterCharacterReference);
2117
+ this._reconsumeInState(NUMERIC_CHARACTER_REFERENCE_END_STATE);
2118
+ }
1328
2119
  }
1329
- };
1330
-
1331
2120
 
1332
- //12.2.4.32 Script data double escaped less-than sign state
1333
- //------------------------------------------------------------------
1334
- _[SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN_STATE] = function scriptDataDoubleEscapedLessThanSignState(cp) {
1335
- if (cp === $.SOLIDUS) {
1336
- this.tempBuff = [];
1337
- this.state = SCRIPT_DATA_DOUBLE_ESCAPE_END_STATE;
1338
- this._emitChar('/');
2121
+ // Decimal character reference state
2122
+ //------------------------------------------------------------------
2123
+ [DECIMAL_CHARACTER_REFERENCE_STATE](cp) {
2124
+ if (isAsciiDigit(cp)) {
2125
+ this.charRefCode = this.charRefCode * 10 + cp - 0x30;
2126
+ } else if (cp === $.SEMICOLON) {
2127
+ this.state = NUMERIC_CHARACTER_REFERENCE_END_STATE;
2128
+ } else {
2129
+ this._err(ERR.missingSemicolonAfterCharacterReference);
2130
+ this._reconsumeInState(NUMERIC_CHARACTER_REFERENCE_END_STATE);
2131
+ }
1339
2132
  }
1340
2133
 
1341
- else
1342
- this._reconsumeInState(SCRIPT_DATA_DOUBLE_ESCAPED_STATE);
1343
- };
1344
-
1345
-
1346
- //12.2.4.33 Script data double escape end state
1347
- //------------------------------------------------------------------
1348
- _[SCRIPT_DATA_DOUBLE_ESCAPE_END_STATE] = function scriptDataDoubleEscapeEndState(cp) {
1349
- if (isWhitespace(cp) || cp === $.SOLIDUS || cp === $.GREATER_THAN_SIGN) {
1350
- this.state = this.isTempBufferEqualToScriptString() ? SCRIPT_DATA_ESCAPED_STATE : SCRIPT_DATA_DOUBLE_ESCAPED_STATE;
2134
+ // Numeric character reference end state
2135
+ //------------------------------------------------------------------
2136
+ [NUMERIC_CHARACTER_REFERENCE_END_STATE]() {
2137
+ if (this.charRefCode === $.NULL) {
2138
+ this._err(ERR.nullCharacterReference);
2139
+ this.charRefCode = $.REPLACEMENT_CHARACTER;
2140
+ } else if (this.charRefCode > 0x10ffff) {
2141
+ this._err(ERR.characterReferenceOutsideUnicodeRange);
2142
+ this.charRefCode = $.REPLACEMENT_CHARACTER;
2143
+ } else if (unicode.isSurrogate(this.charRefCode)) {
2144
+ this._err(ERR.surrogateCharacterReference);
2145
+ this.charRefCode = $.REPLACEMENT_CHARACTER;
2146
+ } else if (unicode.isUndefinedCodePoint(this.charRefCode)) {
2147
+ this._err(ERR.noncharacterCharacterReference);
2148
+ } else if (unicode.isControlCodePoint(this.charRefCode) || this.charRefCode === $.CARRIAGE_RETURN) {
2149
+ this._err(ERR.controlCharacterReference);
2150
+
2151
+ const replacement = C1_CONTROLS_REFERENCE_REPLACEMENTS[this.charRefCode];
2152
+
2153
+ if (replacement) {
2154
+ this.charRefCode = replacement;
2155
+ }
2156
+ }
1351
2157
 
1352
- this._emitCodePoint(cp);
1353
- }
2158
+ this.tempBuff = [this.charRefCode];
1354
2159
 
1355
- else if (isAsciiUpper(cp)) {
1356
- this.tempBuff.push(toAsciiLowerCodePoint(cp));
1357
- this._emitCodePoint(cp);
2160
+ this._flushCodePointsConsumedAsCharacterReference();
2161
+ this._reconsumeInState(this.returnState);
1358
2162
  }
2163
+ }
1359
2164
 
1360
- else if (isAsciiLower(cp)) {
1361
- this.tempBuff.push(cp);
1362
- this._emitCodePoint(cp);
1363
- }
2165
+ //Token types
2166
+ Tokenizer.CHARACTER_TOKEN = 'CHARACTER_TOKEN';
2167
+ Tokenizer.NULL_CHARACTER_TOKEN = 'NULL_CHARACTER_TOKEN';
2168
+ Tokenizer.WHITESPACE_CHARACTER_TOKEN = 'WHITESPACE_CHARACTER_TOKEN';
2169
+ Tokenizer.START_TAG_TOKEN = 'START_TAG_TOKEN';
2170
+ Tokenizer.END_TAG_TOKEN = 'END_TAG_TOKEN';
2171
+ Tokenizer.COMMENT_TOKEN = 'COMMENT_TOKEN';
2172
+ Tokenizer.DOCTYPE_TOKEN = 'DOCTYPE_TOKEN';
2173
+ Tokenizer.EOF_TOKEN = 'EOF_TOKEN';
2174
+ Tokenizer.HIBERNATION_TOKEN = 'HIBERNATION_TOKEN';
1364
2175
 
1365
- else
1366
- this._reconsumeInState(SCRIPT_DATA_DOUBLE_ESCAPED_STATE);
2176
+ //Tokenizer initial states for different modes
2177
+ Tokenizer.MODE = {
2178
+ DATA: DATA_STATE,
2179
+ RCDATA: RCDATA_STATE,
2180
+ RAWTEXT: RAWTEXT_STATE,
2181
+ SCRIPT_DATA: SCRIPT_DATA_STATE,
2182
+ PLAINTEXT: PLAINTEXT_STATE
1367
2183
  };
1368
2184
 
1369
-
1370
- //12.2.4.34 Before attribute name state
1371
- //------------------------------------------------------------------
1372
- _[BEFORE_ATTRIBUTE_NAME_STATE] = function beforeAttributeNameState(cp) {
1373
- if (isWhitespace(cp))
1374
- return;
1375
-
1376
- if (cp === $.SOLIDUS || cp === $.GREATER_THAN_SIGN || cp === $.EOF)
1377
- this._reconsumeInState(AFTER_ATTRIBUTE_NAME_STATE);
1378
-
1379
- else if (cp === $.EQUALS_SIGN) {
1380
- this._createAttr('=');
1381
- this.state = ATTRIBUTE_NAME_STATE;
2185
+ //Static
2186
+ Tokenizer.getTokenAttr = function(token, attrName) {
2187
+ for (let i = token.attrs.length - 1; i >= 0; i--) {
2188
+ if (token.attrs[i].name === attrName) {
2189
+ return token.attrs[i].value;
2190
+ }
1382
2191
  }
1383
2192
 
1384
- else {
1385
- this._createAttr('');
1386
- this._reconsumeInState(ATTRIBUTE_NAME_STATE);
1387
- }
2193
+ return null;
1388
2194
  };
1389
2195
 
1390
-
1391
- //12.2.4.35 Attribute name state
1392
- //------------------------------------------------------------------
1393
- _[ATTRIBUTE_NAME_STATE] = function attributeNameState(cp) {
1394
- if (isWhitespace(cp) || cp === $.SOLIDUS || cp === $.GREATER_THAN_SIGN || cp === $.EOF) {
1395
- this._leaveAttrName(AFTER_ATTRIBUTE_NAME_STATE);
1396
- this._unconsume();
1397
- }
1398
-
1399
- else if (cp === $.EQUALS_SIGN)
1400
- this._leaveAttrName(BEFORE_ATTRIBUTE_VALUE_STATE);
1401
-
1402
- else if (isAsciiUpper(cp))
1403
- this.currentAttr.name += toAsciiLowerChar(cp);
1404
-
1405
- else if (cp === $.QUOTATION_MARK || cp === $.APOSTROPHE || cp === $.LESS_THAN_SIGN)
1406
- this.currentAttr.name += toChar(cp);
1407
-
1408
- else if (cp === $.NULL)
1409
- this.currentAttr.name += UNICODE.REPLACEMENT_CHARACTER;
1410
-
1411
- else
1412
- this.currentAttr.name += toChar(cp);
1413
- };
1414
-
1415
-
1416
- //12.2.4.36 After attribute name state
1417
- //------------------------------------------------------------------
1418
- _[AFTER_ATTRIBUTE_NAME_STATE] = function afterAttributeNameState(cp) {
1419
- if (isWhitespace(cp))
1420
- return;
1421
-
1422
- if (cp === $.SOLIDUS)
1423
- this.state = SELF_CLOSING_START_TAG_STATE;
1424
-
1425
- else if (cp === $.EQUALS_SIGN)
1426
- this.state = BEFORE_ATTRIBUTE_VALUE_STATE;
1427
-
1428
- else if (cp === $.GREATER_THAN_SIGN) {
1429
- this.state = DATA_STATE;
1430
- this._emitCurrentToken();
1431
- }
1432
-
1433
- else if (cp === $.EOF)
1434
- this._reconsumeInState(DATA_STATE);
1435
-
1436
- else {
1437
- this._createAttr('');
1438
- this._reconsumeInState(ATTRIBUTE_NAME_STATE);
1439
- }
1440
- };
1441
-
1442
-
1443
- //12.2.4.37 Before attribute value state
1444
- //------------------------------------------------------------------
1445
- _[BEFORE_ATTRIBUTE_VALUE_STATE] = function beforeAttributeValueState(cp) {
1446
- if (isWhitespace(cp))
1447
- return;
1448
-
1449
- if (cp === $.QUOTATION_MARK)
1450
- this.state = ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE;
1451
-
1452
- else if (cp === $.APOSTROPHE)
1453
- this.state = ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE;
1454
-
1455
- else
1456
- this._reconsumeInState(ATTRIBUTE_VALUE_UNQUOTED_STATE);
1457
- };
1458
-
1459
-
1460
- //12.2.4.38 Attribute value (double-quoted) state
1461
- //------------------------------------------------------------------
1462
- _[ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE] = function attributeValueDoubleQuotedState(cp) {
1463
- if (cp === $.QUOTATION_MARK)
1464
- this.state = AFTER_ATTRIBUTE_VALUE_QUOTED_STATE;
1465
-
1466
- else if (cp === $.AMPERSAND) {
1467
- this.additionalAllowedCp = $.QUOTATION_MARK;
1468
- this.returnState = this.state;
1469
- this.state = CHARACTER_REFERENCE_IN_ATTRIBUTE_VALUE_STATE;
1470
- }
1471
-
1472
- else if (cp === $.NULL)
1473
- this.currentAttr.value += UNICODE.REPLACEMENT_CHARACTER;
1474
-
1475
- else if (cp === $.EOF)
1476
- this._reconsumeInState(DATA_STATE);
1477
-
1478
- else
1479
- this.currentAttr.value += toChar(cp);
1480
- };
1481
-
1482
-
1483
- //12.2.4.39 Attribute value (single-quoted) state
1484
- //------------------------------------------------------------------
1485
- _[ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE] = function attributeValueSingleQuotedState(cp) {
1486
- if (cp === $.APOSTROPHE)
1487
- this.state = AFTER_ATTRIBUTE_VALUE_QUOTED_STATE;
1488
-
1489
- else if (cp === $.AMPERSAND) {
1490
- this.additionalAllowedCp = $.APOSTROPHE;
1491
- this.returnState = this.state;
1492
- this.state = CHARACTER_REFERENCE_IN_ATTRIBUTE_VALUE_STATE;
1493
- }
1494
-
1495
- else if (cp === $.NULL)
1496
- this.currentAttr.value += UNICODE.REPLACEMENT_CHARACTER;
1497
-
1498
- else if (cp === $.EOF)
1499
- this._reconsumeInState(DATA_STATE);
1500
-
1501
- else
1502
- this.currentAttr.value += toChar(cp);
1503
- };
1504
-
1505
-
1506
- //12.2.4.40 Attribute value (unquoted) state
1507
- //------------------------------------------------------------------
1508
- _[ATTRIBUTE_VALUE_UNQUOTED_STATE] = function attributeValueUnquotedState(cp) {
1509
- if (isWhitespace(cp))
1510
- this._leaveAttrValue(BEFORE_ATTRIBUTE_NAME_STATE);
1511
-
1512
- else if (cp === $.AMPERSAND) {
1513
- this.additionalAllowedCp = $.GREATER_THAN_SIGN;
1514
- this.returnState = this.state;
1515
- this.state = CHARACTER_REFERENCE_IN_ATTRIBUTE_VALUE_STATE;
1516
- }
1517
-
1518
- else if (cp === $.GREATER_THAN_SIGN) {
1519
- this._leaveAttrValue(DATA_STATE);
1520
- this._emitCurrentToken();
1521
- }
1522
-
1523
- else if (cp === $.NULL)
1524
- this.currentAttr.value += UNICODE.REPLACEMENT_CHARACTER;
1525
-
1526
- else if (cp === $.QUOTATION_MARK || cp === $.APOSTROPHE || cp === $.LESS_THAN_SIGN ||
1527
- cp === $.EQUALS_SIGN || cp === $.GRAVE_ACCENT)
1528
- this.currentAttr.value += toChar(cp);
1529
-
1530
- else if (cp === $.EOF)
1531
- this._reconsumeInState(DATA_STATE);
1532
-
1533
- else
1534
- this.currentAttr.value += toChar(cp);
1535
- };
1536
-
1537
-
1538
- //12.2.4.41 Character reference in attribute value state
1539
- //------------------------------------------------------------------
1540
- _[CHARACTER_REFERENCE_IN_ATTRIBUTE_VALUE_STATE] = function characterReferenceInAttributeValueState(cp) {
1541
- var referencedCodePoints = this._consumeCharacterReference(cp, true);
1542
-
1543
- if (!this._ensureHibernation()) {
1544
- if (referencedCodePoints) {
1545
- for (var i = 0; i < referencedCodePoints.length; i++)
1546
- this.currentAttr.value += toChar(referencedCodePoints[i]);
1547
- }
1548
- else
1549
- this.currentAttr.value += '&';
1550
-
1551
- this.state = this.returnState;
1552
- }
1553
- };
1554
-
1555
-
1556
- //12.2.4.42 After attribute value (quoted) state
1557
- //------------------------------------------------------------------
1558
- _[AFTER_ATTRIBUTE_VALUE_QUOTED_STATE] = function afterAttributeValueQuotedState(cp) {
1559
- if (isWhitespace(cp))
1560
- this._leaveAttrValue(BEFORE_ATTRIBUTE_NAME_STATE);
1561
-
1562
- else if (cp === $.SOLIDUS)
1563
- this._leaveAttrValue(SELF_CLOSING_START_TAG_STATE);
1564
-
1565
- else if (cp === $.GREATER_THAN_SIGN) {
1566
- this._leaveAttrValue(DATA_STATE);
1567
- this._emitCurrentToken();
1568
- }
1569
-
1570
- else if (cp === $.EOF)
1571
- this._reconsumeInState(DATA_STATE);
1572
-
1573
- else
1574
- this._reconsumeInState(BEFORE_ATTRIBUTE_NAME_STATE);
1575
- };
1576
-
1577
-
1578
- //12.2.4.43 Self-closing start tag state
1579
- //------------------------------------------------------------------
1580
- _[SELF_CLOSING_START_TAG_STATE] = function selfClosingStartTagState(cp) {
1581
- if (cp === $.GREATER_THAN_SIGN) {
1582
- this.currentToken.selfClosing = true;
1583
- this.state = DATA_STATE;
1584
- this._emitCurrentToken();
1585
- }
1586
-
1587
- else if (cp === $.EOF)
1588
- this._reconsumeInState(DATA_STATE);
1589
-
1590
- else
1591
- this._reconsumeInState(BEFORE_ATTRIBUTE_NAME_STATE);
1592
- };
1593
-
1594
-
1595
- //12.2.4.44 Bogus comment state
1596
- //------------------------------------------------------------------
1597
- _[BOGUS_COMMENT_STATE] = function bogusCommentState() {
1598
- this._createCommentToken();
1599
- this._reconsumeInState(BOGUS_COMMENT_STATE_CONTINUATION);
1600
- };
1601
-
1602
- //HACK: to support streaming and make BOGUS_COMMENT_STATE reentrant we've
1603
- //introduced BOGUS_COMMENT_STATE_CONTINUATION state which will not produce
1604
- //comment token on each call.
1605
- _[BOGUS_COMMENT_STATE_CONTINUATION] = function bogusCommentStateContinuation(cp) {
1606
- while (true) {
1607
- if (cp === $.GREATER_THAN_SIGN) {
1608
- this.state = DATA_STATE;
1609
- break;
1610
- }
1611
-
1612
- else if (cp === $.EOF) {
1613
- this._reconsumeInState(DATA_STATE);
1614
- break;
1615
- }
1616
-
1617
- else {
1618
- this.currentToken.data += cp === $.NULL ? UNICODE.REPLACEMENT_CHARACTER : toChar(cp);
1619
-
1620
- this._hibernationSnapshot();
1621
- cp = this._consume();
1622
-
1623
- if (this._ensureHibernation())
1624
- return;
1625
- }
1626
- }
1627
-
1628
- this._emitCurrentToken();
1629
- };
1630
-
1631
- //12.2.4.45 Markup declaration open state
1632
- //------------------------------------------------------------------
1633
- _[MARKUP_DECLARATION_OPEN_STATE] = function markupDeclarationOpenState(cp) {
1634
- var dashDashMatch = this._consumeSubsequentIfMatch($$.DASH_DASH_STRING, cp, true),
1635
- doctypeMatch = !dashDashMatch && this._consumeSubsequentIfMatch($$.DOCTYPE_STRING, cp, false),
1636
- cdataMatch = !dashDashMatch && !doctypeMatch &&
1637
- this.allowCDATA &&
1638
- this._consumeSubsequentIfMatch($$.CDATA_START_STRING, cp, true);
1639
-
1640
- if (!this._ensureHibernation()) {
1641
- if (dashDashMatch) {
1642
- this._createCommentToken();
1643
- this.state = COMMENT_START_STATE;
1644
- }
1645
-
1646
- else if (doctypeMatch)
1647
- this.state = DOCTYPE_STATE;
1648
-
1649
- else if (cdataMatch)
1650
- this.state = CDATA_SECTION_STATE;
1651
-
1652
- else
1653
- this._reconsumeInState(BOGUS_COMMENT_STATE);
1654
- }
1655
- };
1656
-
1657
-
1658
- //12.2.4.46 Comment start state
1659
- //------------------------------------------------------------------
1660
- _[COMMENT_START_STATE] = function commentStartState(cp) {
1661
- if (cp === $.HYPHEN_MINUS)
1662
- this.state = COMMENT_START_DASH_STATE;
1663
-
1664
- else if (cp === $.NULL) {
1665
- this.currentToken.data += UNICODE.REPLACEMENT_CHARACTER;
1666
- this.state = COMMENT_STATE;
1667
- }
1668
-
1669
- else if (cp === $.GREATER_THAN_SIGN) {
1670
- this.state = DATA_STATE;
1671
- this._emitCurrentToken();
1672
- }
1673
-
1674
- else if (cp === $.EOF) {
1675
- this._emitCurrentToken();
1676
- this._reconsumeInState(DATA_STATE);
1677
- }
1678
-
1679
- else {
1680
- this.currentToken.data += toChar(cp);
1681
- this.state = COMMENT_STATE;
1682
- }
1683
- };
1684
-
1685
-
1686
- //12.2.4.47 Comment start dash state
1687
- //------------------------------------------------------------------
1688
- _[COMMENT_START_DASH_STATE] = function commentStartDashState(cp) {
1689
- if (cp === $.HYPHEN_MINUS)
1690
- this.state = COMMENT_END_STATE;
1691
-
1692
- else if (cp === $.NULL) {
1693
- this.currentToken.data += '-';
1694
- this.currentToken.data += UNICODE.REPLACEMENT_CHARACTER;
1695
- this.state = COMMENT_STATE;
1696
- }
1697
-
1698
- else if (cp === $.GREATER_THAN_SIGN) {
1699
- this.state = DATA_STATE;
1700
- this._emitCurrentToken();
1701
- }
1702
-
1703
- else if (cp === $.EOF) {
1704
- this._emitCurrentToken();
1705
- this._reconsumeInState(DATA_STATE);
1706
- }
1707
-
1708
- else {
1709
- this.currentToken.data += '-';
1710
- this.currentToken.data += toChar(cp);
1711
- this.state = COMMENT_STATE;
1712
- }
1713
- };
1714
-
1715
-
1716
- //12.2.4.48 Comment state
1717
- //------------------------------------------------------------------
1718
- _[COMMENT_STATE] = function commentState(cp) {
1719
- if (cp === $.HYPHEN_MINUS)
1720
- this.state = COMMENT_END_DASH_STATE;
1721
-
1722
- else if (cp === $.NULL)
1723
- this.currentToken.data += UNICODE.REPLACEMENT_CHARACTER;
1724
-
1725
- else if (cp === $.EOF) {
1726
- this._emitCurrentToken();
1727
- this._reconsumeInState(DATA_STATE);
1728
- }
1729
-
1730
- else
1731
- this.currentToken.data += toChar(cp);
1732
- };
1733
-
1734
-
1735
- //12.2.4.49 Comment end dash state
1736
- //------------------------------------------------------------------
1737
- _[COMMENT_END_DASH_STATE] = function commentEndDashState(cp) {
1738
- if (cp === $.HYPHEN_MINUS)
1739
- this.state = COMMENT_END_STATE;
1740
-
1741
- else if (cp === $.NULL) {
1742
- this.currentToken.data += '-';
1743
- this.currentToken.data += UNICODE.REPLACEMENT_CHARACTER;
1744
- this.state = COMMENT_STATE;
1745
- }
1746
-
1747
- else if (cp === $.EOF) {
1748
- this._emitCurrentToken();
1749
- this._reconsumeInState(DATA_STATE);
1750
- }
1751
-
1752
- else {
1753
- this.currentToken.data += '-';
1754
- this.currentToken.data += toChar(cp);
1755
- this.state = COMMENT_STATE;
1756
- }
1757
- };
1758
-
1759
-
1760
- //12.2.4.50 Comment end state
1761
- //------------------------------------------------------------------
1762
- _[COMMENT_END_STATE] = function commentEndState(cp) {
1763
- if (cp === $.GREATER_THAN_SIGN) {
1764
- this.state = DATA_STATE;
1765
- this._emitCurrentToken();
1766
- }
1767
-
1768
- else if (cp === $.EXCLAMATION_MARK)
1769
- this.state = COMMENT_END_BANG_STATE;
1770
-
1771
- else if (cp === $.HYPHEN_MINUS)
1772
- this.currentToken.data += '-';
1773
-
1774
- else if (cp === $.NULL) {
1775
- this.currentToken.data += '--';
1776
- this.currentToken.data += UNICODE.REPLACEMENT_CHARACTER;
1777
- this.state = COMMENT_STATE;
1778
- }
1779
-
1780
- else if (cp === $.EOF) {
1781
- this._reconsumeInState(DATA_STATE);
1782
- this._emitCurrentToken();
1783
- }
1784
-
1785
- else {
1786
- this.currentToken.data += '--';
1787
- this.currentToken.data += toChar(cp);
1788
- this.state = COMMENT_STATE;
1789
- }
1790
- };
1791
-
1792
-
1793
- //12.2.4.51 Comment end bang state
1794
- //------------------------------------------------------------------
1795
- _[COMMENT_END_BANG_STATE] = function commentEndBangState(cp) {
1796
- if (cp === $.HYPHEN_MINUS) {
1797
- this.currentToken.data += '--!';
1798
- this.state = COMMENT_END_DASH_STATE;
1799
- }
1800
-
1801
- else if (cp === $.GREATER_THAN_SIGN) {
1802
- this.state = DATA_STATE;
1803
- this._emitCurrentToken();
1804
- }
1805
-
1806
- else if (cp === $.NULL) {
1807
- this.currentToken.data += '--!';
1808
- this.currentToken.data += UNICODE.REPLACEMENT_CHARACTER;
1809
- this.state = COMMENT_STATE;
1810
- }
1811
-
1812
- else if (cp === $.EOF) {
1813
- this._emitCurrentToken();
1814
- this._reconsumeInState(DATA_STATE);
1815
- }
1816
-
1817
- else {
1818
- this.currentToken.data += '--!';
1819
- this.currentToken.data += toChar(cp);
1820
- this.state = COMMENT_STATE;
1821
- }
1822
- };
1823
-
1824
-
1825
- //12.2.4.52 DOCTYPE state
1826
- //------------------------------------------------------------------
1827
- _[DOCTYPE_STATE] = function doctypeState(cp) {
1828
- if (isWhitespace(cp))
1829
- return;
1830
-
1831
- else if (cp === $.GREATER_THAN_SIGN) {
1832
- this._createDoctypeToken(null);
1833
- this.currentToken.forceQuirks = true;
1834
- this._emitCurrentToken();
1835
- this.state = DATA_STATE;
1836
- }
1837
-
1838
- else if (cp === $.EOF) {
1839
- this._createDoctypeToken(null);
1840
- this.currentToken.forceQuirks = true;
1841
- this._emitCurrentToken();
1842
- this._reconsumeInState(DATA_STATE);
1843
- }
1844
- else {
1845
- this._createDoctypeToken('');
1846
- this._reconsumeInState(DOCTYPE_NAME_STATE);
1847
- }
1848
- };
1849
-
1850
-
1851
- //12.2.4.54 DOCTYPE name state
1852
- //------------------------------------------------------------------
1853
- _[DOCTYPE_NAME_STATE] = function doctypeNameState(cp) {
1854
- if (isWhitespace(cp) || cp === $.GREATER_THAN_SIGN || cp === $.EOF)
1855
- this._reconsumeInState(AFTER_DOCTYPE_NAME_STATE);
1856
-
1857
- else if (isAsciiUpper(cp))
1858
- this.currentToken.name += toAsciiLowerChar(cp);
1859
-
1860
- else if (cp === $.NULL)
1861
- this.currentToken.name += UNICODE.REPLACEMENT_CHARACTER;
1862
-
1863
- else
1864
- this.currentToken.name += toChar(cp);
1865
- };
1866
-
1867
-
1868
- //12.2.4.55 After DOCTYPE name state
1869
- //------------------------------------------------------------------
1870
- _[AFTER_DOCTYPE_NAME_STATE] = function afterDoctypeNameState(cp) {
1871
- if (isWhitespace(cp))
1872
- return;
1873
-
1874
- if (cp === $.GREATER_THAN_SIGN) {
1875
- this.state = DATA_STATE;
1876
- this._emitCurrentToken();
1877
- }
1878
-
1879
- else {
1880
- var publicMatch = this._consumeSubsequentIfMatch($$.PUBLIC_STRING, cp, false),
1881
- systemMatch = !publicMatch && this._consumeSubsequentIfMatch($$.SYSTEM_STRING, cp, false);
1882
-
1883
- if (!this._ensureHibernation()) {
1884
- if (publicMatch)
1885
- this.state = BEFORE_DOCTYPE_PUBLIC_IDENTIFIER_STATE;
1886
-
1887
- else if (systemMatch)
1888
- this.state = BEFORE_DOCTYPE_SYSTEM_IDENTIFIER_STATE;
1889
-
1890
- else {
1891
- this.currentToken.forceQuirks = true;
1892
- this.state = BOGUS_DOCTYPE_STATE;
1893
- }
1894
- }
1895
- }
1896
- };
1897
-
1898
-
1899
- //12.2.4.57 Before DOCTYPE public identifier state
1900
- //------------------------------------------------------------------
1901
- _[BEFORE_DOCTYPE_PUBLIC_IDENTIFIER_STATE] = function beforeDoctypePublicIdentifierState(cp) {
1902
- if (isWhitespace(cp))
1903
- return;
1904
-
1905
- if (cp === $.QUOTATION_MARK) {
1906
- this.currentToken.publicId = '';
1907
- this.state = DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED_STATE;
1908
- }
1909
-
1910
- else if (cp === $.APOSTROPHE) {
1911
- this.currentToken.publicId = '';
1912
- this.state = DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED_STATE;
1913
- }
1914
-
1915
- else {
1916
- this.currentToken.forceQuirks = true;
1917
- this._reconsumeInState(BOGUS_DOCTYPE_STATE);
1918
- }
1919
- };
1920
-
1921
-
1922
- //12.2.4.58 DOCTYPE public identifier (double-quoted) state
1923
- //------------------------------------------------------------------
1924
- _[DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED_STATE] = function doctypePublicIdentifierDoubleQuotedState(cp) {
1925
- if (cp === $.QUOTATION_MARK)
1926
- this.state = BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS_STATE;
1927
-
1928
- else if (cp === $.NULL)
1929
- this.currentToken.publicId += UNICODE.REPLACEMENT_CHARACTER;
1930
-
1931
- else if (cp === $.GREATER_THAN_SIGN) {
1932
- this.currentToken.forceQuirks = true;
1933
- this._emitCurrentToken();
1934
- this.state = DATA_STATE;
1935
- }
1936
-
1937
- else if (cp === $.EOF) {
1938
- this.currentToken.forceQuirks = true;
1939
- this._emitCurrentToken();
1940
- this._reconsumeInState(DATA_STATE);
1941
- }
1942
-
1943
- else
1944
- this.currentToken.publicId += toChar(cp);
1945
- };
1946
-
1947
-
1948
- //12.2.4.59 DOCTYPE public identifier (single-quoted) state
1949
- //------------------------------------------------------------------
1950
- _[DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED_STATE] = function doctypePublicIdentifierSingleQuotedState(cp) {
1951
- if (cp === $.APOSTROPHE)
1952
- this.state = BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS_STATE;
1953
-
1954
- else if (cp === $.NULL)
1955
- this.currentToken.publicId += UNICODE.REPLACEMENT_CHARACTER;
1956
-
1957
- else if (cp === $.GREATER_THAN_SIGN) {
1958
- this.currentToken.forceQuirks = true;
1959
- this._emitCurrentToken();
1960
- this.state = DATA_STATE;
1961
- }
1962
-
1963
- else if (cp === $.EOF) {
1964
- this.currentToken.forceQuirks = true;
1965
- this._emitCurrentToken();
1966
- this._reconsumeInState(DATA_STATE);
1967
- }
1968
-
1969
- else
1970
- this.currentToken.publicId += toChar(cp);
1971
- };
1972
-
1973
-
1974
- //12.2.4.61 Between DOCTYPE public and system identifiers state
1975
- //------------------------------------------------------------------
1976
- _[BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS_STATE] = function betweenDoctypePublicAndSystemIdentifiersState(cp) {
1977
- if (isWhitespace(cp))
1978
- return;
1979
-
1980
- if (cp === $.GREATER_THAN_SIGN) {
1981
- this._emitCurrentToken();
1982
- this.state = DATA_STATE;
1983
- }
1984
-
1985
- else if (cp === $.QUOTATION_MARK) {
1986
- this.currentToken.systemId = '';
1987
- this.state = DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE;
1988
- }
1989
-
1990
-
1991
- else if (cp === $.APOSTROPHE) {
1992
- this.currentToken.systemId = '';
1993
- this.state = DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE;
1994
- }
1995
-
1996
- else {
1997
- this.currentToken.forceQuirks = true;
1998
- this._reconsumeInState(BOGUS_DOCTYPE_STATE);
1999
- }
2000
- };
2001
-
2002
-
2003
- //12.2.4.63 Before DOCTYPE system identifier state
2004
- //------------------------------------------------------------------
2005
- _[BEFORE_DOCTYPE_SYSTEM_IDENTIFIER_STATE] = function beforeDoctypeSystemIdentifierState(cp) {
2006
- if (isWhitespace(cp))
2007
- return;
2008
-
2009
- if (cp === $.QUOTATION_MARK) {
2010
- this.currentToken.systemId = '';
2011
- this.state = DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE;
2012
- }
2013
-
2014
- else if (cp === $.APOSTROPHE) {
2015
- this.currentToken.systemId = '';
2016
- this.state = DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE;
2017
- }
2018
-
2019
- else {
2020
- this.currentToken.forceQuirks = true;
2021
- this._reconsumeInState(BOGUS_DOCTYPE_STATE);
2022
- }
2023
- };
2024
-
2025
-
2026
- //12.2.4.64 DOCTYPE system identifier (double-quoted) state
2027
- //------------------------------------------------------------------
2028
- _[DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE] = function doctypeSystemIdentifierDoubleQuotedState(cp) {
2029
- if (cp === $.QUOTATION_MARK)
2030
- this.state = AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE;
2031
-
2032
- else if (cp === $.GREATER_THAN_SIGN) {
2033
- this.currentToken.forceQuirks = true;
2034
- this._emitCurrentToken();
2035
- this.state = DATA_STATE;
2036
- }
2037
-
2038
- else if (cp === $.NULL)
2039
- this.currentToken.systemId += UNICODE.REPLACEMENT_CHARACTER;
2040
-
2041
- else if (cp === $.EOF) {
2042
- this.currentToken.forceQuirks = true;
2043
- this._emitCurrentToken();
2044
- this._reconsumeInState(DATA_STATE);
2045
- }
2046
-
2047
- else
2048
- this.currentToken.systemId += toChar(cp);
2049
- };
2050
-
2051
-
2052
- //12.2.4.65 DOCTYPE system identifier (single-quoted) state
2053
- //------------------------------------------------------------------
2054
- _[DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE] = function doctypeSystemIdentifierSingleQuotedState(cp) {
2055
- if (cp === $.APOSTROPHE)
2056
- this.state = AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE;
2057
-
2058
- else if (cp === $.GREATER_THAN_SIGN) {
2059
- this.currentToken.forceQuirks = true;
2060
- this._emitCurrentToken();
2061
- this.state = DATA_STATE;
2062
- }
2063
-
2064
- else if (cp === $.NULL)
2065
- this.currentToken.systemId += UNICODE.REPLACEMENT_CHARACTER;
2066
-
2067
- else if (cp === $.EOF) {
2068
- this.currentToken.forceQuirks = true;
2069
- this._emitCurrentToken();
2070
- this._reconsumeInState(DATA_STATE);
2071
- }
2072
-
2073
- else
2074
- this.currentToken.systemId += toChar(cp);
2075
- };
2076
-
2077
-
2078
- //12.2.4.66 After DOCTYPE system identifier state
2079
- //------------------------------------------------------------------
2080
- _[AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE] = function afterDoctypeSystemIdentifierState(cp) {
2081
- if (isWhitespace(cp))
2082
- return;
2083
-
2084
- if (cp === $.GREATER_THAN_SIGN) {
2085
- this._emitCurrentToken();
2086
- this.state = DATA_STATE;
2087
- }
2088
-
2089
- else if (cp === $.EOF) {
2090
- this.currentToken.forceQuirks = true;
2091
- this._emitCurrentToken();
2092
- this._reconsumeInState(DATA_STATE);
2093
- }
2094
-
2095
- else
2096
- this.state = BOGUS_DOCTYPE_STATE;
2097
- };
2098
-
2099
-
2100
- //12.2.4.67 Bogus DOCTYPE state
2101
- //------------------------------------------------------------------
2102
- _[BOGUS_DOCTYPE_STATE] = function bogusDoctypeState(cp) {
2103
- if (cp === $.GREATER_THAN_SIGN) {
2104
- this._emitCurrentToken();
2105
- this.state = DATA_STATE;
2106
- }
2107
-
2108
- else if (cp === $.EOF) {
2109
- this._emitCurrentToken();
2110
- this._reconsumeInState(DATA_STATE);
2111
- }
2112
- };
2113
-
2114
-
2115
- //12.2.4.68 CDATA section state
2116
- //------------------------------------------------------------------
2117
- _[CDATA_SECTION_STATE] = function cdataSectionState(cp) {
2118
- while (true) {
2119
- if (cp === $.EOF) {
2120
- this._reconsumeInState(DATA_STATE);
2121
- break;
2122
- }
2123
-
2124
- else {
2125
- var cdataEndMatch = this._consumeSubsequentIfMatch($$.CDATA_END_STRING, cp, true);
2126
-
2127
- if (this._ensureHibernation())
2128
- break;
2129
-
2130
- if (cdataEndMatch) {
2131
- this.state = DATA_STATE;
2132
- break;
2133
- }
2134
-
2135
- this._emitCodePoint(cp);
2136
-
2137
- this._hibernationSnapshot();
2138
- cp = this._consume();
2139
-
2140
- if (this._ensureHibernation())
2141
- break;
2142
- }
2143
- }
2144
- };
2196
+ module.exports = Tokenizer;