parse5 2.1.5 → 2.2.3
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/LICENSE +19 -19
- package/README.md +40 -40
- package/lib/common/doctype.js +1 -1
- package/lib/common/foreign_content.js +260 -250
- package/lib/common/html.js +0 -3
- package/lib/index.js +108 -108
- package/lib/location_info/parser_mixin.js +4 -1
- package/lib/location_info/tokenizer_mixin.js +169 -168
- package/lib/parser/index.js +2817 -2864
- package/lib/parser/open_element_stack.js +395 -382
- package/lib/sax/dev_null_stream.js +14 -14
- package/lib/sax/index.js +3 -5
- package/lib/sax/parser_feedback_simulator.js +153 -116
- package/lib/serializer/index.js +180 -180
- package/lib/serializer/stream.js +49 -49
- package/lib/tokenizer/index.js +69 -361
- package/lib/tokenizer/preprocessor.js +155 -131
- package/lib/tree_adapters/htmlparser2.js +327 -327
- package/package.json +7 -6
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var WritableStream = require('stream').Writable,
|
|
4
|
-
util = require('util');
|
|
5
|
-
|
|
6
|
-
var DevNullStream = module.exports = function () {
|
|
7
|
-
WritableStream.call(this);
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
util.inherits(DevNullStream, WritableStream);
|
|
11
|
-
|
|
12
|
-
DevNullStream.prototype._write = function (chunk, encoding, cb) {
|
|
13
|
-
cb();
|
|
14
|
-
};
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var WritableStream = require('stream').Writable,
|
|
4
|
+
util = require('util');
|
|
5
|
+
|
|
6
|
+
var DevNullStream = module.exports = function () {
|
|
7
|
+
WritableStream.call(this);
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
util.inherits(DevNullStream, WritableStream);
|
|
11
|
+
|
|
12
|
+
DevNullStream.prototype._write = function (chunk, encoding, cb) {
|
|
13
|
+
cb();
|
|
14
|
+
};
|
package/lib/sax/index.js
CHANGED
|
@@ -124,13 +124,11 @@ SAXParser.prototype.stop = function () {
|
|
|
124
124
|
//Internals
|
|
125
125
|
SAXParser.prototype._runParsingLoop = function () {
|
|
126
126
|
do {
|
|
127
|
-
var token = this.
|
|
127
|
+
var token = this.parserFeedbackSimulator.getNextToken();
|
|
128
128
|
|
|
129
129
|
if (token.type === Tokenizer.HIBERNATION_TOKEN)
|
|
130
130
|
break;
|
|
131
131
|
|
|
132
|
-
this.parserFeedbackSimulator.adjustTokenizer(token);
|
|
133
|
-
|
|
134
132
|
if (token.type === Tokenizer.CHARACTER_TOKEN ||
|
|
135
133
|
token.type === Tokenizer.WHITESPACE_CHARACTER_TOKEN ||
|
|
136
134
|
token.type === Tokenizer.NULL_CHARACTER_TOKEN) {
|
|
@@ -140,7 +138,7 @@ SAXParser.prototype._runParsingLoop = function () {
|
|
|
140
138
|
this.currentTokenLocation = token.location;
|
|
141
139
|
|
|
142
140
|
else
|
|
143
|
-
this.currentTokenLocation.
|
|
141
|
+
this.currentTokenLocation.endOffset = token.location.endOffset;
|
|
144
142
|
}
|
|
145
143
|
|
|
146
144
|
this.pendingText = (this.pendingText || '') + token.chars;
|
|
@@ -165,7 +163,7 @@ SAXParser.prototype._handleToken = function (token) {
|
|
|
165
163
|
* @instance
|
|
166
164
|
* @type {Function}
|
|
167
165
|
* @param {String} name - Tag name.
|
|
168
|
-
* @param {
|
|
166
|
+
* @param {Array} attrs - List of attributes in the `{ name: String, value: String, prefix?: String }` form.
|
|
169
167
|
* @param {Boolean} selfClosing - Indicates if the tag is self-closing.
|
|
170
168
|
* @param {StartTagLocationInfo} [location] - Start tag source code location info.
|
|
171
169
|
* Available if location info is enabled in {@link SAXParserOptions}.
|
|
@@ -1,116 +1,153 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var Tokenizer = require('../tokenizer'),
|
|
4
|
-
foreignContent = require('../common/foreign_content'),
|
|
5
|
-
UNICODE = require('../common/unicode'),
|
|
6
|
-
HTML = require('../common/html');
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
//Aliases
|
|
10
|
-
var $ = HTML.TAG_NAMES,
|
|
11
|
-
NS = HTML.NAMESPACES;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
//ParserFeedbackSimulator
|
|
15
|
-
//Simulates adjustment of the Tokenizer which performed by standard parser during tree construction.
|
|
16
|
-
var ParserFeedbackSimulator = module.exports = function (tokenizer) {
|
|
17
|
-
this.tokenizer = tokenizer;
|
|
18
|
-
|
|
19
|
-
this.namespaceStack = [];
|
|
20
|
-
this.namespaceStackTop = -1;
|
|
21
|
-
this.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (token.type === Tokenizer.START_TAG_TOKEN)
|
|
28
|
-
this._handleStartTagToken(token);
|
|
29
|
-
|
|
30
|
-
else if (token.type === Tokenizer.END_TAG_TOKEN)
|
|
31
|
-
this._handleEndTagToken(token);
|
|
32
|
-
|
|
33
|
-
else if (token.type === Tokenizer.NULL_CHARACTER_TOKEN && this.inForeignContent) {
|
|
34
|
-
token.type = Tokenizer.CHARACTER_TOKEN;
|
|
35
|
-
token.chars = UNICODE.REPLACEMENT_CHARACTER;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
this.
|
|
56
|
-
this.
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
else
|
|
95
|
-
this.
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (
|
|
106
|
-
foreignContent.
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var Tokenizer = require('../tokenizer'),
|
|
4
|
+
foreignContent = require('../common/foreign_content'),
|
|
5
|
+
UNICODE = require('../common/unicode'),
|
|
6
|
+
HTML = require('../common/html');
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
//Aliases
|
|
10
|
+
var $ = HTML.TAG_NAMES,
|
|
11
|
+
NS = HTML.NAMESPACES;
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
//ParserFeedbackSimulator
|
|
15
|
+
//Simulates adjustment of the Tokenizer which performed by standard parser during tree construction.
|
|
16
|
+
var ParserFeedbackSimulator = module.exports = function (tokenizer) {
|
|
17
|
+
this.tokenizer = tokenizer;
|
|
18
|
+
|
|
19
|
+
this.namespaceStack = [];
|
|
20
|
+
this.namespaceStackTop = -1;
|
|
21
|
+
this._enterNamespace(NS.HTML);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
ParserFeedbackSimulator.prototype.getNextToken = function () {
|
|
25
|
+
var token = this.tokenizer.getNextToken();
|
|
26
|
+
|
|
27
|
+
if (token.type === Tokenizer.START_TAG_TOKEN)
|
|
28
|
+
this._handleStartTagToken(token);
|
|
29
|
+
|
|
30
|
+
else if (token.type === Tokenizer.END_TAG_TOKEN)
|
|
31
|
+
this._handleEndTagToken(token);
|
|
32
|
+
|
|
33
|
+
else if (token.type === Tokenizer.NULL_CHARACTER_TOKEN && this.inForeignContent) {
|
|
34
|
+
token.type = Tokenizer.CHARACTER_TOKEN;
|
|
35
|
+
token.chars = UNICODE.REPLACEMENT_CHARACTER;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
else if (this.skipNextNewLine) {
|
|
39
|
+
if (token.type !== Tokenizer.HIBERNATION_TOKEN)
|
|
40
|
+
this.skipNextNewLine = false;
|
|
41
|
+
|
|
42
|
+
if (token.type === Tokenizer.WHITESPACE_CHARACTER_TOKEN && token.chars[0] === '\n') {
|
|
43
|
+
if (token.chars.length === 1)
|
|
44
|
+
return this.getNextToken();
|
|
45
|
+
|
|
46
|
+
token.chars = token.chars.substr(1);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return token;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
//Namespace stack mutations
|
|
54
|
+
ParserFeedbackSimulator.prototype._enterNamespace = function (namespace) {
|
|
55
|
+
this.namespaceStackTop++;
|
|
56
|
+
this.namespaceStack.push(namespace);
|
|
57
|
+
|
|
58
|
+
this.inForeignContent = namespace !== NS.HTML;
|
|
59
|
+
this.currentNamespace = namespace;
|
|
60
|
+
this.tokenizer.allowCDATA = this.inForeignContent;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
ParserFeedbackSimulator.prototype._leaveCurrentNamespace = function () {
|
|
64
|
+
this.namespaceStackTop--;
|
|
65
|
+
this.namespaceStack.pop();
|
|
66
|
+
|
|
67
|
+
this.currentNamespace = this.namespaceStack[this.namespaceStackTop];
|
|
68
|
+
this.inForeignContent = this.currentNamespace !== NS.HTML;
|
|
69
|
+
this.tokenizer.allowCDATA = this.inForeignContent;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
//Token handlers
|
|
73
|
+
ParserFeedbackSimulator.prototype._ensureTokenizerMode = function (tn) {
|
|
74
|
+
if (tn === $.TEXTAREA || tn === $.TITLE)
|
|
75
|
+
this.tokenizer.state = Tokenizer.MODE.RCDATA;
|
|
76
|
+
|
|
77
|
+
else if (tn === $.PLAINTEXT)
|
|
78
|
+
this.tokenizer.state = Tokenizer.MODE.PLAINTEXT;
|
|
79
|
+
|
|
80
|
+
else if (tn === $.SCRIPT)
|
|
81
|
+
this.tokenizer.state = Tokenizer.MODE.SCRIPT_DATA;
|
|
82
|
+
|
|
83
|
+
else if (tn === $.STYLE || tn === $.IFRAME || tn === $.XMP ||
|
|
84
|
+
tn === $.NOEMBED || tn === $.NOFRAMES || tn === $.NOSCRIPT)
|
|
85
|
+
this.tokenizer.state = Tokenizer.MODE.RAWTEXT;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
ParserFeedbackSimulator.prototype._handleStartTagToken = function (token) {
|
|
89
|
+
var tn = token.tagName;
|
|
90
|
+
|
|
91
|
+
if (tn === $.SVG)
|
|
92
|
+
this._enterNamespace(NS.SVG);
|
|
93
|
+
|
|
94
|
+
else if (tn === $.MATH)
|
|
95
|
+
this._enterNamespace(NS.MATHML);
|
|
96
|
+
|
|
97
|
+
if (this.inForeignContent) {
|
|
98
|
+
if (foreignContent.causesExit(token)) {
|
|
99
|
+
this._leaveCurrentNamespace();
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
var currentNs = this.currentNamespace;
|
|
104
|
+
|
|
105
|
+
if (currentNs === NS.MATHML)
|
|
106
|
+
foreignContent.adjustTokenMathMLAttrs(token);
|
|
107
|
+
|
|
108
|
+
else if (currentNs === NS.SVG) {
|
|
109
|
+
foreignContent.adjustTokenSVGTagName(token);
|
|
110
|
+
foreignContent.adjustTokenSVGAttrs(token);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
foreignContent.adjustTokenXMLAttrs(token);
|
|
114
|
+
|
|
115
|
+
tn = token.tagName;
|
|
116
|
+
|
|
117
|
+
if (!token.selfClosing && foreignContent.isIntegrationPoint(tn, currentNs, token.attrs))
|
|
118
|
+
this._enterNamespace(NS.HTML);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
else {
|
|
122
|
+
if (tn === $.PRE || tn === $.TEXTAREA || tn === $.LISTING)
|
|
123
|
+
this.skipNextNewLine = true;
|
|
124
|
+
|
|
125
|
+
else if (tn === $.IMAGE)
|
|
126
|
+
token.tagName = $.IMG;
|
|
127
|
+
|
|
128
|
+
this._ensureTokenizerMode(tn);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
ParserFeedbackSimulator.prototype._handleEndTagToken = function (token) {
|
|
133
|
+
var tn = token.tagName;
|
|
134
|
+
|
|
135
|
+
if (!this.inForeignContent) {
|
|
136
|
+
var previousNs = this.namespaceStack[this.namespaceStackTop - 1];
|
|
137
|
+
|
|
138
|
+
if (previousNs === NS.SVG && foreignContent.SVG_TAG_NAMES_ADJUSTMENT_MAP[tn])
|
|
139
|
+
tn = foreignContent.SVG_TAG_NAMES_ADJUSTMENT_MAP[tn];
|
|
140
|
+
|
|
141
|
+
//NOTE: check for exit from integration point
|
|
142
|
+
if (foreignContent.isIntegrationPoint(tn, previousNs, token.attrs))
|
|
143
|
+
this._leaveCurrentNamespace();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
else if (tn === $.SVG && this.currentNamespace === NS.SVG ||
|
|
147
|
+
tn === $.MATH && this.currentNamespace === NS.MATHML)
|
|
148
|
+
this._leaveCurrentNamespace();
|
|
149
|
+
|
|
150
|
+
// NOTE: adjust end tag name as well for consistency
|
|
151
|
+
if (this.currentNamespace === NS.SVG)
|
|
152
|
+
foreignContent.adjustTokenSVGTagName(token);
|
|
153
|
+
};
|