node-html-parser 6.1.13 → 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,13 @@
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
+
5
12
  ### [6.1.13](https://github.com/taoqf/node-fast-html-parser/compare/v6.1.12...v6.1.13) (2024-03-29)
6
13
 
7
14
 
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
@@ -738,7 +738,8 @@ define("nodes/html", ["require", "exports", "css-select", "he", "back", "matcher
738
738
  return child === _this;
739
739
  });
740
740
  resetParent([this], null);
741
- 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);
742
743
  return this;
743
744
  };
744
745
  Object.defineProperty(HTMLElement.prototype, "outerHTML", {
@@ -824,6 +825,13 @@ define("nodes/html", ["require", "exports", "css-select", "he", "back", "matcher
824
825
  _this.childNodes[o++] = node;
825
826
  });
826
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;
827
835
  return this;
828
836
  };
829
837
  /**
@@ -980,34 +988,9 @@ define("nodes/html", ["require", "exports", "css-select", "he", "back", "matcher
980
988
  * @return {Node} node appended
981
989
  */
982
990
  HTMLElement.prototype.appendChild = function (node) {
983
- // remove the node from it's parent
984
- node.remove();
985
- this.childNodes.push(node);
986
- node.parentNode = this;
991
+ this.append(node);
987
992
  return node;
988
993
  };
989
- Object.defineProperty(HTMLElement.prototype, "firstChild", {
990
- /**
991
- * Get first child node
992
- * @return {Node | undefined} first child node; or undefined if none
993
- */
994
- get: function () {
995
- return this.childNodes[0];
996
- },
997
- enumerable: false,
998
- configurable: true
999
- });
1000
- Object.defineProperty(HTMLElement.prototype, "lastChild", {
1001
- /**
1002
- * Get last child node
1003
- * @return {Node | undefined} last child node; or undefined if none
1004
- */
1005
- get: function () {
1006
- return (0, back_1.default)(this.childNodes);
1007
- },
1008
- enumerable: false,
1009
- configurable: true
1010
- });
1011
994
  Object.defineProperty(HTMLElement.prototype, "attrs", {
1012
995
  /**
1013
996
  * Get attributes
@@ -1166,42 +1149,70 @@ define("nodes/html", ["require", "exports", "css-select", "he", "back", "matcher
1166
1149
  return this;
1167
1150
  };
1168
1151
  HTMLElement.prototype.insertAdjacentHTML = function (where, html) {
1169
- var _a, _b, _c;
1170
- var _this = this;
1171
1152
  if (arguments.length < 2) {
1172
1153
  throw new Error('2 arguments required');
1173
1154
  }
1174
1155
  var p = parse(html, this._parseOptions);
1175
1156
  if (where === 'afterend') {
1176
- var idx = this.parentNode.childNodes.findIndex(function (child) {
1177
- return child === _this;
1178
- });
1179
- resetParent(p.childNodes, this.parentNode);
1180
- (_a = this.parentNode.childNodes).splice.apply(_a, __spreadArray([idx + 1, 0], p.childNodes, false));
1157
+ this.after.apply(this, p.childNodes);
1181
1158
  }
1182
1159
  else if (where === 'afterbegin') {
1183
- resetParent(p.childNodes, this);
1184
- (_b = this.childNodes).unshift.apply(_b, p.childNodes);
1160
+ this.prepend.apply(this, p.childNodes);
1185
1161
  }
1186
1162
  else if (where === 'beforeend') {
1187
- p.childNodes.forEach(function (n) {
1188
- _this.appendChild(n);
1189
- });
1163
+ this.append.apply(this, p.childNodes);
1190
1164
  }
1191
1165
  else if (where === 'beforebegin') {
1192
- var idx = this.parentNode.childNodes.findIndex(function (child) {
1193
- return child === _this;
1194
- });
1195
- resetParent(p.childNodes, this.parentNode);
1196
- (_c = this.parentNode.childNodes).splice.apply(_c, __spreadArray([idx, 0], p.childNodes, false));
1166
+ this.before.apply(this, p.childNodes);
1197
1167
  }
1198
1168
  else {
1199
1169
  throw new Error("The value provided ('".concat(where, "') is not one of 'beforebegin', 'afterbegin', 'beforeend', or 'afterend'"));
1200
1170
  }
1201
1171
  return this;
1202
- // if (!where || html === undefined || html === null) {
1203
- // return;
1204
- // }
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));
1205
1216
  };
1206
1217
  Object.defineProperty(HTMLElement.prototype, "nextSibling", {
1207
1218
  get: function () {
@@ -1281,6 +1292,72 @@ define("nodes/html", ["require", "exports", "css-select", "he", "back", "matcher
1281
1292
  enumerable: false,
1282
1293
  configurable: true
1283
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
+ });
1284
1361
  Object.defineProperty(HTMLElement.prototype, "classNames", {
1285
1362
  get: function () {
1286
1363
  return this.classList.toString();
@@ -1288,9 +1365,7 @@ define("nodes/html", ["require", "exports", "css-select", "he", "back", "matcher
1288
1365
  enumerable: false,
1289
1366
  configurable: true
1290
1367
  });
1291
- /**
1292
- * Clone this Node
1293
- */
1368
+ /** Clone this Node */
1294
1369
  HTMLElement.prototype.clone = function () {
1295
1370
  return parse(this.toString(), this._parseOptions).firstChild;
1296
1371
  };
@@ -1499,10 +1574,11 @@ define("nodes/html", ["require", "exports", "css-select", "he", "back", "matcher
1499
1574
  * Parse a chuck of HTML source.
1500
1575
  */
1501
1576
  function parse(data, options) {
1577
+ var _a, _b;
1502
1578
  if (options === void 0) { options = {}; }
1503
1579
  var stack = base_parse(data, options);
1504
1580
  var root = stack[0];
1505
- var _loop_1 = function () {
1581
+ while (stack.length > 1) {
1506
1582
  // Handle each error elements.
1507
1583
  var last = stack.pop();
1508
1584
  var oneBefore = (0, back_1.default)(stack);
@@ -1512,9 +1588,7 @@ define("nodes/html", ["require", "exports", "css-select", "he", "back", "matcher
1512
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
1513
1589
  if (options.parseNoneClosedTags !== true) {
1514
1590
  oneBefore.removeChild(last);
1515
- last.childNodes.forEach(function (child) {
1516
- oneBefore.parentNode.appendChild(child);
1517
- });
1591
+ (_a = oneBefore.parentNode.childNodes).push.apply(_a, last.childNodes);
1518
1592
  stack.pop();
1519
1593
  }
1520
1594
  }
@@ -1524,31 +1598,43 @@ define("nodes/html", ["require", "exports", "css-select", "he", "back", "matcher
1524
1598
  // eslint-disable-next-line no-lonely-if
1525
1599
  if (options.parseNoneClosedTags !== true) {
1526
1600
  oneBefore.removeChild(last);
1527
- last.childNodes.forEach(function (child) {
1528
- oneBefore.appendChild(child);
1529
- });
1601
+ (_b = oneBefore.childNodes).push.apply(_b, last.childNodes);
1530
1602
  }
1531
1603
  }
1532
1604
  }
1533
1605
  else {
1534
1606
  // If it's final element just skip.
1535
1607
  }
1536
- };
1537
- while (stack.length > 1) {
1538
- _loop_1();
1539
1608
  }
1540
1609
  // response.childNodes.forEach((node) => {
1541
1610
  // if (node instanceof HTMLElement) {
1542
1611
  // node.parentNode = null;
1543
1612
  // }
1544
1613
  // });
1614
+ resetParent(root.childNodes, root, true);
1545
1615
  return root;
1546
1616
  }
1547
1617
  exports.parse = parse;
1548
- function resetParent(nodes, parent) {
1549
- 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) {
1550
1634
  node.parentNode = parent;
1551
- return node;
1635
+ if (recursive && node instanceof HTMLElement) {
1636
+ resetParent(node.childNodes, node, true);
1637
+ }
1552
1638
  });
1553
1639
  }
1554
1640
  });
@@ -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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-html-parser",
3
- "version": "6.1.13",
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",