node-html-parser 6.1.12 → 6.1.15-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/CHANGELOG.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [6.1.14](https://github.com/taoqf/node-fast-html-parser/compare/v6.1.13...v6.1.14) (2024-05-14)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * [#274](https://github.com/taoqf/node-fast-html-parser/issues/274) ([fef574d](https://github.com/taoqf/node-fast-html-parser/commit/fef574da98ce224980ce6fb9f9ea033d3331a161))
11
+
12
+ ### [6.1.13](https://github.com/taoqf/node-fast-html-parser/compare/v6.1.12...v6.1.13) (2024-03-29)
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * add rawTagName [#269](https://github.com/taoqf/node-fast-html-parser/issues/269) [#270](https://github.com/taoqf/node-fast-html-parser/issues/270) ([9ac642d](https://github.com/taoqf/node-fast-html-parser/commit/9ac642d7b6a97c84fd4471b8eaa0bd9debf5e325))
18
+
5
19
  ### [6.1.12](https://github.com/taoqf/node-fast-html-parser/compare/v6.1.11...v6.1.12) (2023-12-25)
6
20
 
7
21
 
package/README.md CHANGED
@@ -81,15 +81,17 @@ Parse the data provided, and return the root of the generated DOM.
81
81
 
82
82
  ```js
83
83
  {
84
- lowerCaseTagName: false, // convert tag name to lower case (hurts performance heavily)
85
- comment: false, // retrieve comments (hurts performance slightly)
86
- voidTag:{
84
+ lowerCaseTagName: false, // convert tag name to lower case (hurts performance heavily)
85
+ comment: false, // retrieve comments (hurts performance slightly)
86
+ fixNestedATags: false, // fix invalid nested <a> HTML tags
87
+ parseNoneClosedTags: false, // close none closed HTML tags instead of removing them
88
+ voidTag: {
87
89
  tags: ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr'], // optional and case insensitive, default value is ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr']
88
- closingSlash: true // optional, default false. void tag serialisation, add a final slash <br/>
90
+ closingSlash: true // optional, default false. void tag serialisation, add a final slash <br/>
89
91
  },
90
92
  blockTextElements: {
91
- script: true, // keep text content when parsing
92
- noscript: true, // keep text content when parsing
93
+ script: true, // keep text content when parsing
94
+ noscript: true, // keep text content when parsing
93
95
  style: true, // keep text content when parsing
94
96
  pre: true // keep text content when parsing
95
97
  }
@@ -184,6 +186,7 @@ Node --|> TextNode
184
186
  Node ..> ClassList
185
187
  ```
186
188
 
189
+
187
190
  ## HTMLElement Methods
188
191
 
189
192
  ### trimRight()
@@ -214,9 +217,26 @@ Note: Use * for all elements.
214
217
 
215
218
  Query closest element by css selector. `null` if not found.
216
219
 
220
+ ### before(...nodesOrStrings)
221
+
222
+ Insert one or multiple nodes or text before the current element. Does not work on root.
223
+
224
+ ### after(...nodesOrStrings)
225
+
226
+ Insert one or multiple nodes or text after the current element. Does not work on root.
227
+
228
+ ### prepend(...nodesOrStrings)
229
+
230
+ Insert one or multiple nodes or text to the first position of an element's child nodes.
231
+
232
+ ### append(...nodesOrStrings)
233
+
234
+ Insert one or multiple nodes or text to the last position of an element's child nodes.
235
+ This is similar to appendChild, but accepts arbitrarily many nodes and converts strings to text nodes.
236
+
217
237
  ### appendChild(node)
218
238
 
219
- Append a child node to childNodes
239
+ Append a node to an element's child nodes.
220
240
 
221
241
  ### insertAdjacentHTML(where, html)
222
242
 
@@ -296,6 +316,7 @@ Clone a node.
296
316
 
297
317
  Get element by it's ID.
298
318
 
319
+
299
320
  ## HTMLElement Properties
300
321
 
301
322
  ### text
@@ -310,7 +331,7 @@ Get escaped (as-is) text value of current node and its children. May have
310
331
 
311
332
  ### tagName
312
333
 
313
- Get or Set tag name of HTMLElement. Notice: the returned value would be an uppercase string.
334
+ Get or Set tag name of HTMLElement. Note that the returned value is an uppercase string.
314
335
 
315
336
  ### structuredText
316
337
 
@@ -320,13 +341,33 @@ Get structured Text.
320
341
 
321
342
  Get DOM structure.
322
343
 
344
+ ### childNodes
345
+
346
+ Get all child nodes. A child node can be a TextNode, a CommentNode and a HTMLElement.
347
+
348
+ ### children
349
+
350
+ Get all child elements, so all child nodes of type HTMLELement.
351
+
323
352
  ### firstChild
324
353
 
325
- Get first child node. `undefined` if no child.
354
+ Get first child node. `undefined` if the node has no children.
326
355
 
327
356
  ### lastChild
328
357
 
329
- Get last child node. `undefined` if no child
358
+ Get last child node. `undefined` if the node has no children.
359
+
360
+ ### firstElementChild
361
+
362
+ Get the first child of type HTMLElement. `undefined` if none exists.
363
+
364
+ ### lastElementChild
365
+
366
+ Get the first child of type HTMLElement. `undefined` if none exists.
367
+
368
+ ### childElementCount
369
+
370
+ Get the number of children that are of type HTMLElement.
330
371
 
331
372
  ### innerHTML
332
373
 
package/dist/main.js CHANGED
@@ -263,6 +263,7 @@ define("nodes/text", ["require", "exports", "he", "nodes/node", "nodes/type"], f
263
263
  * @type {Number}
264
264
  */
265
265
  _this.nodeType = type_2.default.TEXT_NODE;
266
+ _this.rawTagName = '';
266
267
  _this._rawText = rawText;
267
268
  return _this;
268
269
  }
@@ -737,7 +738,8 @@ define("nodes/html", ["require", "exports", "css-select", "he", "back", "matcher
737
738
  return child === _this;
738
739
  });
739
740
  resetParent([this], null);
740
- parent.childNodes = __spreadArray(__spreadArray(__spreadArray([], parent.childNodes.slice(0, idx), true), resetParent(content, parent), true), parent.childNodes.slice(idx + 1), true);
741
+ resetParent(content, parent);
742
+ parent.childNodes = __spreadArray(__spreadArray(__spreadArray([], parent.childNodes.slice(0, idx), true), content, true), parent.childNodes.slice(idx + 1), true);
741
743
  return this;
742
744
  };
743
745
  Object.defineProperty(HTMLElement.prototype, "outerHTML", {
@@ -823,6 +825,13 @@ define("nodes/html", ["require", "exports", "css-select", "he", "back", "matcher
823
825
  _this.childNodes[o++] = node;
824
826
  });
825
827
  this.childNodes.length = o;
828
+ // remove whitespace between attributes
829
+ var attrs = Object.keys(this.rawAttributes).map(function (key) {
830
+ var val = _this.rawAttributes[key];
831
+ return "".concat(key, "=").concat(JSON.stringify(val));
832
+ }).join(' ');
833
+ this.rawAttrs = attrs;
834
+ delete this._rawAttrs;
826
835
  return this;
827
836
  };
828
837
  /**
@@ -979,34 +988,9 @@ define("nodes/html", ["require", "exports", "css-select", "he", "back", "matcher
979
988
  * @return {Node} node appended
980
989
  */
981
990
  HTMLElement.prototype.appendChild = function (node) {
982
- // remove the node from it's parent
983
- node.remove();
984
- this.childNodes.push(node);
985
- node.parentNode = this;
991
+ this.append(node);
986
992
  return node;
987
993
  };
988
- Object.defineProperty(HTMLElement.prototype, "firstChild", {
989
- /**
990
- * Get first child node
991
- * @return {Node | undefined} first child node; or undefined if none
992
- */
993
- get: function () {
994
- return this.childNodes[0];
995
- },
996
- enumerable: false,
997
- configurable: true
998
- });
999
- Object.defineProperty(HTMLElement.prototype, "lastChild", {
1000
- /**
1001
- * Get last child node
1002
- * @return {Node | undefined} last child node; or undefined if none
1003
- */
1004
- get: function () {
1005
- return (0, back_1.default)(this.childNodes);
1006
- },
1007
- enumerable: false,
1008
- configurable: true
1009
- });
1010
994
  Object.defineProperty(HTMLElement.prototype, "attrs", {
1011
995
  /**
1012
996
  * Get attributes
@@ -1165,42 +1149,70 @@ define("nodes/html", ["require", "exports", "css-select", "he", "back", "matcher
1165
1149
  return this;
1166
1150
  };
1167
1151
  HTMLElement.prototype.insertAdjacentHTML = function (where, html) {
1168
- var _a, _b, _c;
1169
- var _this = this;
1170
1152
  if (arguments.length < 2) {
1171
1153
  throw new Error('2 arguments required');
1172
1154
  }
1173
1155
  var p = parse(html, this._parseOptions);
1174
1156
  if (where === 'afterend') {
1175
- var idx = this.parentNode.childNodes.findIndex(function (child) {
1176
- return child === _this;
1177
- });
1178
- resetParent(p.childNodes, this.parentNode);
1179
- (_a = this.parentNode.childNodes).splice.apply(_a, __spreadArray([idx + 1, 0], p.childNodes, false));
1157
+ this.after.apply(this, p.childNodes);
1180
1158
  }
1181
1159
  else if (where === 'afterbegin') {
1182
- resetParent(p.childNodes, this);
1183
- (_b = this.childNodes).unshift.apply(_b, p.childNodes);
1160
+ this.prepend.apply(this, p.childNodes);
1184
1161
  }
1185
1162
  else if (where === 'beforeend') {
1186
- p.childNodes.forEach(function (n) {
1187
- _this.appendChild(n);
1188
- });
1163
+ this.append.apply(this, p.childNodes);
1189
1164
  }
1190
1165
  else if (where === 'beforebegin') {
1191
- var idx = this.parentNode.childNodes.findIndex(function (child) {
1192
- return child === _this;
1193
- });
1194
- resetParent(p.childNodes, this.parentNode);
1195
- (_c = this.parentNode.childNodes).splice.apply(_c, __spreadArray([idx, 0], p.childNodes, false));
1166
+ this.before.apply(this, p.childNodes);
1196
1167
  }
1197
1168
  else {
1198
1169
  throw new Error("The value provided ('".concat(where, "') is not one of 'beforebegin', 'afterbegin', 'beforeend', or 'afterend'"));
1199
1170
  }
1200
1171
  return this;
1201
- // if (!where || html === undefined || html === null) {
1202
- // return;
1203
- // }
1172
+ };
1173
+ /** Prepend nodes or strings to this node's children. */
1174
+ HTMLElement.prototype.prepend = function () {
1175
+ var _a;
1176
+ var insertable = [];
1177
+ for (var _i = 0; _i < arguments.length; _i++) {
1178
+ insertable[_i] = arguments[_i];
1179
+ }
1180
+ var nodes = resolveInsertable(insertable);
1181
+ resetParent(nodes, this);
1182
+ (_a = this.childNodes).unshift.apply(_a, nodes);
1183
+ };
1184
+ /** Append nodes or strings to this node's children. */
1185
+ HTMLElement.prototype.append = function () {
1186
+ var _a;
1187
+ var insertable = [];
1188
+ for (var _i = 0; _i < arguments.length; _i++) {
1189
+ insertable[_i] = arguments[_i];
1190
+ }
1191
+ var nodes = resolveInsertable(insertable);
1192
+ resetParent(nodes, this);
1193
+ (_a = this.childNodes).push.apply(_a, nodes);
1194
+ };
1195
+ /** Insert nodes or strings before this node. */
1196
+ HTMLElement.prototype.before = function () {
1197
+ var insertable = [];
1198
+ for (var _i = 0; _i < arguments.length; _i++) {
1199
+ insertable[_i] = arguments[_i];
1200
+ }
1201
+ var nodes = resolveInsertable(insertable);
1202
+ var siblings = this.parentNode.childNodes;
1203
+ resetParent(nodes, this.parentNode);
1204
+ siblings.splice.apply(siblings, __spreadArray([siblings.indexOf(this), 0], nodes, false));
1205
+ };
1206
+ /** Insert nodes or strings after this node. */
1207
+ HTMLElement.prototype.after = function () {
1208
+ var insertable = [];
1209
+ for (var _i = 0; _i < arguments.length; _i++) {
1210
+ insertable[_i] = arguments[_i];
1211
+ }
1212
+ var nodes = resolveInsertable(insertable);
1213
+ var siblings = this.parentNode.childNodes;
1214
+ resetParent(nodes, this.parentNode);
1215
+ siblings.splice.apply(siblings, __spreadArray([siblings.indexOf(this) + 1, 0], nodes, false));
1204
1216
  };
1205
1217
  Object.defineProperty(HTMLElement.prototype, "nextSibling", {
1206
1218
  get: function () {
@@ -1280,6 +1292,72 @@ define("nodes/html", ["require", "exports", "css-select", "he", "back", "matcher
1280
1292
  enumerable: false,
1281
1293
  configurable: true
1282
1294
  });
1295
+ Object.defineProperty(HTMLElement.prototype, "children", {
1296
+ /** Get all childNodes of type {@link HTMLElement}. */
1297
+ get: function () {
1298
+ var children = [];
1299
+ for (var _i = 0, _a = this.childNodes; _i < _a.length; _i++) {
1300
+ var childNode = _a[_i];
1301
+ if (childNode instanceof HTMLElement) {
1302
+ children.push(childNode);
1303
+ }
1304
+ }
1305
+ return children;
1306
+ },
1307
+ enumerable: false,
1308
+ configurable: true
1309
+ });
1310
+ Object.defineProperty(HTMLElement.prototype, "firstChild", {
1311
+ /**
1312
+ * Get the first child node.
1313
+ * @return The first child or undefined if none exists.
1314
+ */
1315
+ get: function () {
1316
+ return this.childNodes[0];
1317
+ },
1318
+ enumerable: false,
1319
+ configurable: true
1320
+ });
1321
+ Object.defineProperty(HTMLElement.prototype, "firstElementChild", {
1322
+ /**
1323
+ * Get the first child node of type {@link HTMLElement}.
1324
+ * @return The first child element or undefined if none exists.
1325
+ */
1326
+ get: function () {
1327
+ return this.children[0];
1328
+ },
1329
+ enumerable: false,
1330
+ configurable: true
1331
+ });
1332
+ Object.defineProperty(HTMLElement.prototype, "lastChild", {
1333
+ /**
1334
+ * Get the last child node.
1335
+ * @return The last child or undefined if none exists.
1336
+ */
1337
+ get: function () {
1338
+ return (0, back_1.default)(this.childNodes);
1339
+ },
1340
+ enumerable: false,
1341
+ configurable: true
1342
+ });
1343
+ Object.defineProperty(HTMLElement.prototype, "lastElementChild", {
1344
+ /**
1345
+ * Get the last child node of type {@link HTMLElement}.
1346
+ * @return The last child element or undefined if none exists.
1347
+ */
1348
+ get: function () {
1349
+ return this.children[this.children.length - 1];
1350
+ },
1351
+ enumerable: false,
1352
+ configurable: true
1353
+ });
1354
+ Object.defineProperty(HTMLElement.prototype, "childElementCount", {
1355
+ get: function () {
1356
+ return this.children.length;
1357
+ },
1358
+ enumerable: false,
1359
+ configurable: true
1360
+ });
1283
1361
  Object.defineProperty(HTMLElement.prototype, "classNames", {
1284
1362
  get: function () {
1285
1363
  return this.classList.toString();
@@ -1287,9 +1365,7 @@ define("nodes/html", ["require", "exports", "css-select", "he", "back", "matcher
1287
1365
  enumerable: false,
1288
1366
  configurable: true
1289
1367
  });
1290
- /**
1291
- * Clone this Node
1292
- */
1368
+ /** Clone this Node */
1293
1369
  HTMLElement.prototype.clone = function () {
1294
1370
  return parse(this.toString(), this._parseOptions).firstChild;
1295
1371
  };
@@ -1498,10 +1574,11 @@ define("nodes/html", ["require", "exports", "css-select", "he", "back", "matcher
1498
1574
  * Parse a chuck of HTML source.
1499
1575
  */
1500
1576
  function parse(data, options) {
1577
+ var _a, _b;
1501
1578
  if (options === void 0) { options = {}; }
1502
1579
  var stack = base_parse(data, options);
1503
1580
  var root = stack[0];
1504
- var _loop_1 = function () {
1581
+ while (stack.length > 1) {
1505
1582
  // Handle each error elements.
1506
1583
  var last = stack.pop();
1507
1584
  var oneBefore = (0, back_1.default)(stack);
@@ -1511,9 +1588,7 @@ define("nodes/html", ["require", "exports", "css-select", "he", "back", "matcher
1511
1588
  // this is wrong, becouse this will put the H3 outside the current right position which should be inside the current Html Element, see issue 152 for more info
1512
1589
  if (options.parseNoneClosedTags !== true) {
1513
1590
  oneBefore.removeChild(last);
1514
- last.childNodes.forEach(function (child) {
1515
- oneBefore.parentNode.appendChild(child);
1516
- });
1591
+ (_a = oneBefore.parentNode.childNodes).push.apply(_a, last.childNodes);
1517
1592
  stack.pop();
1518
1593
  }
1519
1594
  }
@@ -1523,31 +1598,43 @@ define("nodes/html", ["require", "exports", "css-select", "he", "back", "matcher
1523
1598
  // eslint-disable-next-line no-lonely-if
1524
1599
  if (options.parseNoneClosedTags !== true) {
1525
1600
  oneBefore.removeChild(last);
1526
- last.childNodes.forEach(function (child) {
1527
- oneBefore.appendChild(child);
1528
- });
1601
+ (_b = oneBefore.childNodes).push.apply(_b, last.childNodes);
1529
1602
  }
1530
1603
  }
1531
1604
  }
1532
1605
  else {
1533
1606
  // If it's final element just skip.
1534
1607
  }
1535
- };
1536
- while (stack.length > 1) {
1537
- _loop_1();
1538
1608
  }
1539
1609
  // response.childNodes.forEach((node) => {
1540
1610
  // if (node instanceof HTMLElement) {
1541
1611
  // node.parentNode = null;
1542
1612
  // }
1543
1613
  // });
1614
+ resetParent(root.childNodes, root, true);
1544
1615
  return root;
1545
1616
  }
1546
1617
  exports.parse = parse;
1547
- function resetParent(nodes, parent) {
1548
- return nodes.map(function (node) {
1618
+ /**
1619
+ * Resolves a list of {@link NodeInsertable} to a list of nodes,
1620
+ * and removes nodes from any potential parent.
1621
+ */
1622
+ function resolveInsertable(insertable) {
1623
+ return insertable.map(function (val) {
1624
+ if (typeof val === 'string') {
1625
+ return new text_1.default(val);
1626
+ }
1627
+ val.remove();
1628
+ return val;
1629
+ });
1630
+ }
1631
+ function resetParent(nodes, parent, recursive) {
1632
+ if (recursive === void 0) { recursive = false; }
1633
+ nodes.forEach(function (node) {
1549
1634
  node.parentNode = parent;
1550
- return node;
1635
+ if (recursive && node instanceof HTMLElement) {
1636
+ resetParent(node.childNodes, node, true);
1637
+ }
1551
1638
  });
1552
1639
  }
1553
1640
  });
@@ -1558,10 +1645,12 @@ define("nodes/comment", ["require", "exports", "nodes/node", "nodes/type"], func
1558
1645
  type_4 = __importDefault(type_4);
1559
1646
  var CommentNode = /** @class */ (function (_super) {
1560
1647
  __extends(CommentNode, _super);
1561
- function CommentNode(rawText, parentNode, range) {
1648
+ function CommentNode(rawText, parentNode, range, rawTagName) {
1562
1649
  if (parentNode === void 0) { parentNode = null; }
1650
+ if (rawTagName === void 0) { rawTagName = '!--'; }
1563
1651
  var _this = _super.call(this, parentNode, range) || this;
1564
1652
  _this.rawText = rawText;
1653
+ _this.rawTagName = rawTagName;
1565
1654
  /**
1566
1655
  * Node Type declaration.
1567
1656
  * @type {Number}
@@ -1570,7 +1659,7 @@ define("nodes/comment", ["require", "exports", "nodes/node", "nodes/type"], func
1570
1659
  return _this;
1571
1660
  }
1572
1661
  CommentNode.prototype.clone = function () {
1573
- return new CommentNode(this.rawText, null);
1662
+ return new CommentNode(this.rawText, null, undefined, this.rawTagName);
1574
1663
  };
1575
1664
  Object.defineProperty(CommentNode.prototype, "text", {
1576
1665
  /**
@@ -3,8 +3,9 @@ import Node from './node';
3
3
  import NodeType from './type';
4
4
  export default class CommentNode extends Node {
5
5
  rawText: string;
6
+ rawTagName: string;
6
7
  clone(): CommentNode;
7
- constructor(rawText: string, parentNode?: HTMLElement, range?: [number, number]);
8
+ constructor(rawText: string, parentNode?: HTMLElement, range?: [number, number], rawTagName?: string);
8
9
  /**
9
10
  * Node Type declaration.
10
11
  * @type {Number}
@@ -22,10 +22,12 @@ var node_1 = __importDefault(require("./node"));
22
22
  var type_1 = __importDefault(require("./type"));
23
23
  var CommentNode = /** @class */ (function (_super) {
24
24
  __extends(CommentNode, _super);
25
- function CommentNode(rawText, parentNode, range) {
25
+ function CommentNode(rawText, parentNode, range, rawTagName) {
26
26
  if (parentNode === void 0) { parentNode = null; }
27
+ if (rawTagName === void 0) { rawTagName = '!--'; }
27
28
  var _this = _super.call(this, parentNode, range) || this;
28
29
  _this.rawText = rawText;
30
+ _this.rawTagName = rawTagName;
29
31
  /**
30
32
  * Node Type declaration.
31
33
  * @type {Number}
@@ -34,7 +36,7 @@ var CommentNode = /** @class */ (function (_super) {
34
36
  return _this;
35
37
  }
36
38
  CommentNode.prototype.clone = function () {
37
- return new CommentNode(this.rawText, null);
39
+ return new CommentNode(this.rawText, null, undefined, this.rawTagName);
38
40
  };
39
41
  Object.defineProperty(CommentNode.prototype, "text", {
40
42
  /**
@@ -11,7 +11,8 @@ export interface Attributes {
11
11
  export interface RawAttributes {
12
12
  [key: string]: string;
13
13
  }
14
- export declare type InsertPosition = 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend';
14
+ export type InsertPosition = 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend';
15
+ export type NodeInsertable = Node | string;
15
16
  declare class DOMTokenList {
16
17
  private _set;
17
18
  private _afterUpdate;
@@ -152,16 +153,6 @@ export default class HTMLElement extends Node {
152
153
  * @return {Node} node appended
153
154
  */
154
155
  appendChild<T extends Node = Node>(node: T): T;
155
- /**
156
- * Get first child node
157
- * @return {Node | undefined} first child node; or undefined if none
158
- */
159
- get firstChild(): Node | undefined;
160
- /**
161
- * Get last child node
162
- * @return {Node | undefined} last child node; or undefined if none
163
- */
164
- get lastChild(): Node | undefined;
165
156
  /**
166
157
  * Get attributes
167
158
  * @access private
@@ -193,14 +184,43 @@ export default class HTMLElement extends Node {
193
184
  */
194
185
  setAttributes(attributes: Attributes): this;
195
186
  insertAdjacentHTML(where: InsertPosition, html: string): this;
187
+ /** Prepend nodes or strings to this node's children. */
188
+ prepend(...insertable: NodeInsertable[]): void;
189
+ /** Append nodes or strings to this node's children. */
190
+ append(...insertable: NodeInsertable[]): void;
191
+ /** Insert nodes or strings before this node. */
192
+ before(...insertable: NodeInsertable[]): void;
193
+ /** Insert nodes or strings after this node. */
194
+ after(...insertable: NodeInsertable[]): void;
196
195
  get nextSibling(): Node | null;
197
196
  get nextElementSibling(): HTMLElement | null;
198
197
  get previousSibling(): Node | null;
199
198
  get previousElementSibling(): HTMLElement | null;
200
- get classNames(): string;
199
+ /** Get all childNodes of type {@link HTMLElement}. */
200
+ get children(): HTMLElement[];
201
+ /**
202
+ * Get the first child node.
203
+ * @return The first child or undefined if none exists.
204
+ */
205
+ get firstChild(): Node | undefined;
206
+ /**
207
+ * Get the first child node of type {@link HTMLElement}.
208
+ * @return The first child element or undefined if none exists.
209
+ */
210
+ get firstElementChild(): HTMLElement | undefined;
201
211
  /**
202
- * Clone this Node
212
+ * Get the last child node.
213
+ * @return The last child or undefined if none exists.
203
214
  */
215
+ get lastChild(): Node | undefined;
216
+ /**
217
+ * Get the last child node of type {@link HTMLElement}.
218
+ * @return The last child element or undefined if none exists.
219
+ */
220
+ get lastElementChild(): HTMLElement | undefined;
221
+ get childElementCount(): number;
222
+ get classNames(): string;
223
+ /** Clone this Node */
204
224
  clone(): Node;
205
225
  }
206
226
  export interface Options {
@@ -403,7 +403,8 @@ var HTMLElement = /** @class */ (function (_super) {
403
403
  return child === _this;
404
404
  });
405
405
  resetParent([this], null);
406
- parent.childNodes = __spreadArray(__spreadArray(__spreadArray([], parent.childNodes.slice(0, idx), true), resetParent(content, parent), true), parent.childNodes.slice(idx + 1), true);
406
+ resetParent(content, parent);
407
+ parent.childNodes = __spreadArray(__spreadArray(__spreadArray([], parent.childNodes.slice(0, idx), true), content, true), parent.childNodes.slice(idx + 1), true);
407
408
  return this;
408
409
  };
409
410
  Object.defineProperty(HTMLElement.prototype, "outerHTML", {
@@ -489,6 +490,13 @@ var HTMLElement = /** @class */ (function (_super) {
489
490
  _this.childNodes[o++] = node;
490
491
  });
491
492
  this.childNodes.length = o;
493
+ // remove whitespace between attributes
494
+ var attrs = Object.keys(this.rawAttributes).map(function (key) {
495
+ var val = _this.rawAttributes[key];
496
+ return "".concat(key, "=").concat(JSON.stringify(val));
497
+ }).join(' ');
498
+ this.rawAttrs = attrs;
499
+ delete this._rawAttrs;
492
500
  return this;
493
501
  };
494
502
  /**
@@ -645,34 +653,9 @@ var HTMLElement = /** @class */ (function (_super) {
645
653
  * @return {Node} node appended
646
654
  */
647
655
  HTMLElement.prototype.appendChild = function (node) {
648
- // remove the node from it's parent
649
- node.remove();
650
- this.childNodes.push(node);
651
- node.parentNode = this;
656
+ this.append(node);
652
657
  return node;
653
658
  };
654
- Object.defineProperty(HTMLElement.prototype, "firstChild", {
655
- /**
656
- * Get first child node
657
- * @return {Node | undefined} first child node; or undefined if none
658
- */
659
- get: function () {
660
- return this.childNodes[0];
661
- },
662
- enumerable: false,
663
- configurable: true
664
- });
665
- Object.defineProperty(HTMLElement.prototype, "lastChild", {
666
- /**
667
- * Get last child node
668
- * @return {Node | undefined} last child node; or undefined if none
669
- */
670
- get: function () {
671
- return (0, back_1.default)(this.childNodes);
672
- },
673
- enumerable: false,
674
- configurable: true
675
- });
676
659
  Object.defineProperty(HTMLElement.prototype, "attrs", {
677
660
  /**
678
661
  * Get attributes
@@ -831,42 +814,70 @@ var HTMLElement = /** @class */ (function (_super) {
831
814
  return this;
832
815
  };
833
816
  HTMLElement.prototype.insertAdjacentHTML = function (where, html) {
834
- var _a, _b, _c;
835
- var _this = this;
836
817
  if (arguments.length < 2) {
837
818
  throw new Error('2 arguments required');
838
819
  }
839
820
  var p = parse(html, this._parseOptions);
840
821
  if (where === 'afterend') {
841
- var idx = this.parentNode.childNodes.findIndex(function (child) {
842
- return child === _this;
843
- });
844
- resetParent(p.childNodes, this.parentNode);
845
- (_a = this.parentNode.childNodes).splice.apply(_a, __spreadArray([idx + 1, 0], p.childNodes, false));
822
+ this.after.apply(this, p.childNodes);
846
823
  }
847
824
  else if (where === 'afterbegin') {
848
- resetParent(p.childNodes, this);
849
- (_b = this.childNodes).unshift.apply(_b, p.childNodes);
825
+ this.prepend.apply(this, p.childNodes);
850
826
  }
851
827
  else if (where === 'beforeend') {
852
- p.childNodes.forEach(function (n) {
853
- _this.appendChild(n);
854
- });
828
+ this.append.apply(this, p.childNodes);
855
829
  }
856
830
  else if (where === 'beforebegin') {
857
- var idx = this.parentNode.childNodes.findIndex(function (child) {
858
- return child === _this;
859
- });
860
- resetParent(p.childNodes, this.parentNode);
861
- (_c = this.parentNode.childNodes).splice.apply(_c, __spreadArray([idx, 0], p.childNodes, false));
831
+ this.before.apply(this, p.childNodes);
862
832
  }
863
833
  else {
864
834
  throw new Error("The value provided ('".concat(where, "') is not one of 'beforebegin', 'afterbegin', 'beforeend', or 'afterend'"));
865
835
  }
866
836
  return this;
867
- // if (!where || html === undefined || html === null) {
868
- // return;
869
- // }
837
+ };
838
+ /** Prepend nodes or strings to this node's children. */
839
+ HTMLElement.prototype.prepend = function () {
840
+ var _a;
841
+ var insertable = [];
842
+ for (var _i = 0; _i < arguments.length; _i++) {
843
+ insertable[_i] = arguments[_i];
844
+ }
845
+ var nodes = resolveInsertable(insertable);
846
+ resetParent(nodes, this);
847
+ (_a = this.childNodes).unshift.apply(_a, nodes);
848
+ };
849
+ /** Append nodes or strings to this node's children. */
850
+ HTMLElement.prototype.append = function () {
851
+ var _a;
852
+ var insertable = [];
853
+ for (var _i = 0; _i < arguments.length; _i++) {
854
+ insertable[_i] = arguments[_i];
855
+ }
856
+ var nodes = resolveInsertable(insertable);
857
+ resetParent(nodes, this);
858
+ (_a = this.childNodes).push.apply(_a, nodes);
859
+ };
860
+ /** Insert nodes or strings before this node. */
861
+ HTMLElement.prototype.before = function () {
862
+ var insertable = [];
863
+ for (var _i = 0; _i < arguments.length; _i++) {
864
+ insertable[_i] = arguments[_i];
865
+ }
866
+ var nodes = resolveInsertable(insertable);
867
+ var siblings = this.parentNode.childNodes;
868
+ resetParent(nodes, this.parentNode);
869
+ siblings.splice.apply(siblings, __spreadArray([siblings.indexOf(this), 0], nodes, false));
870
+ };
871
+ /** Insert nodes or strings after this node. */
872
+ HTMLElement.prototype.after = function () {
873
+ var insertable = [];
874
+ for (var _i = 0; _i < arguments.length; _i++) {
875
+ insertable[_i] = arguments[_i];
876
+ }
877
+ var nodes = resolveInsertable(insertable);
878
+ var siblings = this.parentNode.childNodes;
879
+ resetParent(nodes, this.parentNode);
880
+ siblings.splice.apply(siblings, __spreadArray([siblings.indexOf(this) + 1, 0], nodes, false));
870
881
  };
871
882
  Object.defineProperty(HTMLElement.prototype, "nextSibling", {
872
883
  get: function () {
@@ -946,6 +957,72 @@ var HTMLElement = /** @class */ (function (_super) {
946
957
  enumerable: false,
947
958
  configurable: true
948
959
  });
960
+ Object.defineProperty(HTMLElement.prototype, "children", {
961
+ /** Get all childNodes of type {@link HTMLElement}. */
962
+ get: function () {
963
+ var children = [];
964
+ for (var _i = 0, _a = this.childNodes; _i < _a.length; _i++) {
965
+ var childNode = _a[_i];
966
+ if (childNode instanceof HTMLElement) {
967
+ children.push(childNode);
968
+ }
969
+ }
970
+ return children;
971
+ },
972
+ enumerable: false,
973
+ configurable: true
974
+ });
975
+ Object.defineProperty(HTMLElement.prototype, "firstChild", {
976
+ /**
977
+ * Get the first child node.
978
+ * @return The first child or undefined if none exists.
979
+ */
980
+ get: function () {
981
+ return this.childNodes[0];
982
+ },
983
+ enumerable: false,
984
+ configurable: true
985
+ });
986
+ Object.defineProperty(HTMLElement.prototype, "firstElementChild", {
987
+ /**
988
+ * Get the first child node of type {@link HTMLElement}.
989
+ * @return The first child element or undefined if none exists.
990
+ */
991
+ get: function () {
992
+ return this.children[0];
993
+ },
994
+ enumerable: false,
995
+ configurable: true
996
+ });
997
+ Object.defineProperty(HTMLElement.prototype, "lastChild", {
998
+ /**
999
+ * Get the last child node.
1000
+ * @return The last child or undefined if none exists.
1001
+ */
1002
+ get: function () {
1003
+ return (0, back_1.default)(this.childNodes);
1004
+ },
1005
+ enumerable: false,
1006
+ configurable: true
1007
+ });
1008
+ Object.defineProperty(HTMLElement.prototype, "lastElementChild", {
1009
+ /**
1010
+ * Get the last child node of type {@link HTMLElement}.
1011
+ * @return The last child element or undefined if none exists.
1012
+ */
1013
+ get: function () {
1014
+ return this.children[this.children.length - 1];
1015
+ },
1016
+ enumerable: false,
1017
+ configurable: true
1018
+ });
1019
+ Object.defineProperty(HTMLElement.prototype, "childElementCount", {
1020
+ get: function () {
1021
+ return this.children.length;
1022
+ },
1023
+ enumerable: false,
1024
+ configurable: true
1025
+ });
949
1026
  Object.defineProperty(HTMLElement.prototype, "classNames", {
950
1027
  get: function () {
951
1028
  return this.classList.toString();
@@ -953,9 +1030,7 @@ var HTMLElement = /** @class */ (function (_super) {
953
1030
  enumerable: false,
954
1031
  configurable: true
955
1032
  });
956
- /**
957
- * Clone this Node
958
- */
1033
+ /** Clone this Node */
959
1034
  HTMLElement.prototype.clone = function () {
960
1035
  return parse(this.toString(), this._parseOptions).firstChild;
961
1036
  };
@@ -1164,10 +1239,11 @@ exports.base_parse = base_parse;
1164
1239
  * Parse a chuck of HTML source.
1165
1240
  */
1166
1241
  function parse(data, options) {
1242
+ var _a, _b;
1167
1243
  if (options === void 0) { options = {}; }
1168
1244
  var stack = base_parse(data, options);
1169
1245
  var root = stack[0];
1170
- var _loop_1 = function () {
1246
+ while (stack.length > 1) {
1171
1247
  // Handle each error elements.
1172
1248
  var last = stack.pop();
1173
1249
  var oneBefore = (0, back_1.default)(stack);
@@ -1177,9 +1253,7 @@ function parse(data, options) {
1177
1253
  // this is wrong, becouse this will put the H3 outside the current right position which should be inside the current Html Element, see issue 152 for more info
1178
1254
  if (options.parseNoneClosedTags !== true) {
1179
1255
  oneBefore.removeChild(last);
1180
- last.childNodes.forEach(function (child) {
1181
- oneBefore.parentNode.appendChild(child);
1182
- });
1256
+ (_a = oneBefore.parentNode.childNodes).push.apply(_a, last.childNodes);
1183
1257
  stack.pop();
1184
1258
  }
1185
1259
  }
@@ -1189,30 +1263,42 @@ function parse(data, options) {
1189
1263
  // eslint-disable-next-line no-lonely-if
1190
1264
  if (options.parseNoneClosedTags !== true) {
1191
1265
  oneBefore.removeChild(last);
1192
- last.childNodes.forEach(function (child) {
1193
- oneBefore.appendChild(child);
1194
- });
1266
+ (_b = oneBefore.childNodes).push.apply(_b, last.childNodes);
1195
1267
  }
1196
1268
  }
1197
1269
  }
1198
1270
  else {
1199
1271
  // If it's final element just skip.
1200
1272
  }
1201
- };
1202
- while (stack.length > 1) {
1203
- _loop_1();
1204
1273
  }
1205
1274
  // response.childNodes.forEach((node) => {
1206
1275
  // if (node instanceof HTMLElement) {
1207
1276
  // node.parentNode = null;
1208
1277
  // }
1209
1278
  // });
1279
+ resetParent(root.childNodes, root, true);
1210
1280
  return root;
1211
1281
  }
1212
1282
  exports.parse = parse;
1213
- function resetParent(nodes, parent) {
1214
- return nodes.map(function (node) {
1283
+ /**
1284
+ * Resolves a list of {@link NodeInsertable} to a list of nodes,
1285
+ * and removes nodes from any potential parent.
1286
+ */
1287
+ function resolveInsertable(insertable) {
1288
+ return insertable.map(function (val) {
1289
+ if (typeof val === 'string') {
1290
+ return new text_1.default(val);
1291
+ }
1292
+ val.remove();
1293
+ return val;
1294
+ });
1295
+ }
1296
+ function resetParent(nodes, parent, recursive) {
1297
+ if (recursive === void 0) { recursive = false; }
1298
+ nodes.forEach(function (node) {
1215
1299
  node.parentNode = parent;
1216
- return node;
1300
+ if (recursive && node instanceof HTMLElement) {
1301
+ resetParent(node.childNodes, node, true);
1302
+ }
1217
1303
  });
1218
1304
  }
@@ -5,6 +5,7 @@ import HTMLElement from './html';
5
5
  */
6
6
  export default abstract class Node {
7
7
  parentNode: HTMLElement;
8
+ abstract rawTagName: string;
8
9
  abstract nodeType: NodeType;
9
10
  childNodes: Node[];
10
11
  range: readonly [number, number];
@@ -13,6 +13,7 @@ export default class TextNode extends Node {
13
13
  * @type {Number}
14
14
  */
15
15
  nodeType: NodeType;
16
+ rawTagName: string;
16
17
  private _rawText;
17
18
  private _trimmedRawText?;
18
19
  private _trimmedText?;
@@ -35,6 +35,7 @@ var TextNode = /** @class */ (function (_super) {
35
35
  * @type {Number}
36
36
  */
37
37
  _this.nodeType = type_1.default.TEXT_NODE;
38
+ _this.rawTagName = '';
38
39
  _this._rawText = rawText;
39
40
  return _this;
40
41
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-html-parser",
3
- "version": "6.1.12",
3
+ "version": "6.1.15-0",
4
4
  "description": "A very fast HTML parser, generating a simplified DOM, with basic element query support.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -12,6 +12,7 @@
12
12
  "compile:amd": "tsc -t es5 -m amd -d false --outFile ./dist/main.js",
13
13
  "lint": "eslint ./src/*.ts ./src/**/*.ts",
14
14
  "---------------": "",
15
+ "pretest": "cd ./test/ && yarn install && cd ..",
15
16
  "test": "yarn run test:target",
16
17
  "test:src": "cross-env TEST_TARGET=src yarn run test",
17
18
  "test:dist": "cross-env TEST_TARGET=dist yarn run test",