@tkeron/html-parser 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bun.lock CHANGED
@@ -1,28 +1,25 @@
1
1
  {
2
2
  "lockfileVersion": 1,
3
+ "configVersion": 0,
3
4
  "workspaces": {
4
5
  "": {
5
6
  "name": "html-parser",
6
7
  "devDependencies": {
7
- "@types/bun": "latest",
8
+ "@types/bun": "^1.3.4",
8
9
  },
9
10
  "peerDependencies": {
10
- "typescript": "^5.8.3",
11
+ "typescript": "^5.9.3",
11
12
  },
12
13
  },
13
14
  },
14
15
  "packages": {
15
- "@types/bun": ["@types/bun@1.2.18", "", { "dependencies": { "bun-types": "1.2.18" } }, "sha512-Xf6RaWVheyemaThV0kUfaAUvCNokFr+bH8Jxp+tTZfx7dAPA8z9ePnP9S9+Vspzuxxx9JRAXhnyccRj3GyCMdQ=="],
16
+ "@types/bun": ["@types/bun@1.3.4", "", { "dependencies": { "bun-types": "1.3.4" } }, "sha512-EEPTKXHP+zKGPkhRLv+HI0UEX8/o+65hqARxLy8Ov5rIxMBPNTjeZww00CIihrIQGEQBYg+0roO5qOnS/7boGA=="],
16
17
 
17
18
  "@types/node": ["@types/node@24.0.4", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ulyqAkrhnuNq9pB76DRBTkcS6YsmDALy6Ua63V8OhrOBgbcYt6IOdzpw5P1+dyRIyMerzLkeYWBeOXPpA9GMAA=="],
18
19
 
19
- "@types/react": ["@types/react@19.1.8", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g=="],
20
+ "bun-types": ["bun-types@1.3.4", "", { "dependencies": { "@types/node": "*" } }, "sha512-5ua817+BZPZOlNaRgGBpZJOSAQ9RQ17pkwPD0yR7CfJg+r8DgIILByFifDTa+IPDDxzf5VNhtNlcKqFzDgJvlQ=="],
20
21
 
21
- "bun-types": ["bun-types@1.2.18", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-04+Eha5NP7Z0A9YgDAzMk5PHR16ZuLVa83b26kH5+cp1qZW4F6FmAURngE7INf4tKOvCE69vYvDEwoNl1tGiWw=="],
22
-
23
- "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
24
-
25
- "typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
22
+ "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
26
23
 
27
24
  "undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
28
25
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tkeron/html-parser",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "A fast and lightweight HTML parser for Bun",
5
5
  "main": "index.js",
6
6
  "module": "index.ts",
@@ -8,10 +8,10 @@
8
8
  "author": "tkeron",
9
9
  "license": "MIT",
10
10
  "devDependencies": {
11
- "@types/bun": "latest"
11
+ "@types/bun": "^1.3.4"
12
12
  },
13
13
  "peerDependencies": {
14
- "typescript": "^5.8.3"
14
+ "typescript": "^5.9.3"
15
15
  },
16
16
  "keywords": [
17
17
  "cli",
@@ -55,60 +55,19 @@ export function createElement(
55
55
  },
56
56
 
57
57
  removeChild(child: any): any {
58
- const index = element.childNodes.indexOf(child);
59
- if (index === -1) {
60
- throw new Error("Child not found");
61
- }
62
-
63
- element.childNodes.splice(index, 1);
64
-
65
- if (child.previousSibling) {
66
- child.previousSibling.nextSibling = child.nextSibling;
67
- }
68
- if (child.nextSibling) {
69
- child.nextSibling.previousSibling = child.previousSibling;
70
- }
71
-
72
- if (element.firstChild === child) {
73
- element.firstChild = child.nextSibling;
74
- }
75
- if (element.lastChild === child) {
76
- element.lastChild = child.previousSibling;
77
- }
78
-
79
- if (child.nodeType === NodeType.ELEMENT_NODE) {
80
- const childElement = child;
81
- const elemIndex = element.children.indexOf(childElement);
82
- if (elemIndex !== -1) {
83
- element.children.splice(elemIndex, 1);
84
-
85
- if (childElement.previousElementSibling) {
86
- childElement.previousElementSibling.nextElementSibling =
87
- childElement.nextElementSibling;
88
- }
89
- if (childElement.nextElementSibling) {
90
- childElement.nextElementSibling.previousElementSibling =
91
- childElement.previousElementSibling;
92
- }
58
+ return removeChild(element, child);
59
+ },
93
60
 
94
- if (element.firstElementChild === childElement) {
95
- element.firstElementChild = childElement.nextElementSibling;
96
- }
97
- if (element.lastElementChild === childElement) {
98
- element.lastElementChild = childElement.previousElementSibling;
99
- }
100
- }
101
- }
61
+ insertBefore(newNode: any, referenceNode: any): any {
62
+ return insertBefore(element, newNode, referenceNode);
63
+ },
102
64
 
103
- child.parentNode = null;
104
- if (child.nodeType === NodeType.ELEMENT_NODE) {
105
- child.parentElement = null;
106
- }
107
- child.previousSibling = null;
108
- child.nextSibling = null;
65
+ replaceChild(newChild: any, oldChild: any): any {
66
+ return replaceChild(element, newChild, oldChild);
67
+ },
109
68
 
110
- updateElementContent(element);
111
- return child;
69
+ insertAfter(newNode: any, referenceNode: any): any {
70
+ return insertAfter(element, newNode, referenceNode);
112
71
  },
113
72
 
114
73
  setAttribute(name: string, value: string): void {
@@ -249,6 +208,27 @@ export function createDocument(): any {
249
208
  return createTextNode(data);
250
209
  },
251
210
 
211
+ appendChild(child: any): any {
212
+ appendChild(document, child);
213
+ return child;
214
+ },
215
+
216
+ removeChild(child: any): any {
217
+ return removeChild(document, child);
218
+ },
219
+
220
+ insertBefore(newNode: any, referenceNode: any): any {
221
+ return insertBefore(document, newNode, referenceNode);
222
+ },
223
+
224
+ replaceChild(newChild: any, oldChild: any): any {
225
+ return replaceChild(document, newChild, oldChild);
226
+ },
227
+
228
+ insertAfter(newNode: any, referenceNode: any): any {
229
+ return insertAfter(document, newNode, referenceNode);
230
+ },
231
+
252
232
  querySelector(selector: string): any {
253
233
  return querySelectorFunction(document, selector);
254
234
  },
@@ -346,6 +326,23 @@ function convertASTNodeToDOM(astNode: ASTNode): any {
346
326
  }
347
327
 
348
328
  function appendChild(parent: any, child: any): void {
329
+ // Check for hierarchy request error: prevent circular references
330
+ // Check if parent is a descendant of child
331
+ if (child.nodeType === NodeType.ELEMENT_NODE || child.nodeType === NodeType.DOCUMENT_NODE) {
332
+ let ancestor = parent;
333
+ while (ancestor) {
334
+ if (ancestor === child) {
335
+ throw new Error("HierarchyRequestError: Cannot insert a node as a descendant of itself");
336
+ }
337
+ ancestor = ancestor.parentNode;
338
+ }
339
+ }
340
+
341
+ // Remove child from its current parent if it has one
342
+ if (child.parentNode) {
343
+ removeChild(child.parentNode, child);
344
+ }
345
+
349
346
  child.parentNode = parent;
350
347
  parent.childNodes.push(child);
351
348
 
@@ -392,6 +389,354 @@ function appendChild(parent: any, child: any): void {
392
389
  }
393
390
  }
394
391
 
392
+ function removeChild(parent: any, child: any): any {
393
+ const index = parent.childNodes.indexOf(child);
394
+ if (index === -1) {
395
+ throw new Error("Child not found");
396
+ }
397
+
398
+ parent.childNodes.splice(index, 1);
399
+
400
+ if (child.previousSibling) {
401
+ child.previousSibling.nextSibling = child.nextSibling;
402
+ }
403
+ if (child.nextSibling) {
404
+ child.nextSibling.previousSibling = child.previousSibling;
405
+ }
406
+
407
+ if (parent.firstChild === child) {
408
+ parent.firstChild = child.nextSibling;
409
+ }
410
+ if (parent.lastChild === child) {
411
+ parent.lastChild = child.previousSibling;
412
+ }
413
+
414
+ // Only handle element-specific relationships if parent is an element
415
+ if (parent.nodeType === NodeType.ELEMENT_NODE && child.nodeType === NodeType.ELEMENT_NODE) {
416
+ const childElement = child;
417
+ const elemIndex = parent.children.indexOf(childElement);
418
+ if (elemIndex !== -1) {
419
+ parent.children.splice(elemIndex, 1);
420
+
421
+ if (childElement.previousElementSibling) {
422
+ childElement.previousElementSibling.nextElementSibling =
423
+ childElement.nextElementSibling;
424
+ }
425
+ if (childElement.nextElementSibling) {
426
+ childElement.nextElementSibling.previousElementSibling =
427
+ childElement.previousElementSibling;
428
+ }
429
+
430
+ if (parent.firstElementChild === childElement) {
431
+ parent.firstElementChild = childElement.nextElementSibling;
432
+ }
433
+ if (parent.lastElementChild === childElement) {
434
+ parent.lastElementChild = childElement.previousElementSibling;
435
+ }
436
+ }
437
+ }
438
+
439
+ child.parentNode = null;
440
+ if (child.nodeType === NodeType.ELEMENT_NODE) {
441
+ child.parentElement = null;
442
+ }
443
+ child.previousSibling = null;
444
+ child.nextSibling = null;
445
+ if (child.nodeType === NodeType.ELEMENT_NODE) {
446
+ child.previousElementSibling = null;
447
+ child.nextElementSibling = null;
448
+ }
449
+
450
+ if (parent.nodeType === NodeType.ELEMENT_NODE) {
451
+ updateElementContent(parent);
452
+ }
453
+ return child;
454
+ }
455
+
456
+ function insertBefore(parent: any, newNode: any, referenceNode: any): any {
457
+ // If referenceNode is null, append to the end
458
+ if (referenceNode === null) {
459
+ appendChild(parent, newNode);
460
+ return newNode;
461
+ }
462
+
463
+ // Verify referenceNode is actually a child of parent
464
+ const refIndex = parent.childNodes.indexOf(referenceNode);
465
+ if (refIndex === -1) {
466
+ throw new Error("Reference node is not a child of this node");
467
+ }
468
+
469
+ // Check for hierarchy request error: prevent circular references
470
+ if (newNode.nodeType === NodeType.ELEMENT_NODE || newNode.nodeType === NodeType.DOCUMENT_NODE) {
471
+ let ancestor = parent;
472
+ while (ancestor) {
473
+ if (ancestor === newNode) {
474
+ throw new Error("HierarchyRequestError: Cannot insert a node as a descendant of itself");
475
+ }
476
+ ancestor = ancestor.parentNode;
477
+ }
478
+ }
479
+
480
+ // Remove newNode from its current parent if it has one
481
+ if (newNode.parentNode) {
482
+ removeChild(newNode.parentNode, newNode);
483
+ }
484
+
485
+ // Insert into childNodes
486
+ parent.childNodes.splice(refIndex, 0, newNode);
487
+ newNode.parentNode = parent;
488
+
489
+ // Update sibling relationships for all nodes
490
+ newNode.previousSibling = referenceNode.previousSibling;
491
+ newNode.nextSibling = referenceNode;
492
+
493
+ if (referenceNode.previousSibling) {
494
+ referenceNode.previousSibling.nextSibling = newNode;
495
+ }
496
+ referenceNode.previousSibling = newNode;
497
+
498
+ // Update firstChild if inserting at the beginning
499
+ if (parent.firstChild === referenceNode) {
500
+ parent.firstChild = newNode;
501
+ }
502
+
503
+ // Handle element-specific relationships
504
+ if (
505
+ parent.nodeType === NodeType.ELEMENT_NODE &&
506
+ newNode.nodeType === NodeType.ELEMENT_NODE
507
+ ) {
508
+ const parentElement = parent;
509
+ const newElement = newNode;
510
+
511
+ newElement.parentElement = parentElement;
512
+
513
+ // Find the reference node in the children array
514
+ let refElementIndex = -1;
515
+ if (referenceNode.nodeType === NodeType.ELEMENT_NODE) {
516
+ refElementIndex = parentElement.children.indexOf(referenceNode);
517
+ } else {
518
+ // Find the next element sibling
519
+ let nextElement = referenceNode.nextSibling;
520
+ while (nextElement && nextElement.nodeType !== NodeType.ELEMENT_NODE) {
521
+ nextElement = nextElement.nextSibling;
522
+ }
523
+ if (nextElement) {
524
+ refElementIndex = parentElement.children.indexOf(nextElement);
525
+ }
526
+ }
527
+
528
+ if (refElementIndex === -1) {
529
+ // No element siblings after, append to children
530
+ parentElement.children.push(newElement);
531
+ } else {
532
+ // Insert before the reference element
533
+ parentElement.children.splice(refElementIndex, 0, newElement);
534
+ }
535
+
536
+ // Update element sibling relationships
537
+ const newElemIndex = parentElement.children.indexOf(newElement);
538
+ newElement.previousElementSibling =
539
+ newElemIndex > 0 ? parentElement.children[newElemIndex - 1] : null;
540
+ newElement.nextElementSibling =
541
+ newElemIndex < parentElement.children.length - 1
542
+ ? parentElement.children[newElemIndex + 1]
543
+ : null;
544
+
545
+ if (newElement.previousElementSibling) {
546
+ newElement.previousElementSibling.nextElementSibling = newElement;
547
+ }
548
+ if (newElement.nextElementSibling) {
549
+ newElement.nextElementSibling.previousElementSibling = newElement;
550
+ }
551
+
552
+ // Update firstElementChild if needed
553
+ if (newElemIndex === 0) {
554
+ parentElement.firstElementChild = newElement;
555
+ }
556
+
557
+ // lastElementChild is not affected since we're inserting before
558
+ }
559
+
560
+ if (parent.nodeType === NodeType.ELEMENT_NODE) {
561
+ updateElementContent(parent);
562
+ }
563
+
564
+ return newNode;
565
+ }
566
+
567
+ function replaceChild(parent: any, newChild: any, oldChild: any): any {
568
+ // Verify oldChild is actually a child of parent
569
+ const oldIndex = parent.childNodes.indexOf(oldChild);
570
+ if (oldIndex === -1) {
571
+ throw new Error("Old child is not a child of this node");
572
+ }
573
+
574
+ // Check for hierarchy request error: prevent circular references
575
+ if (newChild.nodeType === NodeType.ELEMENT_NODE || newChild.nodeType === NodeType.DOCUMENT_NODE) {
576
+ let ancestor = parent;
577
+ while (ancestor) {
578
+ if (ancestor === newChild) {
579
+ throw new Error("HierarchyRequestError: Cannot insert a node as a descendant of itself");
580
+ }
581
+ ancestor = ancestor.parentNode;
582
+ }
583
+ }
584
+
585
+ // Remove newChild from its current parent if it has one
586
+ if (newChild.parentNode) {
587
+ removeChild(newChild.parentNode, newChild);
588
+ }
589
+
590
+ // Replace in childNodes array
591
+ parent.childNodes[oldIndex] = newChild;
592
+ newChild.parentNode = parent;
593
+
594
+ // Transfer sibling relationships
595
+ newChild.previousSibling = oldChild.previousSibling;
596
+ newChild.nextSibling = oldChild.nextSibling;
597
+
598
+ if (oldChild.previousSibling) {
599
+ oldChild.previousSibling.nextSibling = newChild;
600
+ }
601
+ if (oldChild.nextSibling) {
602
+ oldChild.nextSibling.previousSibling = newChild;
603
+ }
604
+
605
+ // Update first/last child if needed
606
+ if (parent.firstChild === oldChild) {
607
+ parent.firstChild = newChild;
608
+ }
609
+ if (parent.lastChild === oldChild) {
610
+ parent.lastChild = newChild;
611
+ }
612
+
613
+ // Handle element-specific relationships
614
+ if (parent.nodeType === NodeType.ELEMENT_NODE) {
615
+ const parentElement = parent;
616
+
617
+ // Remove old element from children if it's an element
618
+ if (oldChild.nodeType === NodeType.ELEMENT_NODE) {
619
+ const oldElemIndex = parentElement.children.indexOf(oldChild);
620
+ if (oldElemIndex !== -1) {
621
+ if (newChild.nodeType === NodeType.ELEMENT_NODE) {
622
+ // Replace with new element
623
+ parentElement.children[oldElemIndex] = newChild;
624
+ newChild.parentElement = parentElement;
625
+
626
+ // Transfer element sibling relationships
627
+ newChild.previousElementSibling = oldChild.previousElementSibling;
628
+ newChild.nextElementSibling = oldChild.nextElementSibling;
629
+
630
+ if (oldChild.previousElementSibling) {
631
+ oldChild.previousElementSibling.nextElementSibling = newChild;
632
+ }
633
+ if (oldChild.nextElementSibling) {
634
+ oldChild.nextElementSibling.previousElementSibling = newChild;
635
+ }
636
+
637
+ if (parentElement.firstElementChild === oldChild) {
638
+ parentElement.firstElementChild = newChild;
639
+ }
640
+ if (parentElement.lastElementChild === oldChild) {
641
+ parentElement.lastElementChild = newChild;
642
+ }
643
+ } else {
644
+ // Replacing element with non-element, remove from children
645
+ parentElement.children.splice(oldElemIndex, 1);
646
+
647
+ if (oldChild.previousElementSibling) {
648
+ oldChild.previousElementSibling.nextElementSibling =
649
+ oldChild.nextElementSibling;
650
+ }
651
+ if (oldChild.nextElementSibling) {
652
+ oldChild.nextElementSibling.previousElementSibling =
653
+ oldChild.previousElementSibling;
654
+ }
655
+
656
+ if (parentElement.firstElementChild === oldChild) {
657
+ parentElement.firstElementChild = oldChild.nextElementSibling;
658
+ }
659
+ if (parentElement.lastElementChild === oldChild) {
660
+ parentElement.lastElementChild = oldChild.previousElementSibling;
661
+ }
662
+ }
663
+ }
664
+ } else if (newChild.nodeType === NodeType.ELEMENT_NODE) {
665
+ // Replacing non-element with element, need to insert into children array
666
+ const newElement = newChild;
667
+ newElement.parentElement = parentElement;
668
+
669
+ // Find correct position in children array
670
+ let insertIndex = 0;
671
+ for (let i = 0; i < oldIndex; i++) {
672
+ if (parent.childNodes[i].nodeType === NodeType.ELEMENT_NODE) {
673
+ insertIndex++;
674
+ }
675
+ }
676
+
677
+ parentElement.children.splice(insertIndex, 0, newElement);
678
+
679
+ // Update element sibling relationships
680
+ newElement.previousElementSibling =
681
+ insertIndex > 0 ? parentElement.children[insertIndex - 1] : null;
682
+ newElement.nextElementSibling =
683
+ insertIndex < parentElement.children.length - 1
684
+ ? parentElement.children[insertIndex + 1]
685
+ : null;
686
+
687
+ if (newElement.previousElementSibling) {
688
+ newElement.previousElementSibling.nextElementSibling = newElement;
689
+ }
690
+ if (newElement.nextElementSibling) {
691
+ newElement.nextElementSibling.previousElementSibling = newElement;
692
+ }
693
+
694
+ if (insertIndex === 0) {
695
+ parentElement.firstElementChild = newElement;
696
+ }
697
+ if (insertIndex === parentElement.children.length - 1) {
698
+ parentElement.lastElementChild = newElement;
699
+ }
700
+ }
701
+ }
702
+
703
+ // Clear oldChild's relationships
704
+ oldChild.parentNode = null;
705
+ if (oldChild.nodeType === NodeType.ELEMENT_NODE) {
706
+ oldChild.parentElement = null;
707
+ }
708
+ oldChild.previousSibling = null;
709
+ oldChild.nextSibling = null;
710
+ if (oldChild.nodeType === NodeType.ELEMENT_NODE) {
711
+ oldChild.previousElementSibling = null;
712
+ oldChild.nextElementSibling = null;
713
+ }
714
+
715
+ if (parent.nodeType === NodeType.ELEMENT_NODE) {
716
+ updateElementContent(parent);
717
+ }
718
+
719
+ return oldChild;
720
+ }
721
+
722
+ function insertAfter(parent: any, newNode: any, referenceNode: any): any {
723
+ // If referenceNode is null, insert at the beginning
724
+ if (referenceNode === null) {
725
+ insertBefore(parent, newNode, parent.firstChild);
726
+ return newNode;
727
+ }
728
+
729
+ // Verify referenceNode is actually a child of parent
730
+ const refIndex = parent.childNodes.indexOf(referenceNode);
731
+ if (refIndex === -1) {
732
+ throw new Error("Reference node is not a child of this node");
733
+ }
734
+
735
+ // Insert after means insert before the next sibling
736
+ const nextSibling = referenceNode.nextSibling;
737
+ return insertBefore(parent, newNode, nextSibling);
738
+ }
739
+
395
740
  function updateElementContent(element: any): void {
396
741
  const innerHTML = element.childNodes
397
742
  .map((child: any) => {
package/src/dom-types.ts CHANGED
@@ -10,6 +10,9 @@ export interface ParentNode extends Node {
10
10
  lastChild: ChildNode | null;
11
11
  appendChild(child: ChildNode): ChildNode;
12
12
  removeChild(child: ChildNode): ChildNode;
13
+ insertBefore(newNode: ChildNode, referenceNode: ChildNode | null): ChildNode;
14
+ replaceChild(newChild: ChildNode, oldChild: ChildNode): ChildNode;
15
+ insertAfter?(newNode: ChildNode, referenceNode: ChildNode | null): ChildNode;
13
16
  }
14
17
 
15
18
  export interface Text extends ChildNode {