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.
@@ -84,7 +84,6 @@ var $ = exports.TAG_NAMES = {
84
84
  IMAGE: 'image',
85
85
  INPUT: 'input',
86
86
  IFRAME: 'iframe',
87
- ISINDEX: 'isindex',
88
87
 
89
88
  KEYGEN: 'keygen',
90
89
 
@@ -215,14 +214,12 @@ SPECIAL_ELEMENTS[NS.HTML][$.HTML] = true;
215
214
  SPECIAL_ELEMENTS[NS.HTML][$.IFRAME] = true;
216
215
  SPECIAL_ELEMENTS[NS.HTML][$.IMG] = true;
217
216
  SPECIAL_ELEMENTS[NS.HTML][$.INPUT] = true;
218
- SPECIAL_ELEMENTS[NS.HTML][$.ISINDEX] = true;
219
217
  SPECIAL_ELEMENTS[NS.HTML][$.LI] = true;
220
218
  SPECIAL_ELEMENTS[NS.HTML][$.LINK] = true;
221
219
  SPECIAL_ELEMENTS[NS.HTML][$.LISTING] = true;
222
220
  SPECIAL_ELEMENTS[NS.HTML][$.MAIN] = true;
223
221
  SPECIAL_ELEMENTS[NS.HTML][$.MARQUEE] = true;
224
222
  SPECIAL_ELEMENTS[NS.HTML][$.MENU] = true;
225
- SPECIAL_ELEMENTS[NS.HTML][$.MENUITEM] = true;
226
223
  SPECIAL_ELEMENTS[NS.HTML][$.META] = true;
227
224
  SPECIAL_ELEMENTS[NS.HTML][$.NAV] = true;
228
225
  SPECIAL_ELEMENTS[NS.HTML][$.NOEMBED] = true;
package/lib/index.js CHANGED
@@ -1,108 +1,108 @@
1
- 'use strict';
2
-
3
- var Parser = require('./parser'),
4
- Serializer = require('./serializer');
5
-
6
- /** @namespace parse5 */
7
-
8
- /**
9
- * Parses an HTML string.
10
- * @function parse
11
- * @memberof parse5
12
- * @instance
13
- * @param {string} html - Input HTML string.
14
- * @param {ParserOptions} [options] - Parsing options.
15
- * @returns {ASTNode<Document>} document
16
- * @example
17
- * var parse5 = require('parse5');
18
- *
19
- * var document = parse5.parse('<!DOCTYPE html><html><head></head><body>Hi there!</body></html>');
20
- */
21
- exports.parse = function parse(html, options) {
22
- var parser = new Parser(options);
23
-
24
- return parser.parse(html);
25
- };
26
-
27
- /**
28
- * Parses an HTML fragment.
29
- * @function parseFragment
30
- * @memberof parse5
31
- * @instance
32
- * @param {ASTNode} [fragmentContext] - Parsing context element. If specified, given fragment
33
- * will be parsed as if it was set to the context element's `innerHTML` property.
34
- * @param {string} html - Input HTML fragment string.
35
- * @param {ParserOptions} [options] - Parsing options.
36
- * @returns {ASTNode<DocumentFragment>} documentFragment
37
- * @example
38
- * var parse5 = require('parse5');
39
- *
40
- * var documentFragment = parse5.parseFragment('<table></table>');
41
- *
42
- * // Parses the html fragment in the context of the parsed <table> element.
43
- * var trFragment = parser.parseFragment(documentFragment.childNodes[0], '<tr><td>Shake it, baby</td></tr>');
44
- */
45
- exports.parseFragment = function parseFragment(fragmentContext, html, options) {
46
- if (typeof fragmentContext === 'string') {
47
- options = html;
48
- html = fragmentContext;
49
- fragmentContext = null;
50
- }
51
-
52
- var parser = new Parser(options);
53
-
54
- return parser.parseFragment(html, fragmentContext);
55
- };
56
-
57
- /**
58
- * Serializes an AST node to an HTML string.
59
- * @function serialize
60
- * @memberof parse5
61
- * @instance
62
- * @param {ASTNode} node - Node to serialize.
63
- * @param {SerializerOptions} [options] - Serialization options.
64
- * @returns {String} html
65
- * @example
66
- * var parse5 = require('parse5');
67
- *
68
- * var document = parse5.parse('<!DOCTYPE html><html><head></head><body>Hi there!</body></html>');
69
- *
70
- * // Serializes a document.
71
- * var html = parse5.serialize(document);
72
- *
73
- * // Serializes the <body> element content.
74
- * var bodyInnerHtml = parse5.serialize(document.childNodes[0].childNodes[1]);
75
- */
76
- exports.serialize = function (node, options) {
77
- var serializer = new Serializer(node, options);
78
-
79
- return serializer.serialize();
80
- };
81
-
82
- /**
83
- * Provides built-in tree adapters that can be used for parsing and serialization.
84
- * @var treeAdapters
85
- * @memberof parse5
86
- * @instance
87
- * @property {TreeAdapter} default - Default tree format for parse5.
88
- * @property {TreeAdapter} htmlparser2 - Quite popular [htmlparser2](https://github.com/fb55/htmlparser2) tree format
89
- * (e.g. used by [cheerio](https://github.com/MatthewMueller/cheerio) and [jsdom](https://github.com/tmpvar/jsdom)).
90
- * @example
91
- * var parse5 = require('parse5');
92
- *
93
- * // Uses the default tree adapter for parsing.
94
- * var document = parse5.parse('<div></div>', { treeAdapter: parse5.treeAdapters.default });
95
- *
96
- * // Uses the htmlparser2 tree adapter with the SerializerStream.
97
- * var serializer = new parse5.SerializerStream(node, { treeAdapter: parse5.treeAdapters.htmlparser2 });
98
- */
99
- exports.treeAdapters = {
100
- default: require('./tree_adapters/default'),
101
- htmlparser2: require('./tree_adapters/htmlparser2')
102
- };
103
-
104
-
105
- // Streaming
106
- exports.ParserStream = require('./parser/stream');
107
- exports.SerializerStream = require('./serializer/stream');
108
- exports.SAXParser = require('./sax');
1
+ 'use strict';
2
+
3
+ var Parser = require('./parser'),
4
+ Serializer = require('./serializer');
5
+
6
+ /** @namespace parse5 */
7
+
8
+ /**
9
+ * Parses an HTML string.
10
+ * @function parse
11
+ * @memberof parse5
12
+ * @instance
13
+ * @param {string} html - Input HTML string.
14
+ * @param {ParserOptions} [options] - Parsing options.
15
+ * @returns {ASTNode<Document>} document
16
+ * @example
17
+ * var parse5 = require('parse5');
18
+ *
19
+ * var document = parse5.parse('<!DOCTYPE html><html><head></head><body>Hi there!</body></html>');
20
+ */
21
+ exports.parse = function parse(html, options) {
22
+ var parser = new Parser(options);
23
+
24
+ return parser.parse(html);
25
+ };
26
+
27
+ /**
28
+ * Parses an HTML fragment.
29
+ * @function parseFragment
30
+ * @memberof parse5
31
+ * @instance
32
+ * @param {ASTNode} [fragmentContext] - Parsing context element. If specified, given fragment
33
+ * will be parsed as if it was set to the context element's `innerHTML` property.
34
+ * @param {string} html - Input HTML fragment string.
35
+ * @param {ParserOptions} [options] - Parsing options.
36
+ * @returns {ASTNode<DocumentFragment>} documentFragment
37
+ * @example
38
+ * var parse5 = require('parse5');
39
+ *
40
+ * var documentFragment = parse5.parseFragment('<table></table>');
41
+ *
42
+ * // Parses the html fragment in the context of the parsed <table> element.
43
+ * var trFragment = parser.parseFragment(documentFragment.childNodes[0], '<tr><td>Shake it, baby</td></tr>');
44
+ */
45
+ exports.parseFragment = function parseFragment(fragmentContext, html, options) {
46
+ if (typeof fragmentContext === 'string') {
47
+ options = html;
48
+ html = fragmentContext;
49
+ fragmentContext = null;
50
+ }
51
+
52
+ var parser = new Parser(options);
53
+
54
+ return parser.parseFragment(html, fragmentContext);
55
+ };
56
+
57
+ /**
58
+ * Serializes an AST node to an HTML string.
59
+ * @function serialize
60
+ * @memberof parse5
61
+ * @instance
62
+ * @param {ASTNode} node - Node to serialize.
63
+ * @param {SerializerOptions} [options] - Serialization options.
64
+ * @returns {String} html
65
+ * @example
66
+ * var parse5 = require('parse5');
67
+ *
68
+ * var document = parse5.parse('<!DOCTYPE html><html><head></head><body>Hi there!</body></html>');
69
+ *
70
+ * // Serializes a document.
71
+ * var html = parse5.serialize(document);
72
+ *
73
+ * // Serializes the <body> element content.
74
+ * var bodyInnerHtml = parse5.serialize(document.childNodes[0].childNodes[1]);
75
+ */
76
+ exports.serialize = function (node, options) {
77
+ var serializer = new Serializer(node, options);
78
+
79
+ return serializer.serialize();
80
+ };
81
+
82
+ /**
83
+ * Provides built-in tree adapters that can be used for parsing and serialization.
84
+ * @var treeAdapters
85
+ * @memberof parse5
86
+ * @instance
87
+ * @property {TreeAdapter} default - Default tree format for parse5.
88
+ * @property {TreeAdapter} htmlparser2 - Quite popular [htmlparser2](https://github.com/fb55/htmlparser2) tree format
89
+ * (e.g. used by [cheerio](https://github.com/MatthewMueller/cheerio) and [jsdom](https://github.com/tmpvar/jsdom)).
90
+ * @example
91
+ * var parse5 = require('parse5');
92
+ *
93
+ * // Uses the default tree adapter for parsing.
94
+ * var document = parse5.parse('<div></div>', { treeAdapter: parse5.treeAdapters.default });
95
+ *
96
+ * // Uses the htmlparser2 tree adapter with the SerializerStream.
97
+ * var serializer = new parse5.SerializerStream(node, { treeAdapter: parse5.treeAdapters.htmlparser2 });
98
+ */
99
+ exports.treeAdapters = {
100
+ default: require('./tree_adapters/default'),
101
+ htmlparser2: require('./tree_adapters/htmlparser2')
102
+ };
103
+
104
+
105
+ // Streaming
106
+ exports.ParserStream = require('./parser/stream');
107
+ exports.SerializerStream = require('./serializer/stream');
108
+ exports.SAXParser = require('./sax');
@@ -50,7 +50,10 @@ function setEndLocation(element, closingToken, treeAdapter) {
50
50
  };
51
51
  }
52
52
 
53
- loc.endOffset = ctLocation.endOffset;
53
+ if (isClosingEndTag)
54
+ loc.endOffset = ctLocation.endOffset;
55
+ else
56
+ loc.endOffset = ctLocation.startOffset;
54
57
  }
55
58
  }
56
59
 
@@ -1,168 +1,169 @@
1
- 'use strict';
2
-
3
- var UNICODE = require('../common/unicode');
4
-
5
- //Aliases
6
- var $ = UNICODE.CODE_POINTS;
7
-
8
-
9
- exports.assign = function (tokenizer) {
10
- //NOTE: obtain Tokenizer proto this way to avoid module circular references
11
- var tokenizerProto = Object.getPrototypeOf(tokenizer),
12
- tokenStartOffset = -1,
13
- tokenCol = -1,
14
- tokenLine = 1,
15
- isEol = false,
16
- lineStartPosStack = [0],
17
- lineStartPos = 0,
18
- col = -1,
19
- line = 1;
20
-
21
- function attachLocationInfo(token) {
22
- /**
23
- * @typedef {Object} LocationInfo
24
- *
25
- * @property {Number} line - One-based line index
26
- * @property {Number} col - One-based column index
27
- * @property {Number} startOffset - Zero-based first character index
28
- * @property {Number} endOffset - Zero-based last character index
29
- */
30
- token.location = {
31
- line: tokenLine,
32
- col: tokenCol,
33
- startOffset: tokenStartOffset,
34
- endOffset: -1
35
- };
36
- }
37
-
38
- //NOTE: patch consumption method to track line/col information
39
- tokenizer._consume = function () {
40
- var cp = tokenizerProto._consume.call(this);
41
-
42
- //NOTE: LF should be in the last column of the line
43
- if (isEol) {
44
- isEol = false;
45
- line++;
46
- lineStartPosStack.push(this.preprocessor.pos);
47
- lineStartPos = this.preprocessor.pos;
48
- }
49
-
50
- if (cp === $.LINE_FEED)
51
- isEol = true;
52
-
53
- col = this.preprocessor.pos - lineStartPos + 1;
54
-
55
- return cp;
56
- };
57
-
58
- tokenizer._unconsume = function () {
59
- tokenizerProto._unconsume.call(this);
60
-
61
- while (lineStartPos > this.preprocessor.pos && lineStartPosStack.length > 1) {
62
- lineStartPos = lineStartPosStack.pop();
63
- line--;
64
- }
65
-
66
- col = this.preprocessor.pos - lineStartPos + 1;
67
- };
68
-
69
- //NOTE: patch token creation methods and attach location objects
70
- tokenizer._createStartTagToken = function (tagNameFirstCh) {
71
- tokenizerProto._createStartTagToken.call(this, tagNameFirstCh);
72
- attachLocationInfo(this.currentToken);
73
- };
74
-
75
- tokenizer._createEndTagToken = function (tagNameFirstCh) {
76
- tokenizerProto._createEndTagToken.call(this, tagNameFirstCh);
77
- attachLocationInfo(this.currentToken);
78
- };
79
-
80
- tokenizer._createCommentToken = function () {
81
- tokenizerProto._createCommentToken.call(this);
82
- attachLocationInfo(this.currentToken);
83
- };
84
-
85
- tokenizer._createDoctypeToken = function (doctypeNameFirstCh) {
86
- tokenizerProto._createDoctypeToken.call(this, doctypeNameFirstCh);
87
- attachLocationInfo(this.currentToken);
88
- };
89
-
90
- tokenizer._createCharacterToken = function (type, ch) {
91
- tokenizerProto._createCharacterToken.call(this, type, ch);
92
- attachLocationInfo(this.currentCharacterToken);
93
- };
94
-
95
- tokenizer._createAttr = function (attrNameFirstCh) {
96
- tokenizerProto._createAttr.call(this, attrNameFirstCh);
97
- this.currentAttrLocation = {
98
- line: line,
99
- col: col,
100
- startOffset: this.preprocessor.pos,
101
- endOffset: -1
102
- };
103
- };
104
-
105
- tokenizer._leaveAttrName = function (toState) {
106
- tokenizerProto._leaveAttrName.call(this, toState);
107
- this._attachCurrentAttrLocationInfo();
108
- };
109
-
110
- tokenizer._leaveAttrValue = function (toState) {
111
- tokenizerProto._leaveAttrValue.call(this, toState);
112
- this._attachCurrentAttrLocationInfo();
113
- };
114
-
115
- tokenizer._attachCurrentAttrLocationInfo = function () {
116
- this.currentAttrLocation.endOffset = this.preprocessor.pos;
117
-
118
- if (!this.currentToken.location.attrs)
119
- this.currentToken.location.attrs = {};
120
-
121
- /**
122
- * @typedef {Object} StartTagLocationInfo
123
- * @extends LocationInfo
124
- *
125
- * @property {Dictionary<String, LocationInfo>} attrs - Start tag attributes' location info.
126
- */
127
- this.currentToken.location.attrs[this.currentAttr.name] = this.currentAttrLocation;
128
- };
129
-
130
- //NOTE: patch token emission methods to determine end location
131
- tokenizer._emitCurrentToken = function () {
132
- //NOTE: if we have pending character token make it's end location equal to the
133
- //current token's start location.
134
- if (this.currentCharacterToken)
135
- this.currentCharacterToken.location.endOffset = this.currentToken.location.startOffset;
136
-
137
- this.currentToken.location.endOffset = this.preprocessor.pos + 1;
138
- tokenizerProto._emitCurrentToken.call(this);
139
- };
140
-
141
- tokenizer._emitCurrentCharacterToken = function () {
142
- //NOTE: if we have character token and it's location wasn't set in the _emitCurrentToken(),
143
- //then set it's location at the current preprocessor position.
144
- //We don't need to increment preprocessor position, since character token
145
- //emission is always forced by the start of the next character token here.
146
- //So, we already have advanced position.
147
- if (this.currentCharacterToken && this.currentCharacterToken.location.endOffset === -1)
148
- this.currentCharacterToken.location.endOffset = this.preprocessor.pos;
149
-
150
- tokenizerProto._emitCurrentCharacterToken.call(this);
151
- };
152
-
153
- //NOTE: patch initial states for each mode to obtain token start position
154
- Object.keys(tokenizerProto.MODE)
155
-
156
- .map(function (modeName) {
157
- return tokenizerProto.MODE[modeName];
158
- })
159
-
160
- .forEach(function (state) {
161
- tokenizer[state] = function (cp) {
162
- tokenStartOffset = this.preprocessor.pos;
163
- tokenLine = line;
164
- tokenCol = col;
165
- tokenizerProto[state].call(this, cp);
166
- };
167
- });
168
- };
1
+ 'use strict';
2
+
3
+ var UNICODE = require('../common/unicode');
4
+
5
+ //Aliases
6
+ var $ = UNICODE.CODE_POINTS;
7
+
8
+
9
+ exports.assign = function (tokenizer) {
10
+ //NOTE: obtain Tokenizer proto this way to avoid module circular references
11
+ var tokenizerProto = Object.getPrototypeOf(tokenizer),
12
+ tokenStartOffset = -1,
13
+ tokenCol = -1,
14
+ tokenLine = 1,
15
+ isEol = false,
16
+ lineStartPosStack = [0],
17
+ lineStartPos = 0,
18
+ col = -1,
19
+ line = 1;
20
+
21
+ function attachLocationInfo(token) {
22
+ /**
23
+ * @typedef {Object} LocationInfo
24
+ *
25
+ * @property {Number} line - One-based line index
26
+ * @property {Number} col - One-based column index
27
+ * @property {Number} startOffset - Zero-based first character index
28
+ * @property {Number} endOffset - Zero-based last character index
29
+ */
30
+ token.location = {
31
+ line: tokenLine,
32
+ col: tokenCol,
33
+ startOffset: tokenStartOffset,
34
+ endOffset: -1
35
+ };
36
+ }
37
+
38
+ //NOTE: patch consumption method to track line/col information
39
+ tokenizer._consume = function () {
40
+ var cp = tokenizerProto._consume.call(this);
41
+
42
+ //NOTE: LF should be in the last column of the line
43
+ if (isEol) {
44
+ isEol = false;
45
+ line++;
46
+ lineStartPosStack.push(this.preprocessor.sourcePos);
47
+ lineStartPos = this.preprocessor.sourcePos;
48
+ }
49
+
50
+ if (cp === $.LINE_FEED)
51
+ isEol = true;
52
+
53
+ col = this.preprocessor.sourcePos - lineStartPos + 1;
54
+
55
+ return cp;
56
+ };
57
+
58
+ tokenizer._unconsume = function () {
59
+ tokenizerProto._unconsume.call(this);
60
+ isEol = false;
61
+
62
+ while (lineStartPos > this.preprocessor.sourcePos && lineStartPosStack.length > 1) {
63
+ lineStartPos = lineStartPosStack.pop();
64
+ line--;
65
+ }
66
+
67
+ col = this.preprocessor.sourcePos - lineStartPos + 1;
68
+ };
69
+
70
+ //NOTE: patch token creation methods and attach location objects
71
+ tokenizer._createStartTagToken = function () {
72
+ tokenizerProto._createStartTagToken.call(this);
73
+ attachLocationInfo(this.currentToken);
74
+ };
75
+
76
+ tokenizer._createEndTagToken = function () {
77
+ tokenizerProto._createEndTagToken.call(this);
78
+ attachLocationInfo(this.currentToken);
79
+ };
80
+
81
+ tokenizer._createCommentToken = function () {
82
+ tokenizerProto._createCommentToken.call(this);
83
+ attachLocationInfo(this.currentToken);
84
+ };
85
+
86
+ tokenizer._createDoctypeToken = function (initialName) {
87
+ tokenizerProto._createDoctypeToken.call(this, initialName);
88
+ attachLocationInfo(this.currentToken);
89
+ };
90
+
91
+ tokenizer._createCharacterToken = function (type, ch) {
92
+ tokenizerProto._createCharacterToken.call(this, type, ch);
93
+ attachLocationInfo(this.currentCharacterToken);
94
+ };
95
+
96
+ tokenizer._createAttr = function (attrNameFirstCh) {
97
+ tokenizerProto._createAttr.call(this, attrNameFirstCh);
98
+ this.currentAttrLocation = {
99
+ line: line,
100
+ col: col,
101
+ startOffset: this.preprocessor.sourcePos,
102
+ endOffset: -1
103
+ };
104
+ };
105
+
106
+ tokenizer._leaveAttrName = function (toState) {
107
+ tokenizerProto._leaveAttrName.call(this, toState);
108
+ this._attachCurrentAttrLocationInfo();
109
+ };
110
+
111
+ tokenizer._leaveAttrValue = function (toState) {
112
+ tokenizerProto._leaveAttrValue.call(this, toState);
113
+ this._attachCurrentAttrLocationInfo();
114
+ };
115
+
116
+ tokenizer._attachCurrentAttrLocationInfo = function () {
117
+ this.currentAttrLocation.endOffset = this.preprocessor.sourcePos;
118
+
119
+ if (!this.currentToken.location.attrs)
120
+ this.currentToken.location.attrs = {};
121
+
122
+ /**
123
+ * @typedef {Object} StartTagLocationInfo
124
+ * @extends LocationInfo
125
+ *
126
+ * @property {Dictionary<String, LocationInfo>} attrs - Start tag attributes' location info.
127
+ */
128
+ this.currentToken.location.attrs[this.currentAttr.name] = this.currentAttrLocation;
129
+ };
130
+
131
+ //NOTE: patch token emission methods to determine end location
132
+ tokenizer._emitCurrentToken = function () {
133
+ //NOTE: if we have pending character token make it's end location equal to the
134
+ //current token's start location.
135
+ if (this.currentCharacterToken)
136
+ this.currentCharacterToken.location.endOffset = this.currentToken.location.startOffset;
137
+
138
+ this.currentToken.location.endOffset = this.preprocessor.sourcePos + 1;
139
+ tokenizerProto._emitCurrentToken.call(this);
140
+ };
141
+
142
+ tokenizer._emitCurrentCharacterToken = function () {
143
+ //NOTE: if we have character token and it's location wasn't set in the _emitCurrentToken(),
144
+ //then set it's location at the current preprocessor position.
145
+ //We don't need to increment preprocessor position, since character token
146
+ //emission is always forced by the start of the next character token here.
147
+ //So, we already have advanced position.
148
+ if (this.currentCharacterToken && this.currentCharacterToken.location.endOffset === -1)
149
+ this.currentCharacterToken.location.endOffset = this.preprocessor.sourcePos;
150
+
151
+ tokenizerProto._emitCurrentCharacterToken.call(this);
152
+ };
153
+
154
+ //NOTE: patch initial states for each mode to obtain token start position
155
+ Object.keys(tokenizerProto.MODE)
156
+
157
+ .map(function (modeName) {
158
+ return tokenizerProto.MODE[modeName];
159
+ })
160
+
161
+ .forEach(function (state) {
162
+ tokenizer[state] = function (cp) {
163
+ tokenStartOffset = this.preprocessor.sourcePos;
164
+ tokenLine = line;
165
+ tokenCol = col;
166
+ tokenizerProto[state].call(this, cp);
167
+ };
168
+ });
169
+ };