parse5 1.4.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.
@@ -81,6 +81,16 @@ var VALID_DOCTYPE_NAME = 'html',
81
81
  'html'
82
82
  ];
83
83
 
84
+
85
+ //Utils
86
+ function enquoteDoctypeId(id) {
87
+ var quote = id.indexOf('"') !== -1 ? '\'' : '"';
88
+
89
+ return quote + id + quote;
90
+ }
91
+
92
+
93
+ //API
84
94
  exports.isQuirks = function (name, publicId, systemId) {
85
95
  if (name !== VALID_DOCTYPE_NAME)
86
96
  return true;
@@ -107,3 +117,18 @@ exports.isQuirks = function (name, publicId, systemId) {
107
117
 
108
118
  return false;
109
119
  };
120
+
121
+ exports.serializeContent = function (name, publicId, systemId) {
122
+ var str = '!DOCTYPE ' + name;
123
+
124
+ if (publicId !== null)
125
+ str += ' PUBLIC ' + enquoteDoctypeId(publicId);
126
+
127
+ else if (systemId !== null)
128
+ str += ' SYSTEM';
129
+
130
+ if (systemId !== null)
131
+ str += ' ' + enquoteDoctypeId(systemId);
132
+
133
+ return str;
134
+ };
@@ -1,194 +1,178 @@
1
- 'use strict';
2
-
3
- var DefaultTreeAdapter = require('../tree_adapters/default'),
4
- Utils = require('../common/utils'),
5
- HTML = require('../common/html');
6
-
7
- //Aliases
8
- var $ = HTML.TAG_NAMES,
9
- NS = HTML.NAMESPACES;
10
-
11
- //Default serializer options
12
- var DEFAULT_OPTIONS = {
13
- encodeHtmlEntities: true
14
- };
15
-
16
- //Escaping regexes
17
- var AMP_REGEX = /&/g,
18
- NBSP_REGEX = /\u00a0/g,
19
- DOUBLE_QUOTE_REGEX = /"/g,
20
- LT_REGEX = /</g,
21
- GT_REGEX = />/g;
22
-
23
- //Escape string
24
- function escapeString(str, attrMode) {
25
- str = str
26
- .replace(AMP_REGEX, '&amp;')
27
- .replace(NBSP_REGEX, '&nbsp;');
28
-
29
- if (attrMode)
30
- str = str.replace(DOUBLE_QUOTE_REGEX, '&quot;');
31
-
32
- else {
33
- str = str
34
- .replace(LT_REGEX, '&lt;')
35
- .replace(GT_REGEX, '&gt;');
36
- }
37
-
38
- return str;
39
- }
40
-
41
-
42
- //Enquote doctype ID
43
- function enquoteDoctypeId(id) {
44
- var quote = id.indexOf('"') !== -1 ? '\'' : '"';
45
-
46
- return quote + id + quote;
47
- }
48
-
49
-
50
- //Serializer
51
- var Serializer = module.exports = function (treeAdapter, options) {
52
- this.treeAdapter = treeAdapter || DefaultTreeAdapter;
53
- this.options = Utils.mergeOptions(DEFAULT_OPTIONS, options);
54
- };
55
-
56
-
57
- //API
58
- Serializer.prototype.serialize = function (node) {
59
- this.html = '';
60
- this._serializeChildNodes(node);
61
-
62
- return this.html;
63
- };
64
-
65
-
66
- //Internals
67
- Serializer.prototype._serializeChildNodes = function (parentNode) {
68
- var childNodes = this.treeAdapter.getChildNodes(parentNode);
69
-
70
- if (childNodes) {
71
- for (var i = 0, cnLength = childNodes.length; i < cnLength; i++) {
72
- var currentNode = childNodes[i];
73
-
74
- if (this.treeAdapter.isElementNode(currentNode))
75
- this._serializeElement(currentNode);
76
-
77
- else if (this.treeAdapter.isTextNode(currentNode))
78
- this._serializeTextNode(currentNode);
79
-
80
- else if (this.treeAdapter.isCommentNode(currentNode))
81
- this._serializeCommentNode(currentNode);
82
-
83
- else if (this.treeAdapter.isDocumentTypeNode(currentNode))
84
- this._serializeDocumentTypeNode(currentNode);
85
- }
86
- }
87
- };
88
-
89
- Serializer.prototype._serializeElement = function (node) {
90
- var tn = this.treeAdapter.getTagName(node),
91
- ns = this.treeAdapter.getNamespaceURI(node),
92
- qualifiedTn = (ns === NS.HTML || ns === NS.SVG || ns === NS.MATHML) ? tn : (ns + ':' + tn);
93
-
94
- this.html += '<' + qualifiedTn;
95
- this._serializeAttributes(node);
96
- this.html += '>';
97
-
98
- if (tn !== $.AREA && tn !== $.BASE && tn !== $.BASEFONT && tn !== $.BGSOUND && tn !== $.BR && tn !== $.BR &&
99
- tn !== $.COL && tn !== $.EMBED && tn !== $.FRAME && tn !== $.HR && tn !== $.IMG && tn !== $.INPUT &&
100
- tn !== $.KEYGEN && tn !== $.LINK && tn !== $.MENUITEM && tn !== $.META && tn !== $.PARAM && tn !== $.SOURCE &&
101
- tn !== $.TRACK && tn !== $.WBR) {
102
-
103
- if (tn === $.PRE || tn === $.TEXTAREA || tn === $.LISTING) {
104
- var firstChild = this.treeAdapter.getFirstChild(node);
105
-
106
- if (firstChild && this.treeAdapter.isTextNode(firstChild)) {
107
- var content = this.treeAdapter.getTextNodeContent(firstChild);
108
-
109
- if (content[0] === '\n')
110
- this.html += '\n';
111
- }
112
- }
113
-
114
- var childNodesHolder = tn === $.TEMPLATE && ns === NS.HTML ?
115
- this.treeAdapter.getChildNodes(node)[0] :
116
- node;
117
-
118
- this._serializeChildNodes(childNodesHolder);
119
- this.html += '</' + qualifiedTn + '>';
120
- }
121
- };
122
-
123
- Serializer.prototype._serializeAttributes = function (node) {
124
- var attrs = this.treeAdapter.getAttrList(node);
125
-
126
- for (var i = 0, attrsLength = attrs.length; i < attrsLength; i++) {
127
- var attr = attrs[i],
128
- value = this.options.encodeHtmlEntities ? escapeString(attr.value, true) : attr.value;
129
-
130
- this.html += ' ';
131
-
132
- if (!attr.namespace)
133
- this.html += attr.name;
134
-
135
- else if (attr.namespace === NS.XML)
136
- this.html += 'xml:' + attr.name;
137
-
138
- else if (attr.namespace === NS.XMLNS) {
139
- if (attr.name !== 'xmlns')
140
- this.html += 'xmlns:';
141
-
142
- this.html += attr.name;
143
- }
144
-
145
- else if (attr.namespace === NS.XLINK)
146
- this.html += 'xlink:' + attr.name;
147
-
148
- else
149
- this.html += attr.namespace + ':' + attr.name;
150
-
151
- this.html += '="' + value + '"';
152
- }
153
- };
154
-
155
- Serializer.prototype._serializeTextNode = function (node) {
156
- var content = this.treeAdapter.getTextNodeContent(node),
157
- parent = this.treeAdapter.getParentNode(node),
158
- parentTn = void 0;
159
-
160
- if (parent && this.treeAdapter.isElementNode(parent))
161
- parentTn = this.treeAdapter.getTagName(parent);
162
-
163
- if (parentTn === $.STYLE || parentTn === $.SCRIPT || parentTn === $.XMP || parentTn === $.IFRAME ||
164
- parentTn === $.NOEMBED || parentTn === $.NOFRAMES || parentTn === $.PLAINTEXT || parentTn === $.NOSCRIPT) {
165
- this.html += content;
166
- }
167
-
168
- else
169
- this.html += this.options.encodeHtmlEntities ? escapeString(content, false) : content;
170
- };
171
-
172
- Serializer.prototype._serializeCommentNode = function (node) {
173
- this.html += '<!--' + this.treeAdapter.getCommentNodeContent(node) + '-->';
174
- };
175
-
176
- Serializer.prototype._serializeDocumentTypeNode = function (node) {
177
- var name = this.treeAdapter.getDocumentTypeNodeName(node),
178
- publicId = this.treeAdapter.getDocumentTypeNodePublicId(node),
179
- systemId = this.treeAdapter.getDocumentTypeNodeSystemId(node);
180
-
181
- this.html += '<!DOCTYPE ' + name;
182
-
183
- if (publicId !== null)
184
- this.html += ' PUBLIC ' + enquoteDoctypeId(publicId);
185
-
186
- else if (systemId !== null)
187
- this.html += ' SYSTEM';
188
-
189
- if (systemId !== null)
190
- this.html += ' ' + enquoteDoctypeId(systemId);
191
-
192
-
193
- this.html += '>';
194
- };
1
+ 'use strict';
2
+
3
+ var DefaultTreeAdapter = require('../tree_adapters/default'),
4
+ Doctype = require('../common/doctype'),
5
+ Utils = require('../common/utils'),
6
+ HTML = require('../common/html');
7
+
8
+ //Aliases
9
+ var $ = HTML.TAG_NAMES,
10
+ NS = HTML.NAMESPACES;
11
+
12
+ //Default serializer options
13
+ var DEFAULT_OPTIONS = {
14
+ encodeHtmlEntities: true
15
+ };
16
+
17
+ //Escaping regexes
18
+ var AMP_REGEX = /&/g,
19
+ NBSP_REGEX = /\u00a0/g,
20
+ DOUBLE_QUOTE_REGEX = /"/g,
21
+ LT_REGEX = /</g,
22
+ GT_REGEX = />/g;
23
+
24
+ //Escape string
25
+ function escapeString(str, attrMode) {
26
+ str = str
27
+ .replace(AMP_REGEX, '&amp;')
28
+ .replace(NBSP_REGEX, '&nbsp;');
29
+
30
+ if (attrMode)
31
+ str = str.replace(DOUBLE_QUOTE_REGEX, '&quot;');
32
+
33
+ else {
34
+ str = str
35
+ .replace(LT_REGEX, '&lt;')
36
+ .replace(GT_REGEX, '&gt;');
37
+ }
38
+
39
+ return str;
40
+ }
41
+
42
+
43
+ //Enquote doctype ID
44
+
45
+
46
+
47
+ //Serializer
48
+ var Serializer = module.exports = function (treeAdapter, options) {
49
+ this.treeAdapter = treeAdapter || DefaultTreeAdapter;
50
+ this.options = Utils.mergeOptions(DEFAULT_OPTIONS, options);
51
+ };
52
+
53
+
54
+ //API
55
+ Serializer.prototype.serialize = function (node) {
56
+ this.html = '';
57
+ this._serializeChildNodes(node);
58
+
59
+ return this.html;
60
+ };
61
+
62
+
63
+ //Internals
64
+ Serializer.prototype._serializeChildNodes = function (parentNode) {
65
+ var childNodes = this.treeAdapter.getChildNodes(parentNode);
66
+
67
+ if (childNodes) {
68
+ for (var i = 0, cnLength = childNodes.length; i < cnLength; i++) {
69
+ var currentNode = childNodes[i];
70
+
71
+ if (this.treeAdapter.isElementNode(currentNode))
72
+ this._serializeElement(currentNode);
73
+
74
+ else if (this.treeAdapter.isTextNode(currentNode))
75
+ this._serializeTextNode(currentNode);
76
+
77
+ else if (this.treeAdapter.isCommentNode(currentNode))
78
+ this._serializeCommentNode(currentNode);
79
+
80
+ else if (this.treeAdapter.isDocumentTypeNode(currentNode))
81
+ this._serializeDocumentTypeNode(currentNode);
82
+ }
83
+ }
84
+ };
85
+
86
+ Serializer.prototype._serializeElement = function (node) {
87
+ var tn = this.treeAdapter.getTagName(node),
88
+ ns = this.treeAdapter.getNamespaceURI(node);
89
+
90
+ this.html += '<' + tn;
91
+ this._serializeAttributes(node);
92
+ this.html += '>';
93
+
94
+ if (tn !== $.AREA && tn !== $.BASE && tn !== $.BASEFONT && tn !== $.BGSOUND && tn !== $.BR && tn !== $.BR &&
95
+ tn !== $.COL && tn !== $.EMBED && tn !== $.FRAME && tn !== $.HR && tn !== $.IMG && tn !== $.INPUT &&
96
+ tn !== $.KEYGEN && tn !== $.LINK && tn !== $.MENUITEM && tn !== $.META && tn !== $.PARAM && tn !== $.SOURCE &&
97
+ tn !== $.TRACK && tn !== $.WBR) {
98
+
99
+ if (tn === $.PRE || tn === $.TEXTAREA || tn === $.LISTING) {
100
+ var firstChild = this.treeAdapter.getFirstChild(node);
101
+
102
+ if (firstChild && this.treeAdapter.isTextNode(firstChild)) {
103
+ var content = this.treeAdapter.getTextNodeContent(firstChild);
104
+
105
+ if (content[0] === '\n')
106
+ this.html += '\n';
107
+ }
108
+ }
109
+
110
+ var childNodesHolder = tn === $.TEMPLATE && ns === NS.HTML ?
111
+ this.treeAdapter.getChildNodes(node)[0] :
112
+ node;
113
+
114
+ this._serializeChildNodes(childNodesHolder);
115
+ this.html += '</' + tn + '>';
116
+ }
117
+ };
118
+
119
+ Serializer.prototype._serializeAttributes = function (node) {
120
+ var attrs = this.treeAdapter.getAttrList(node);
121
+
122
+ for (var i = 0, attrsLength = attrs.length; i < attrsLength; i++) {
123
+ var attr = attrs[i],
124
+ value = this.options.encodeHtmlEntities ? escapeString(attr.value, true) : attr.value;
125
+
126
+ this.html += ' ';
127
+
128
+ if (!attr.namespace)
129
+ this.html += attr.name;
130
+
131
+ else if (attr.namespace === NS.XML)
132
+ this.html += 'xml:' + attr.name;
133
+
134
+ else if (attr.namespace === NS.XMLNS) {
135
+ if (attr.name !== 'xmlns')
136
+ this.html += 'xmlns:';
137
+
138
+ this.html += attr.name;
139
+ }
140
+
141
+ else if (attr.namespace === NS.XLINK)
142
+ this.html += 'xlink:' + attr.name;
143
+
144
+ else
145
+ this.html += attr.namespace + ':' + attr.name;
146
+
147
+ this.html += '="' + value + '"';
148
+ }
149
+ };
150
+
151
+ Serializer.prototype._serializeTextNode = function (node) {
152
+ var content = this.treeAdapter.getTextNodeContent(node),
153
+ parent = this.treeAdapter.getParentNode(node),
154
+ parentTn = void 0;
155
+
156
+ if (parent && this.treeAdapter.isElementNode(parent))
157
+ parentTn = this.treeAdapter.getTagName(parent);
158
+
159
+ if (parentTn === $.STYLE || parentTn === $.SCRIPT || parentTn === $.XMP || parentTn === $.IFRAME ||
160
+ parentTn === $.NOEMBED || parentTn === $.NOFRAMES || parentTn === $.PLAINTEXT || parentTn === $.NOSCRIPT) {
161
+ this.html += content;
162
+ }
163
+
164
+ else
165
+ this.html += this.options.encodeHtmlEntities ? escapeString(content, false) : content;
166
+ };
167
+
168
+ Serializer.prototype._serializeCommentNode = function (node) {
169
+ this.html += '<!--' + this.treeAdapter.getCommentNodeContent(node) + '-->';
170
+ };
171
+
172
+ Serializer.prototype._serializeDocumentTypeNode = function (node) {
173
+ var name = this.treeAdapter.getDocumentTypeNodeName(node),
174
+ publicId = this.treeAdapter.getDocumentTypeNodePublicId(node),
175
+ systemId = this.treeAdapter.getDocumentTypeNodeSystemId(node);
176
+
177
+ this.html += '<' + Doctype.serializeContent(name, publicId, systemId) + '>';
178
+ };
@@ -1,107 +1,107 @@
1
- 'use strict';
2
-
3
- var Tokenizer = require('../tokenization/tokenizer'),
4
- TokenizerProxy = require('./tokenizer_proxy'),
5
- Utils = require('../common/utils');
6
-
7
- //Default options
8
- var DEFAULT_OPTIONS = {
9
- decodeHtmlEntities: true,
10
- locationInfo: false
11
- };
12
-
13
- //Skipping handler
14
- function skip() {
15
- //NOTE: do nothing =)
16
- }
17
-
18
- //SimpleApiParser
19
- var SimpleApiParser = module.exports = function (handlers, options) {
20
- this.options = Utils.mergeOptions(DEFAULT_OPTIONS, options);
21
- this.handlers = {
22
- doctype: this._wrapHandler(handlers.doctype),
23
- startTag: this._wrapHandler(handlers.startTag),
24
- endTag: this._wrapHandler(handlers.endTag),
25
- text: this._wrapHandler(handlers.text),
26
- comment: this._wrapHandler(handlers.comment)
27
- };
28
- };
29
-
30
- SimpleApiParser.prototype._wrapHandler = function (handler) {
31
- var parser = this;
32
-
33
- handler = handler || skip;
34
-
35
- if (this.options.locationInfo) {
36
- return function () {
37
- var args = Array.prototype.slice.call(arguments);
38
- args.push(parser.currentTokenLocation);
39
- handler.apply(handler, args);
40
- };
41
- }
42
-
43
- return handler;
44
- };
45
-
46
- //API
47
- SimpleApiParser.prototype.parse = function (html) {
48
- var token = null;
49
-
50
- this._reset(html);
51
-
52
- do {
53
- token = this.tokenizerProxy.getNextToken();
54
-
55
- if (token.type === Tokenizer.CHARACTER_TOKEN ||
56
- token.type === Tokenizer.WHITESPACE_CHARACTER_TOKEN ||
57
- token.type === Tokenizer.NULL_CHARACTER_TOKEN) {
58
-
59
- if (this.options.locationInfo) {
60
- if (this.pendingText === null)
61
- this.currentTokenLocation = token.location;
62
-
63
- else
64
- this.currentTokenLocation.end = token.location.end;
65
- }
66
-
67
- this.pendingText = (this.pendingText || '') + token.chars;
68
- }
69
-
70
- else {
71
- this._emitPendingText();
72
- this._handleToken(token);
73
- }
74
- } while (token.type !== Tokenizer.EOF_TOKEN);
75
- };
76
-
77
- //Internals
78
- SimpleApiParser.prototype._handleToken = function (token) {
79
- if (this.options.locationInfo)
80
- this.currentTokenLocation = token.location;
81
-
82
- if (token.type === Tokenizer.START_TAG_TOKEN)
83
- this.handlers.startTag(token.tagName, token.attrs, token.selfClosing);
84
-
85
- else if (token.type === Tokenizer.END_TAG_TOKEN)
86
- this.handlers.endTag(token.tagName);
87
-
88
- else if (token.type === Tokenizer.COMMENT_TOKEN)
89
- this.handlers.comment(token.data);
90
-
91
- else if (token.type === Tokenizer.DOCTYPE_TOKEN)
92
- this.handlers.doctype(token.name, token.publicId, token.systemId);
93
-
94
- };
95
-
96
- SimpleApiParser.prototype._reset = function (html) {
97
- this.tokenizerProxy = new TokenizerProxy(html, this.options);
98
- this.pendingText = null;
99
- this.currentTokenLocation = null;
100
- };
101
-
102
- SimpleApiParser.prototype._emitPendingText = function () {
103
- if (this.pendingText !== null) {
104
- this.handlers.text(this.pendingText);
105
- this.pendingText = null;
106
- }
107
- };
1
+ 'use strict';
2
+
3
+ var Tokenizer = require('../tokenization/tokenizer'),
4
+ TokenizerProxy = require('./tokenizer_proxy'),
5
+ Utils = require('../common/utils');
6
+
7
+ //Default options
8
+ var DEFAULT_OPTIONS = {
9
+ decodeHtmlEntities: true,
10
+ locationInfo: false
11
+ };
12
+
13
+ //Skipping handler
14
+ function skip() {
15
+ //NOTE: do nothing =)
16
+ }
17
+
18
+ //SimpleApiParser
19
+ var SimpleApiParser = module.exports = function (handlers, options) {
20
+ this.options = Utils.mergeOptions(DEFAULT_OPTIONS, options);
21
+ this.handlers = {
22
+ doctype: this._wrapHandler(handlers.doctype),
23
+ startTag: this._wrapHandler(handlers.startTag),
24
+ endTag: this._wrapHandler(handlers.endTag),
25
+ text: this._wrapHandler(handlers.text),
26
+ comment: this._wrapHandler(handlers.comment)
27
+ };
28
+ };
29
+
30
+ SimpleApiParser.prototype._wrapHandler = function (handler) {
31
+ var parser = this;
32
+
33
+ handler = handler || skip;
34
+
35
+ if (this.options.locationInfo) {
36
+ return function () {
37
+ var args = Array.prototype.slice.call(arguments);
38
+ args.push(parser.currentTokenLocation);
39
+ handler.apply(handler, args);
40
+ };
41
+ }
42
+
43
+ return handler;
44
+ };
45
+
46
+ //API
47
+ SimpleApiParser.prototype.parse = function (html) {
48
+ var token = null;
49
+
50
+ this._reset(html);
51
+
52
+ do {
53
+ token = this.tokenizerProxy.getNextToken();
54
+
55
+ if (token.type === Tokenizer.CHARACTER_TOKEN ||
56
+ token.type === Tokenizer.WHITESPACE_CHARACTER_TOKEN ||
57
+ token.type === Tokenizer.NULL_CHARACTER_TOKEN) {
58
+
59
+ if (this.options.locationInfo) {
60
+ if (this.pendingText === null)
61
+ this.currentTokenLocation = token.location;
62
+
63
+ else
64
+ this.currentTokenLocation.end = token.location.end;
65
+ }
66
+
67
+ this.pendingText = (this.pendingText || '') + token.chars;
68
+ }
69
+
70
+ else {
71
+ this._emitPendingText();
72
+ this._handleToken(token);
73
+ }
74
+ } while (token.type !== Tokenizer.EOF_TOKEN);
75
+ };
76
+
77
+ //Internals
78
+ SimpleApiParser.prototype._handleToken = function (token) {
79
+ if (this.options.locationInfo)
80
+ this.currentTokenLocation = token.location;
81
+
82
+ if (token.type === Tokenizer.START_TAG_TOKEN)
83
+ this.handlers.startTag(token.tagName, token.attrs, token.selfClosing);
84
+
85
+ else if (token.type === Tokenizer.END_TAG_TOKEN)
86
+ this.handlers.endTag(token.tagName);
87
+
88
+ else if (token.type === Tokenizer.COMMENT_TOKEN)
89
+ this.handlers.comment(token.data);
90
+
91
+ else if (token.type === Tokenizer.DOCTYPE_TOKEN)
92
+ this.handlers.doctype(token.name, token.publicId, token.systemId);
93
+
94
+ };
95
+
96
+ SimpleApiParser.prototype._reset = function (html) {
97
+ this.tokenizerProxy = new TokenizerProxy(html, this.options);
98
+ this.pendingText = null;
99
+ this.currentTokenLocation = null;
100
+ };
101
+
102
+ SimpleApiParser.prototype._emitPendingText = function () {
103
+ if (this.pendingText !== null) {
104
+ this.handlers.text(this.pendingText);
105
+ this.pendingText = null;
106
+ }
107
+ };