parse5 1.5.0 → 1.5.1
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/CHANGELOG.md +69 -66
- package/docs/build/index.md +963 -0
- package/lib/common/doctype.js +134 -134
- package/lib/serialization/serializer.js +178 -179
- package/lib/simple_api/simple_api_parser.js +107 -107
- package/lib/simple_api/tokenizer_proxy.js +122 -122
- package/lib/tokenization/named_entity_trie.js +1 -54
- package/lib/tokenization/preprocessor.js +115 -115
- package/lib/tree_adapters/htmlparser2.js +317 -317
- package/lib/tree_construction/location_info_mixin.js +197 -197
- package/lib/tree_construction/parser.js +2827 -2827
- package/package.json +47 -47
|
@@ -1,197 +1,197 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var OpenElementStack = require('./open_element_stack'),
|
|
4
|
-
Tokenizer = require('../tokenization/tokenizer'),
|
|
5
|
-
HTML = require('../common/html');
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
//Aliases
|
|
9
|
-
var $ = HTML.TAG_NAMES;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
function setEndLocation(element, closingToken, treeAdapter) {
|
|
13
|
-
var loc = element.__location;
|
|
14
|
-
|
|
15
|
-
if (!loc)
|
|
16
|
-
return;
|
|
17
|
-
|
|
18
|
-
if (!loc.startTag) {
|
|
19
|
-
loc.startTag = {
|
|
20
|
-
start: loc.start,
|
|
21
|
-
end: loc.end
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (closingToken.location) {
|
|
26
|
-
var tn = treeAdapter.getTagName(element),
|
|
27
|
-
// NOTE: For cases like <p> <p> </p> - First 'p' closes without a closing tag and
|
|
28
|
-
// for cases like <td> <p> </td> - 'p' closes without a closing tag
|
|
29
|
-
isClosingEndTag = closingToken.type === Tokenizer.END_TAG_TOKEN &&
|
|
30
|
-
tn === closingToken.tagName;
|
|
31
|
-
|
|
32
|
-
if (isClosingEndTag) {
|
|
33
|
-
loc.endTag = {
|
|
34
|
-
start: closingToken.location.start,
|
|
35
|
-
end: closingToken.location.end
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
loc.end = closingToken.location.end;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
//NOTE: patch open elements stack, so we can assign end location for the elements
|
|
44
|
-
function patchOpenElementsStack(stack, parser) {
|
|
45
|
-
var treeAdapter = parser.treeAdapter;
|
|
46
|
-
|
|
47
|
-
stack.pop = function () {
|
|
48
|
-
setEndLocation(this.current, parser.currentToken, treeAdapter);
|
|
49
|
-
OpenElementStack.prototype.pop.call(this);
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
stack.popAllUpToHtmlElement = function () {
|
|
53
|
-
for (var i = this.stackTop; i > 0; i--)
|
|
54
|
-
setEndLocation(this.items[i], parser.currentToken, treeAdapter);
|
|
55
|
-
|
|
56
|
-
OpenElementStack.prototype.popAllUpToHtmlElement.call(this);
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
stack.remove = function (element) {
|
|
60
|
-
setEndLocation(element, parser.currentToken, treeAdapter);
|
|
61
|
-
OpenElementStack.prototype.remove.call(this, element);
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
exports.assign = function (parser) {
|
|
66
|
-
//NOTE: obtain Parser proto this way to avoid module circular references
|
|
67
|
-
var parserProto = Object.getPrototypeOf(parser),
|
|
68
|
-
treeAdapter = parser.treeAdapter;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
//NOTE: patch _reset method
|
|
72
|
-
parser._reset = function (html, document, fragmentContext) {
|
|
73
|
-
parserProto._reset.call(this, html, document, fragmentContext);
|
|
74
|
-
|
|
75
|
-
this.attachableElementLocation = null;
|
|
76
|
-
this.lastFosterParentingLocation = null;
|
|
77
|
-
this.currentToken = null;
|
|
78
|
-
|
|
79
|
-
patchOpenElementsStack(this.openElements, parser);
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
parser._processTokenInForeignContent = function (token) {
|
|
83
|
-
this.currentToken = token;
|
|
84
|
-
parserProto._processTokenInForeignContent.call(this, token);
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
parser._processToken = function (token) {
|
|
88
|
-
this.currentToken = token;
|
|
89
|
-
parserProto._processToken.call(this, token);
|
|
90
|
-
|
|
91
|
-
//NOTE: <body> and <html> are never popped from the stack, so we need to updated
|
|
92
|
-
//their end location explicitly.
|
|
93
|
-
if (token.type === Tokenizer.END_TAG_TOKEN &&
|
|
94
|
-
(token.tagName === $.HTML ||
|
|
95
|
-
(token.tagName === $.BODY && this.openElements.hasInScope($.BODY)))) {
|
|
96
|
-
for (var i = this.openElements.stackTop; i >= 0; i--) {
|
|
97
|
-
var element = this.openElements.items[i];
|
|
98
|
-
|
|
99
|
-
if (this.treeAdapter.getTagName(element) === token.tagName) {
|
|
100
|
-
setEndLocation(element, token, treeAdapter);
|
|
101
|
-
break;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
//Doctype
|
|
108
|
-
parser._setDocumentType = function (token) {
|
|
109
|
-
parserProto._setDocumentType.call(this, token);
|
|
110
|
-
|
|
111
|
-
var documentChildren = this.treeAdapter.getChildNodes(this.document),
|
|
112
|
-
cnLength = documentChildren.length;
|
|
113
|
-
|
|
114
|
-
for (var i = 0; i < cnLength; i++) {
|
|
115
|
-
var node = documentChildren[i];
|
|
116
|
-
|
|
117
|
-
if (this.treeAdapter.isDocumentTypeNode(node)) {
|
|
118
|
-
node.__location = token.location;
|
|
119
|
-
break;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
//Elements
|
|
125
|
-
parser._attachElementToTree = function (element) {
|
|
126
|
-
//NOTE: _attachElementToTree is called from _appendElement, _insertElement and _insertTemplate methods.
|
|
127
|
-
//So we will use token location stored in this methods for the element.
|
|
128
|
-
element.__location = this.attachableElementLocation || null;
|
|
129
|
-
this.attachableElementLocation = null;
|
|
130
|
-
parserProto._attachElementToTree.call(this, element);
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
parser._appendElement = function (token, namespaceURI) {
|
|
134
|
-
this.attachableElementLocation = token.location;
|
|
135
|
-
parserProto._appendElement.call(this, token, namespaceURI);
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
parser._insertElement = function (token, namespaceURI) {
|
|
139
|
-
this.attachableElementLocation = token.location;
|
|
140
|
-
parserProto._insertElement.call(this, token, namespaceURI);
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
parser._insertTemplate = function (token) {
|
|
144
|
-
this.attachableElementLocation = token.location;
|
|
145
|
-
parserProto._insertTemplate.call(this, token);
|
|
146
|
-
|
|
147
|
-
var tmplContent = this.treeAdapter.getChildNodes(this.openElements.current)[0];
|
|
148
|
-
|
|
149
|
-
tmplContent.__location = null;
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
parser._insertFakeRootElement = function () {
|
|
153
|
-
parserProto._insertFakeRootElement.call(this);
|
|
154
|
-
this.openElements.current.__location = null;
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
//Comments
|
|
158
|
-
parser._appendCommentNode = function (token, parent) {
|
|
159
|
-
parserProto._appendCommentNode.call(this, token, parent);
|
|
160
|
-
|
|
161
|
-
var children = this.treeAdapter.getChildNodes(parent),
|
|
162
|
-
commentNode = children[children.length - 1];
|
|
163
|
-
|
|
164
|
-
commentNode.__location = token.location;
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
//Text
|
|
168
|
-
parser._findFosterParentingLocation = function () {
|
|
169
|
-
//NOTE: store last foster parenting location, so we will be able to find inserted text
|
|
170
|
-
//in case of foster parenting
|
|
171
|
-
this.lastFosterParentingLocation = parserProto._findFosterParentingLocation.call(this);
|
|
172
|
-
return this.lastFosterParentingLocation;
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
parser._insertCharacters = function (token) {
|
|
176
|
-
parserProto._insertCharacters.call(this, token);
|
|
177
|
-
|
|
178
|
-
var hasFosterParent = this._shouldFosterParentOnInsertion(),
|
|
179
|
-
parentingLocation = this.lastFosterParentingLocation,
|
|
180
|
-
parent = (hasFosterParent && parentingLocation.parent) ||
|
|
181
|
-
this.openElements.currentTmplContent ||
|
|
182
|
-
this.openElements.current,
|
|
183
|
-
siblings = this.treeAdapter.getChildNodes(parent),
|
|
184
|
-
textNodeIdx = hasFosterParent && parentingLocation.beforeElement ?
|
|
185
|
-
siblings.indexOf(parentingLocation.beforeElement) - 1 :
|
|
186
|
-
siblings.length - 1,
|
|
187
|
-
textNode = siblings[textNodeIdx];
|
|
188
|
-
|
|
189
|
-
//NOTE: if we have location assigned by another token, then just update end position
|
|
190
|
-
if (textNode.__location)
|
|
191
|
-
textNode.__location.end = token.location.end;
|
|
192
|
-
|
|
193
|
-
else
|
|
194
|
-
textNode.__location = token.location;
|
|
195
|
-
};
|
|
196
|
-
};
|
|
197
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var OpenElementStack = require('./open_element_stack'),
|
|
4
|
+
Tokenizer = require('../tokenization/tokenizer'),
|
|
5
|
+
HTML = require('../common/html');
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
//Aliases
|
|
9
|
+
var $ = HTML.TAG_NAMES;
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
function setEndLocation(element, closingToken, treeAdapter) {
|
|
13
|
+
var loc = element.__location;
|
|
14
|
+
|
|
15
|
+
if (!loc)
|
|
16
|
+
return;
|
|
17
|
+
|
|
18
|
+
if (!loc.startTag) {
|
|
19
|
+
loc.startTag = {
|
|
20
|
+
start: loc.start,
|
|
21
|
+
end: loc.end
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (closingToken.location) {
|
|
26
|
+
var tn = treeAdapter.getTagName(element),
|
|
27
|
+
// NOTE: For cases like <p> <p> </p> - First 'p' closes without a closing tag and
|
|
28
|
+
// for cases like <td> <p> </td> - 'p' closes without a closing tag
|
|
29
|
+
isClosingEndTag = closingToken.type === Tokenizer.END_TAG_TOKEN &&
|
|
30
|
+
tn === closingToken.tagName;
|
|
31
|
+
|
|
32
|
+
if (isClosingEndTag) {
|
|
33
|
+
loc.endTag = {
|
|
34
|
+
start: closingToken.location.start,
|
|
35
|
+
end: closingToken.location.end
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
loc.end = closingToken.location.end;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
//NOTE: patch open elements stack, so we can assign end location for the elements
|
|
44
|
+
function patchOpenElementsStack(stack, parser) {
|
|
45
|
+
var treeAdapter = parser.treeAdapter;
|
|
46
|
+
|
|
47
|
+
stack.pop = function () {
|
|
48
|
+
setEndLocation(this.current, parser.currentToken, treeAdapter);
|
|
49
|
+
OpenElementStack.prototype.pop.call(this);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
stack.popAllUpToHtmlElement = function () {
|
|
53
|
+
for (var i = this.stackTop; i > 0; i--)
|
|
54
|
+
setEndLocation(this.items[i], parser.currentToken, treeAdapter);
|
|
55
|
+
|
|
56
|
+
OpenElementStack.prototype.popAllUpToHtmlElement.call(this);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
stack.remove = function (element) {
|
|
60
|
+
setEndLocation(element, parser.currentToken, treeAdapter);
|
|
61
|
+
OpenElementStack.prototype.remove.call(this, element);
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
exports.assign = function (parser) {
|
|
66
|
+
//NOTE: obtain Parser proto this way to avoid module circular references
|
|
67
|
+
var parserProto = Object.getPrototypeOf(parser),
|
|
68
|
+
treeAdapter = parser.treeAdapter;
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
//NOTE: patch _reset method
|
|
72
|
+
parser._reset = function (html, document, fragmentContext) {
|
|
73
|
+
parserProto._reset.call(this, html, document, fragmentContext);
|
|
74
|
+
|
|
75
|
+
this.attachableElementLocation = null;
|
|
76
|
+
this.lastFosterParentingLocation = null;
|
|
77
|
+
this.currentToken = null;
|
|
78
|
+
|
|
79
|
+
patchOpenElementsStack(this.openElements, parser);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
parser._processTokenInForeignContent = function (token) {
|
|
83
|
+
this.currentToken = token;
|
|
84
|
+
parserProto._processTokenInForeignContent.call(this, token);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
parser._processToken = function (token) {
|
|
88
|
+
this.currentToken = token;
|
|
89
|
+
parserProto._processToken.call(this, token);
|
|
90
|
+
|
|
91
|
+
//NOTE: <body> and <html> are never popped from the stack, so we need to updated
|
|
92
|
+
//their end location explicitly.
|
|
93
|
+
if (token.type === Tokenizer.END_TAG_TOKEN &&
|
|
94
|
+
(token.tagName === $.HTML ||
|
|
95
|
+
(token.tagName === $.BODY && this.openElements.hasInScope($.BODY)))) {
|
|
96
|
+
for (var i = this.openElements.stackTop; i >= 0; i--) {
|
|
97
|
+
var element = this.openElements.items[i];
|
|
98
|
+
|
|
99
|
+
if (this.treeAdapter.getTagName(element) === token.tagName) {
|
|
100
|
+
setEndLocation(element, token, treeAdapter);
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
//Doctype
|
|
108
|
+
parser._setDocumentType = function (token) {
|
|
109
|
+
parserProto._setDocumentType.call(this, token);
|
|
110
|
+
|
|
111
|
+
var documentChildren = this.treeAdapter.getChildNodes(this.document),
|
|
112
|
+
cnLength = documentChildren.length;
|
|
113
|
+
|
|
114
|
+
for (var i = 0; i < cnLength; i++) {
|
|
115
|
+
var node = documentChildren[i];
|
|
116
|
+
|
|
117
|
+
if (this.treeAdapter.isDocumentTypeNode(node)) {
|
|
118
|
+
node.__location = token.location;
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
//Elements
|
|
125
|
+
parser._attachElementToTree = function (element) {
|
|
126
|
+
//NOTE: _attachElementToTree is called from _appendElement, _insertElement and _insertTemplate methods.
|
|
127
|
+
//So we will use token location stored in this methods for the element.
|
|
128
|
+
element.__location = this.attachableElementLocation || null;
|
|
129
|
+
this.attachableElementLocation = null;
|
|
130
|
+
parserProto._attachElementToTree.call(this, element);
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
parser._appendElement = function (token, namespaceURI) {
|
|
134
|
+
this.attachableElementLocation = token.location;
|
|
135
|
+
parserProto._appendElement.call(this, token, namespaceURI);
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
parser._insertElement = function (token, namespaceURI) {
|
|
139
|
+
this.attachableElementLocation = token.location;
|
|
140
|
+
parserProto._insertElement.call(this, token, namespaceURI);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
parser._insertTemplate = function (token) {
|
|
144
|
+
this.attachableElementLocation = token.location;
|
|
145
|
+
parserProto._insertTemplate.call(this, token);
|
|
146
|
+
|
|
147
|
+
var tmplContent = this.treeAdapter.getChildNodes(this.openElements.current)[0];
|
|
148
|
+
|
|
149
|
+
tmplContent.__location = null;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
parser._insertFakeRootElement = function () {
|
|
153
|
+
parserProto._insertFakeRootElement.call(this);
|
|
154
|
+
this.openElements.current.__location = null;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
//Comments
|
|
158
|
+
parser._appendCommentNode = function (token, parent) {
|
|
159
|
+
parserProto._appendCommentNode.call(this, token, parent);
|
|
160
|
+
|
|
161
|
+
var children = this.treeAdapter.getChildNodes(parent),
|
|
162
|
+
commentNode = children[children.length - 1];
|
|
163
|
+
|
|
164
|
+
commentNode.__location = token.location;
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
//Text
|
|
168
|
+
parser._findFosterParentingLocation = function () {
|
|
169
|
+
//NOTE: store last foster parenting location, so we will be able to find inserted text
|
|
170
|
+
//in case of foster parenting
|
|
171
|
+
this.lastFosterParentingLocation = parserProto._findFosterParentingLocation.call(this);
|
|
172
|
+
return this.lastFosterParentingLocation;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
parser._insertCharacters = function (token) {
|
|
176
|
+
parserProto._insertCharacters.call(this, token);
|
|
177
|
+
|
|
178
|
+
var hasFosterParent = this._shouldFosterParentOnInsertion(),
|
|
179
|
+
parentingLocation = this.lastFosterParentingLocation,
|
|
180
|
+
parent = (hasFosterParent && parentingLocation.parent) ||
|
|
181
|
+
this.openElements.currentTmplContent ||
|
|
182
|
+
this.openElements.current,
|
|
183
|
+
siblings = this.treeAdapter.getChildNodes(parent),
|
|
184
|
+
textNodeIdx = hasFosterParent && parentingLocation.beforeElement ?
|
|
185
|
+
siblings.indexOf(parentingLocation.beforeElement) - 1 :
|
|
186
|
+
siblings.length - 1,
|
|
187
|
+
textNode = siblings[textNodeIdx];
|
|
188
|
+
|
|
189
|
+
//NOTE: if we have location assigned by another token, then just update end position
|
|
190
|
+
if (textNode.__location)
|
|
191
|
+
textNode.__location.end = token.location.end;
|
|
192
|
+
|
|
193
|
+
else
|
|
194
|
+
textNode.__location = token.location;
|
|
195
|
+
};
|
|
196
|
+
};
|
|
197
|
+
|