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.
- package/README.md +14 -16
- package/lib/common/doctype.js +125 -108
- package/lib/common/error-codes.js +65 -0
- package/lib/common/foreign-content.js +265 -0
- package/lib/common/html.js +102 -102
- package/lib/common/unicode.js +81 -19
- package/lib/extensions/error-reporting/mixin-base.js +43 -0
- package/lib/extensions/error-reporting/parser-mixin.js +52 -0
- package/lib/extensions/error-reporting/preprocessor-mixin.js +24 -0
- package/lib/extensions/error-reporting/tokenizer-mixin.js +17 -0
- package/lib/extensions/location-info/open-element-stack-mixin.js +35 -0
- package/lib/extensions/location-info/parser-mixin.js +222 -0
- package/lib/extensions/location-info/tokenizer-mixin.js +146 -0
- package/lib/extensions/position-tracking/preprocessor-mixin.js +64 -0
- package/lib/index.js +6 -21
- package/lib/parser/formatting-element-list.js +181 -0
- package/lib/parser/index.js +1469 -1332
- package/lib/parser/open-element-stack.js +482 -0
- package/lib/serializer/index.js +136 -122
- package/lib/tokenizer/index.js +1856 -1804
- package/lib/tokenizer/{named_entity_data.js → named-entity-data.js} +1 -1
- package/lib/tokenizer/preprocessor.js +115 -103
- package/lib/tree-adapters/default.js +217 -0
- package/lib/utils/{merge_options.js → merge-options.js} +2 -2
- package/lib/utils/mixin.js +33 -12
- package/package.json +32 -61
- package/LICENSE +0 -19
- package/lib/common/foreign_content.js +0 -260
- package/lib/extensions/location_info/open_element_stack_mixin.js +0 -34
- package/lib/extensions/location_info/parser_mixin.js +0 -213
- package/lib/extensions/location_info/tokenizer_mixin.js +0 -117
- package/lib/extensions/position_tracking/preprocessor_mixin.js +0 -72
- package/lib/index.d.ts +0 -1077
- package/lib/parser/formatting_element_list.js +0 -167
- package/lib/parser/open_element_stack.js +0 -395
- package/lib/parser/parser_stream.js +0 -76
- package/lib/parser/plain_text_conversion_stream.js +0 -20
- package/lib/sax/dev_null_stream.js +0 -14
- package/lib/sax/index.js +0 -118
- package/lib/sax/parser_feedback_simulator.js +0 -153
- package/lib/serializer/serializer_stream.js +0 -28
- package/lib/tree_adapters/default.js +0 -209
- package/lib/tree_adapters/htmlparser2.js +0 -338
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
//Const
|
|
4
|
+
const NOAH_ARK_CAPACITY = 3;
|
|
5
|
+
|
|
6
|
+
//List of formatting elements
|
|
7
|
+
class FormattingElementList {
|
|
8
|
+
constructor(treeAdapter) {
|
|
9
|
+
this.length = 0;
|
|
10
|
+
this.entries = [];
|
|
11
|
+
this.treeAdapter = treeAdapter;
|
|
12
|
+
this.bookmark = null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
//Noah Ark's condition
|
|
16
|
+
//OPTIMIZATION: at first we try to find possible candidates for exclusion using
|
|
17
|
+
//lightweight heuristics without thorough attributes check.
|
|
18
|
+
_getNoahArkConditionCandidates(newElement) {
|
|
19
|
+
const candidates = [];
|
|
20
|
+
|
|
21
|
+
if (this.length >= NOAH_ARK_CAPACITY) {
|
|
22
|
+
const neAttrsLength = this.treeAdapter.getAttrList(newElement).length;
|
|
23
|
+
const neTagName = this.treeAdapter.getTagName(newElement);
|
|
24
|
+
const neNamespaceURI = this.treeAdapter.getNamespaceURI(newElement);
|
|
25
|
+
|
|
26
|
+
for (let i = this.length - 1; i >= 0; i--) {
|
|
27
|
+
const entry = this.entries[i];
|
|
28
|
+
|
|
29
|
+
if (entry.type === FormattingElementList.MARKER_ENTRY) {
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const element = entry.element;
|
|
34
|
+
const elementAttrs = this.treeAdapter.getAttrList(element);
|
|
35
|
+
|
|
36
|
+
const isCandidate =
|
|
37
|
+
this.treeAdapter.getTagName(element) === neTagName &&
|
|
38
|
+
this.treeAdapter.getNamespaceURI(element) === neNamespaceURI &&
|
|
39
|
+
elementAttrs.length === neAttrsLength;
|
|
40
|
+
|
|
41
|
+
if (isCandidate) {
|
|
42
|
+
candidates.push({ idx: i, attrs: elementAttrs });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return candidates.length < NOAH_ARK_CAPACITY ? [] : candidates;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
_ensureNoahArkCondition(newElement) {
|
|
51
|
+
const candidates = this._getNoahArkConditionCandidates(newElement);
|
|
52
|
+
let cLength = candidates.length;
|
|
53
|
+
|
|
54
|
+
if (cLength) {
|
|
55
|
+
const neAttrs = this.treeAdapter.getAttrList(newElement);
|
|
56
|
+
const neAttrsLength = neAttrs.length;
|
|
57
|
+
const neAttrsMap = Object.create(null);
|
|
58
|
+
|
|
59
|
+
//NOTE: build attrs map for the new element so we can perform fast lookups
|
|
60
|
+
for (let i = 0; i < neAttrsLength; i++) {
|
|
61
|
+
const neAttr = neAttrs[i];
|
|
62
|
+
|
|
63
|
+
neAttrsMap[neAttr.name] = neAttr.value;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
for (let i = 0; i < neAttrsLength; i++) {
|
|
67
|
+
for (let j = 0; j < cLength; j++) {
|
|
68
|
+
const cAttr = candidates[j].attrs[i];
|
|
69
|
+
|
|
70
|
+
if (neAttrsMap[cAttr.name] !== cAttr.value) {
|
|
71
|
+
candidates.splice(j, 1);
|
|
72
|
+
cLength--;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (candidates.length < NOAH_ARK_CAPACITY) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
//NOTE: remove bottommost candidates until Noah's Ark condition will not be met
|
|
82
|
+
for (let i = cLength - 1; i >= NOAH_ARK_CAPACITY - 1; i--) {
|
|
83
|
+
this.entries.splice(candidates[i].idx, 1);
|
|
84
|
+
this.length--;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
//Mutations
|
|
90
|
+
insertMarker() {
|
|
91
|
+
this.entries.push({ type: FormattingElementList.MARKER_ENTRY });
|
|
92
|
+
this.length++;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
pushElement(element, token) {
|
|
96
|
+
this._ensureNoahArkCondition(element);
|
|
97
|
+
|
|
98
|
+
this.entries.push({
|
|
99
|
+
type: FormattingElementList.ELEMENT_ENTRY,
|
|
100
|
+
element: element,
|
|
101
|
+
token: token
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
this.length++;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
insertElementAfterBookmark(element, token) {
|
|
108
|
+
let bookmarkIdx = this.length - 1;
|
|
109
|
+
|
|
110
|
+
for (; bookmarkIdx >= 0; bookmarkIdx--) {
|
|
111
|
+
if (this.entries[bookmarkIdx] === this.bookmark) {
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
this.entries.splice(bookmarkIdx + 1, 0, {
|
|
117
|
+
type: FormattingElementList.ELEMENT_ENTRY,
|
|
118
|
+
element: element,
|
|
119
|
+
token: token
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
this.length++;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
removeEntry(entry) {
|
|
126
|
+
for (let i = this.length - 1; i >= 0; i--) {
|
|
127
|
+
if (this.entries[i] === entry) {
|
|
128
|
+
this.entries.splice(i, 1);
|
|
129
|
+
this.length--;
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
clearToLastMarker() {
|
|
136
|
+
while (this.length) {
|
|
137
|
+
const entry = this.entries.pop();
|
|
138
|
+
|
|
139
|
+
this.length--;
|
|
140
|
+
|
|
141
|
+
if (entry.type === FormattingElementList.MARKER_ENTRY) {
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
//Search
|
|
148
|
+
getElementEntryInScopeWithTagName(tagName) {
|
|
149
|
+
for (let i = this.length - 1; i >= 0; i--) {
|
|
150
|
+
const entry = this.entries[i];
|
|
151
|
+
|
|
152
|
+
if (entry.type === FormattingElementList.MARKER_ENTRY) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (this.treeAdapter.getTagName(entry.element) === tagName) {
|
|
157
|
+
return entry;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
getElementEntry(element) {
|
|
165
|
+
for (let i = this.length - 1; i >= 0; i--) {
|
|
166
|
+
const entry = this.entries[i];
|
|
167
|
+
|
|
168
|
+
if (entry.type === FormattingElementList.ELEMENT_ENTRY && entry.element === element) {
|
|
169
|
+
return entry;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
//Entry types
|
|
178
|
+
FormattingElementList.MARKER_ENTRY = 'MARKER_ENTRY';
|
|
179
|
+
FormattingElementList.ELEMENT_ENTRY = 'ELEMENT_ENTRY';
|
|
180
|
+
|
|
181
|
+
module.exports = FormattingElementList;
|